Sử dụng dịch vụ theo dõi tình trạng xe để gỡ lỗi VHAL. Bộ đếm giờ phòng vệ của ô tô theo dõi tình trạng của và tiêu diệt các quy trình không lành mạnh. Để bộ đếm giờ phòng vệ ô tô giám sát một quy trình, bạn phải đăng ký quy trình đó với bộ đếm giờ phòng vệ ô tô. Khi trình giám sát ô tô loại bỏ các quy trình không lành mạnh, trình giám sát ô tô sẽ ghi trạng thái của các quy trình đó vào data/anr
như với các tệp báo lỗi Ứng dụng không phản hồi (ANR) khác. Làm như vậy sẽ thiết lập cơ sở cho quá trình gỡ lỗi.
Bài viết này mô tả cách các dịch vụ và HAL của nhà cung cấp có thể đăng ký một quy trình với bộ đếm giờ phòng vệ của ô tô.
HAL của nhà cung cấp
Thông thường, HAL của nhà cung cấp sử dụng nhóm luồng cho hwbinder
. Tuy nhiên, ứng dụng của bộ đếm giờ phòng vệ cho ô tô giao tiếp với trình nền của bộ đếm giờ phòng vệ cho ô tô thông qua binder
, khác với hwbinder
. Do đó, một nhóm luồng khác cho binder
đang được sử dụng.
Chỉ định aidl của bộ đếm giờ phòng vệ của ô tô trong tệp makefile
- Đưa
carwatchdog_aidl_interface-ndk_platform
vàoshared_libs
:Android.bp
:cc_defaults { name: "vhal_v2_0_defaults", shared_libs: [ "libbinder_ndk", "libhidlbase", "liblog", "libutils", "android.hardware.automotive.vehicle@2.0", "carwatchdog_aidl_interface-ndk_platform", ], cflags: [ "-Wall", "-Wextra", "-Werror", ], }
Thêm chính sách SELinux
-
Cho phép
system_server
loại bỏ HAL của bạn. Nếu bạn chưa cósystem_server.te
, hãy tạo một tài khoản. Bạn nên thêm chính sách SELinux vào từng thiết bị. -
Cho phép HAL của nhà cung cấp sử dụng trình liên kết (macro
binder_use
) và thêm HAL của nhà cung cấp vào miền ứng dụngcarwatchdog
(macrocarwatchdog_client_domain
). Xem mã bên dưới chosystemserver.te
vàvehicle_default.te
:system_server.te
# Allow system_server to kill vehicle HAL allow system_server hal_vehicle_server:process sigkill;
hal_vehicle_default.te
# Configuration for register VHAL to car watchdog carwatchdog_client_domain(hal_vehicle_default) binder_use(hal_vehicle_default)
Triển khai một lớp ứng dụng bằng cách kế thừa BnCarWatchdogClient
-
Trong
checkIfAlive
, hãy kiểm tra tình trạng. Ví dụ: đăng lên trình xử lý vòng lặp luồng. Nếu khỏe mạnh, hãy gọiICarWatchdog::tellClientAlive
. Xem mã bên dưới choWatchogClient.h
vàWatchogClient.cpp
:WatchogClient.h
class WatchdogClient : public aidl::android::automotive::watchdog::BnCarWatchdogClient { public: explicit WatchdogClient(const ::android::sp<::android::Looper>& handlerLooper, VehicleHalManager* vhalManager);
ndk::ScopedAStatus checkIfAlive(int32_t sessionId, aidl::android::automotive::watchdog::TimeoutLength timeout) override; ndk::ScopedAStatus prepareProcessTermination() override; };WatchogClient.cpp
ndk::ScopedAStatus WatchdogClient::checkIfAlive(int32_t sessionId, TimeoutLength /*timeout*/) { // Implement or call your health check logic here return ndk::ScopedAStatus::ok(); }
Bắt đầu luồng liên kết và đăng ký ứng dụng
- Tạo một nhóm luồng để giao tiếp với liên kết. Nếu HAL của nhà cung cấp sử dụng hwbinder cho mục đích riêng, bạn phải tạo một nhóm luồng khác để giao tiếp với trình liên kết chó săn xe).
-
Tìm trình nền có tên và gọi
ICarWatchdog::registerClient
. Tên giao diện trình nền theo dõi tình trạng xe làandroid.automotive.watchdog.ICarWatchdog/default
. -
Dựa trên khả năng phản hồi của dịch vụ, hãy chọn một trong ba loại thời gian chờ sau đây mà trình giám sát xe hỗ trợ, sau đó truyền thời gian chờ trong lệnh gọi đến
ICarWatchdog::registerClient
:- critical(3s)
- trung bình(5 giây)
- bình thường(10 giây)
VehicleService.cpp
vàWatchogClient.cpp
:XeService.cpp
int main(int /* argc */, char* /* argv */ []) { // Set up thread pool for hwbinder configureRpcThreadpool(4, false /* callerWillJoin */); ALOGI("Registering as service..."); status_t status = service->registerAsService(); if (status != OK) { ALOGE("Unable to register vehicle service (%d)", status); return 1; } // Setup a binder thread pool to be a car watchdog client. ABinderProcess_setThreadPoolMaxThreadCount(1); ABinderProcess_startThreadPool(); sp<Looper> looper(Looper::prepare(0 /* opts */)); std::shared_ptr<WatchdogClient> watchdogClient = ndk::SharedRefBase::make<WatchdogClient>(looper, service.get()); // The current health check is done in the main thread, so it falls short of capturing the real // situation. Checking through HAL binder thread should be considered. if (!watchdogClient->initialize()) { ALOGE("Failed to initialize car watchdog client"); return 1; } ALOGI("Ready"); while (true) { looper->pollAll(-1 /* timeoutMillis */); } return 1; }
WatchogClient.cpp
bool WatchdogClient::initialize() { ndk::SpAIBinder binder(AServiceManager_getService("android.automotive.watchdog.ICarWatchdog/default")); if (binder.get() == nullptr) { ALOGE("Failed to get carwatchdog daemon"); return false; } std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder); if (server == nullptr) { ALOGE("Failed to connect to carwatchdog daemon"); return false; } mWatchdogServer = server; binder = this->asBinder(); if (binder.get() == nullptr) { ALOGE("Failed to get car watchdog client binder object"); return false; } std::shared_ptr<ICarWatchdogClient> client = ICarWatchdogClient::fromBinder(binder); if (client == nullptr) { ALOGE("Failed to get ICarWatchdogClient from binder"); return false; } mTestClient = client; mWatchdogServer->registerClient(client, TimeoutLength::TIMEOUT_NORMAL); ALOGI("Successfully registered the client to car watchdog server"); return true; }
Dịch vụ của nhà cung cấp (Gốc)
Chỉ định tệp makefile aidl của car watchdog
- Đưa
carwatchdog_aidl_interface-ndk_platform
vàoshared_libs
.Android.bp
cc_binary { name: "sample_native_client", srcs: [ "src/*.cpp" ], shared_libs: [ "carwatchdog_aidl_interface-ndk_platform", "libbinder_ndk", ], vendor: true, }
Thêm chính sách SELinux
- Để thêm chính sách SELinux, hãy cho phép miền dịch vụ của nhà cung cấp sử dụng trình liên kết (macro
binder_use
) và thêm miền dịch vụ của nhà cung cấp vào miền ứng dụngcarwatchdog
(macrocarwatchdog_client_domain
). Xem mã bên dưới chosample_client.te
vàfile_contexts
:sample_client.te
type sample_client, domain; type sample_client_exec, exec_type, file_type, vendor_file_type; carwatchdog_client_domain(sample_client) init_daemon_domain(sample_client) binder_use(sample_client)
file_contexts
/vendor/bin/sample_native_client u:object_r:sample_client_exec:s0
Triển khai lớp ứng dụng khách bằng cách kế thừa BnCarWatchdogClient
- Trong
checkIfAlive
, hãy kiểm tra tình trạng. Một cách là đăng lên trình xử lý vòng lặp luồng. Nếu khỏe mạnh, hãy gọiICarWatchdog::tellClientAlive
. Xem mã bên dưới choSampleNativeClient.h
vàSampleNativeClient.cpp
:SampleNativeClient.h
class SampleNativeClient : public BnCarWatchdogClient { public: ndk::ScopedAStatus checkIfAlive(int32_t sessionId, TimeoutLength timeout) override; ndk::ScopedAStatus prepareProcessTermination() override; void initialize(); private: void respondToDaemon(); private: ::android::sp<::android::Looper> mHandlerLooper; std::shared_ptr<ICarWatchdog> mWatchdogServer; std::shared_ptr<ICarWatchdogClient> mClient; int32_t mSessionId; };
SampleNativeClient.cpp
ndk::ScopedAStatus WatchdogClient::checkIfAlive(int32_t sessionId, TimeoutLength timeout) { mHandlerLooper->removeMessages(mMessageHandler, WHAT_CHECK_ALIVE); mSessionId = sessionId; mHandlerLooper->sendMessage(mMessageHandler, Message(WHAT_CHECK_ALIVE)); return ndk::ScopedAStatus::ok(); } // WHAT_CHECK_ALIVE triggers respondToDaemon from thread handler void WatchdogClient::respondToDaemon() { // your health checking method here ndk::ScopedAStatus status = mWatchdogServer->tellClientAlive(mClient, mSessionId); }
Bắt đầu một luồng liên kết và đăng ký ứng dụng
Tên giao diện trình nền theo dõi tình trạng xe là android.automotive.watchdog.ICarWatchdog/default
.
- Tìm trình nền có tên và gọi
ICarWatchdog::registerClient
. Xem mã bên dưới chomain.cpp
vàSampleNativeClient.cpp
:main.cpp
int main(int argc, char** argv) { sp<Looper> looper(Looper::prepare(/*opts=*/0)); ABinderProcess_setThreadPoolMaxThreadCount(1); ABinderProcess_startThreadPool(); std::shared_ptr<SampleNativeClient> client = ndk::SharedRefBase::make<SampleNatvieClient>(looper); // The client is registered in initialize() client->initialize(); ... }
SampleNativeClient.cpp
void SampleNativeClient::initialize() { ndk::SpAIBinder binder(AServiceManager_getService( "android.automotive.watchdog.ICarWatchdog/default")); std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder); mWatchdogServer = server; ndk::SpAIBinder binder = this->asBinder(); std::shared_ptr<ICarWatchdogClient> client = ICarWatchdogClient::fromBinder(binder) mClient = client; server->registerClient(client, TimeoutLength::TIMEOUT_NORMAL); }
Dịch vụ của nhà cung cấp (Android)
Triển khai ứng dụng bằng cách kế thừa CarWatchdogClientCallback
- Chỉnh sửa tệp mới như sau:
private final CarWatchdogClientCallback mClientCallback = new CarWatchdogClientCallback() { @Override public boolean onCheckHealthStatus(int sessionId, int timeout) { // Your health check logic here // Returning true implies the client is healthy // If false is returned, the client should call // CarWatchdogManager.tellClientAlive after health check is // completed } @Override public void onPrepareProcessTermination() {} };
Đăng ký ứng dụng
- Gọi
CarWatchdogManager.registerClient()
:private void startClient() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager( Car.CAR_WATCHDOG_SERVICE); // Choose a proper executor according to your health check method ExecutorService executor = Executors.newFixedThreadPool(1); manager.registerClient(executor, mClientCallback, CarWatchdogManager.TIMEOUT_NORMAL); }
Huỷ đăng ký ứng dụng
- Gọi
CarWatchdogManager.unregisterClient()
khi dịch vụ hoàn tất:private void finishClient() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager( Car.CAR_WATCHDOG_SERVICE); manager.unregisterClient(mClientCallback); }
Phát hiện các quy trình do bộ đếm giờ phòng vệ của ô tô chấm dứt
Quy trình kết xuất/xoá bộ đếm giờ phòng vệ của ô tô (HAL của nhà cung cấp, dịch vụ gốc của nhà cung cấp, dịch vụ Android của nhà cung cấp) được đăng ký với bộ đếm giờ phòng vệ của ô tô khi chúng bị lỗi và không phản hồi. Bạn có thể phát hiện hoạt động kết xuất như vậy bằng cách kiểm tra logcats. Bộ đếm giờ phòng vệ của ô tô sẽ xuất ra nhật ký carwatchdog killed process_name (pid:process_id)
khi một quy trình có vấn đề bị kết xuất hoặc bị dừng. Do đó:
$ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"
Các nhật ký có liên quan sẽ được ghi lại. Ví dụ: nếu ứng dụng KitchenSink (một ứng dụng giám sát ô tô) bị treo, thì một dòng như dưới đây sẽ được ghi vào nhật ký:
05-01 09:50:19.683 578 5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)
Để xác định lý do hoặc vị trí ứng dụng KitchenSink gặp sự cố, hãy sử dụng tệp kết xuất quy trình được lưu trữ tại /data/anr
giống như cách bạn sử dụng các trường hợp ANR hoạt động.
$ adb root $ adb shell grep -Hn "pid process_pid" /data/anr/*
Kết quả mẫu sau đây dành riêng cho ứng dụng KitchenSink:
$ adb shell su root grep -Hn "pid 5574" /data/anr/*. /data/anr/anr_2020-05-01-09-50-18-290:3:----- pid 5574 at 2020-05-01 09:50:18 ----- /data/anr/anr_2020-05-01-09-50-18-290:285:----- Waiting Channels: pid 5574 at 2020-05-01 09:50:18 -----
Tìm tệp kết xuất (ví dụ: /data/anr/anr_2020-05-01-09-50-18-290
trong ví dụ trên) và bắt đầu phân tích.