Watchdog giám sát tình trạng của các dịch vụ nhà cung cấp và dịch vụ VHAL, đồng thời chấm dứt mọi quy trình không lành mạnh. Khi một quy trình không lành mạnh bị chấm dứt, Watchdog sẽ kết xuất trạng thái quy trình sang /data/anr
như với các kết xuất Application Not Responding (ANR) khác. Việc này giúp quá trình gỡ lỗi diễn ra dễ dàng hơn.
Theo dõi tình trạng dịch vụ của nhà cung cấp
Các dịch vụ của nhà cung cấp được giám sát ở cả phía gốc và phía Java. Để được Watchdog giám sát, dịch vụ Nhà cung cấp phải đăng ký quy trình kiểm tra tình trạng với Watchdog bằng cách chỉ định thời gian chờ xác định trước. Watchdog giám sát trạng thái của một quy trình kiểm tra trạng thái đã đăng ký bằng cách ping quy trình đó theo một khoảng thời gian tương ứng với thời gian chờ được chỉ định trong quá trình đăng ký. Khi một quy trình được ping không phản hồi trong thời gian chờ, quy trình đó sẽ được coi là không hoạt động bình thường.
Theo dõi tình trạng dịch vụ gốc
Chỉ định tệp makefile AIDL của Watchdog
- Bao gồm
carwatchdog_aidl_interface-ndk_platform
trongshared_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 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
). Hãy 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 một lớp ứng dụng bằng cách kế thừa BnCarWatchdogClient
- Trong
checkIfAlive
, hãy thực hiện quy trình kiểm tra tình trạng. Một lựa chọn là đăng lên trình xử lý vòng lặp luồng. Nếu khoẻ mạnh, hãy gọiICarWatchdog::tellClientAlive
. Hãy 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 của trình nền theo dõi tình trạng xe là android.automotive.watchdog.ICarWatchdog/default
.
- Tìm kiếm trình nền có tên và gọi
ICarWatchdog::registerClient
. Hãy 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); }
Giám sát tình trạng dịch vụ Java
Triển khai một ứ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 đến số
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); }
Giám sát tình trạng VHAL
Không giống như tính năng giám sát trạng thái dịch vụ của nhà cung cấp, Watchdog giám sát trạng thái dịch vụ VHAL bằng cách đăng ký thuộc tính VHAL_HEARTBEAT
của xe.
Watchdog dự kiến giá trị của thuộc tính này sẽ được cập nhật mỗi N giây.
Khi nhịp tim không được cập nhật trong thời gian chờ này, Watchdog sẽ chấm dứt dịch vụ VHAL.
Lưu ý: Watchdog chỉ theo dõi trạng thái dịch vụ VHAL khi dịch vụ VHAL hỗ trợ thuộc tính xe VHAL_HEARTBEAT
.
Cách triển khai nội bộ VHAL có thể khác nhau tuỳ theo nhà cung cấp. Hãy dùng các mẫu mã sau đây làm tài liệu tham khảo.
- Đăng ký thuộc tính
VHAL_HEARTBEAT
của xe.Khi bắt đầu dịch vụ VHAL, hãy đăng ký thuộc tính phương tiện
VHAL_HEARTBEAT
. Trong ví dụ bên dưới,unordered_map
(liên kết mã tài sản với cấu hình) được dùng để lưu giữ tất cả các cấu hình được hỗ trợ. Cấu hình choVHAL_HEARTBEAT
được thêm vào bản đồ, để khiVHAL_HEARTBEAT
được truy vấn, cấu hình tương ứng sẽ được trả về.void registerVhalHeartbeatProperty() { const VehiclePropConfig config = { .prop = toInt(VehicleProperty::VHAL_HEARTBEAT), .access = VehiclePropertyAccess::READ, .changeMode = VehiclePropertyChangeMode::ON_CHANGE, }; // mConfigsById is declared as std::unordered_map<int32_t, VehiclePropConfig>. mConfigsById[config.prop] = config; }
- Cập nhật thuộc tính
VHAL_HEARTBEAT
của xe.Dựa trên tần suất kiểm tra tình trạng VHAL (được giải thích trong phần Xác định tần suất kiểm tra tình trạng VHAL"), hãy cập nhật thuộc tính
VHAL_HEARTBEAT
của xe sau mỗi N giây. Một cách để thực hiện việc này là sử dụngRecurrentTimer
để gọi thao tác kiểm tra tình trạng VHAL và cập nhật thuộc tínhVHAL_HEARTBEAT
của xe trong thời gian chờ.Dưới đây là một ví dụ về cách triển khai bằng
RecurrentTimer
:int main(int argc, char** argv) { RecurrentTimer recurrentTimer(updateVhalHeartbeat); recurrentTimer.registerRecurrentEvent(kHeartBeatIntervalNs, static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)); … Run service … recurrentTimer.unregisterRecurrentEvent( static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)); } void updateVhalHeartbeat(const std::vector<int32_t>& cookies) { for (int32_t property : cookies) { if (property != static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT)) { continue; } // Perform internal health checking such as retrieving a vehicle property to ensure // the service is responsive. doHealthCheck(); // Construct the VHAL_HEARTBEAT property with system uptime. VehiclePropValuePool valuePool; VehicleHal::VehiclePropValuePtr propValuePtr = valuePool.obtainInt64(uptimeMillis()); propValuePtr->prop = static_cast<int32_t>(VehicleProperty::VHAL_HEARTBEAT); propValuePtr->areaId = 0; propValuePtr->status = VehiclePropertyStatus::AVAILABLE; propValuePtr->timestamp = elapsedRealtimeNano(); // Propagate the HAL event. onHalEvent(std::move(propValuePtr)); } }
- (Không bắt buộc) Xác định tần suất kiểm tra tình trạng của VHAL.
Thuộc tính sản phẩm chỉ đọc
ro.carwatchdog.vhal_healthcheck.interval
của Watchdog xác định tần suất kiểm tra tình trạng VHAL. Tần suất kiểm tra tình trạng mặc định (khi thuộc tính này không được xác định) là 3 giây. Nếu 3 giây là không đủ để dịch vụ VHAL cập nhật thuộc tínhVHAL_HEARTBEAT
của xe, hãy xác định tần suất kiểm tra tình trạng VHAL tuỳ thuộc vào khả năng phản hồi của dịch vụ.
Gỡ lỗi các quy trình không lành mạnh bị Watchdog chấm dứt
Watchdog kết xuất trạng thái của quy trình và chấm dứt các quy trình không lành mạnh. Khi chấm dứt một quy trình không lành mạnh, Watchdog sẽ ghi văn bản carwatchdog terminated
<process name> (pid:<process id>)
vào logcat. Dòng nhật ký này cung cấp thông tin về quy trình đã kết thúc, chẳng hạn như tên quy trình và mã quy trình.
- Bạn có thể tìm kiếm văn bản nêu trên trong logcat bằng cách chạy:
$ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"
Ví dụ: khi ứng dụng KitchenSink là một ứng dụng Watchdog đã đăng ký và không phản hồi các lệnh ping của Watchdog, Watchdog sẽ ghi một dòng như dòng bên dưới khi chấm dứt quy trình KitchenSink đã đăng ký.
05-01 09:50:19.683 578 5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)
- Để xác định nguyên nhân gốc của tình trạng không phản hồi, 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 cho các trường hợp ANR hoạt động. Để truy xuất tệp kết xuất cho quy trình đã kết thúc, hãy dùng các lệnh bên dưới.$ adb root $ adb shell grep -Hn "pid process_pid" /data/anr/*
Đầu ra 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ệp kết xuất cho quy trình KitchenSink đã kết thúc nằm tại
/data/anr/anr_2020-05-01-09-50-18-290
. Bắt đầu phân tích bằng tệp kết xuất ANR của quy trình đã kết thúc.