Watchdog سلامت سرویسهای فروشنده و سرویس VHAL را رصد میکند و هرگونه فرآیند ناسالم را خاتمه میدهد. هنگامی که یک فرآیند ناسالم خاتمه مییابد، Watchdog وضعیت فرآیند را مانند سایر dumpهای Application Not Responding (ANR) در /data/anr ذخیره میکند. انجام این کار فرآیند اشکالزدایی را تسهیل میکند.
نظارت بر سلامت خدمات فروشنده
سرویسهای فروشنده هم در سمت بومی و هم در سمت جاوا مانیتور میشوند. برای اینکه یک سرویس فروشنده مانیتور شود، سرویس باید یک فرآیند بررسی سلامت را با مشخص کردن یک زمان انقضای از پیش تعریف شده در Watchdog ثبت کند. Watchdog سلامت یک فرآیند بررسی سلامت ثبت شده را با پینگ کردن آن در یک بازه زمانی نسبت به زمان انقضای مشخص شده در طول ثبت، مانیتور میکند. هنگامی که یک فرآیند پینگ شده در مدت زمان انقضا پاسخ ندهد، آن فرآیند ناسالم در نظر گرفته میشود.
نظارت بر سلامت خدمات بومی
فایل ساخت Watchdog AIDL را مشخص کنید
-
carwatchdog_aidl_interface-ndk_platformرا درshared_libsوارد کنید.Android.bpcc_binary { name: "sample_native_client", srcs: [ "src/*.cpp" ], shared_libs: [ "carwatchdog_aidl_interface-ndk_platform", "libbinder_ndk", ], vendor: true, }
اضافه کردن یک سیاست SELinux
- برای افزودن یک سیاست SELinux، به دامنه سرویس فروشنده اجازه دهید از binder استفاده کند (ماکرو
binder_use) و دامنه سرویس فروشنده را به دامنه کلاینتcarwatchdogاضافه کنید (ماکروcarwatchdog_client_domain). برایsample_client.teوfile_contextsبه کد زیر مراجعه کنید:sample_client.tetype 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
پیادهسازی یک کلاس کلاینت با ارثبری از BnCarWatchdogClient
- در
checkIfAlive، بررسی سلامت را انجام دهید. یک گزینه این است که به کنترلکننده حلقه نخ ارسال کنید. اگر سالم بود،ICarWatchdog::tellClientAliveرا فراخوانی کنید. کد زیر را برایSampleNativeClient.hوSampleNativeClient.cppببینید:SampleNativeClient.hclass 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.cppndk::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); }
یک رشته اتصالدهنده را شروع کنید و کلاینت را ثبت کنید
نام رابط دیمن car watchdog android.automotive.watchdog.ICarWatchdog/default است.
- به دنبال سرویسی با این نام بگردید و
ICarWatchdog::registerClientفراخوانی کنید. کد زیر را برایmain.cppوSampleNativeClient.cppببینید:main.cppint 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.cppvoid 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); }
نظارت بر سلامت سرویسهای جاوا
پیادهسازی یک کلاینت با ارثبری از CarWatchdogClientCallback
- فایل جدید را به صورت زیر ویرایش کنید:
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() {} };
مشتری را ثبت کنید
- فراخوانی
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); }
لغو ثبت نام مشتری
- وقتی سرویس تمام شد،
CarWatchdogManager.unregisterClient()را فراخوانی کنید:private void finishClient() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager( Car.CAR_WATCHDOG_SERVICE); manager.unregisterClient(mClientCallback); }
نظارت بر سلامت VHAL
برخلاف نظارت بر سلامت سرویس فروشنده، Watchdog با عضویت در ویژگی وسیله نقلیه VHAL_HEARTBEAT ، سلامت سرویس VHAL را رصد میکند. Watchdog انتظار دارد مقدار این ویژگی هر N ثانیه یک بار بهروزرسانی شود. وقتی ضربان قلب در این بازه زمانی بهروزرسانی نشود، Watchdog سرویس VHAL را خاتمه میدهد.
توجه: Watchdog فقط زمانی سلامت سرویس VHAL را رصد میکند که ویژگی وسیله نقلیه VHAL_HEARTBEAT توسط سرویس VHAL پشتیبانی شود.
پیادهسازی داخلی VHAL میتواند بسته به فروشنده متفاوت باشد. از نمونههای کد زیر به عنوان مرجع استفاده کنید.
- ویژگی وسیله نقلیه
VHAL_HEARTBEATرا ثبت کنید.هنگام شروع سرویس VHAL، ویژگی وسیله نقلیه
VHAL_HEARTBEATرا ثبت کنید. در مثال زیر، از یکunordered_mapکه شناسه ویژگی را به پیکربندی نگاشت میکند، برای نگهداری تمام پیکربندیهای پشتیبانی شده استفاده میشود. پیکربندیVHAL_HEARTBEATبه نقشه اضافه میشود، به طوری که وقتیVHAL_HEARTBEATدرخواست میشود، پیکربندی مربوطه بازگردانده میشود.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; }
- ویژگی وسیله نقلیه
VHAL_HEARTBEATرا بهروزرسانی کنید.بر اساس فرکانس بررسی سلامت VHAL (که در بخش «تعریف فرکانس بررسی سلامت VHAL» توضیح داده شده است)، ویژگی وسیله نقلیه
VHAL_HEARTBEATرا هر N ثانیه یک بار بهروزرسانی کنید. یک راه برای انجام این کار، استفاده ازRecurrentTimerبرای فراخوانی عملی است که سلامت VHAL را بررسی میکند و ویژگی وسیله نقلیهVHAL_HEARTBEATرا در بازه زمانی مشخص بهروزرسانی میکند.در زیر یک پیادهسازی نمونه با استفاده از
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)); } }
- ( اختیاری ) تعداد دفعات بررسی سلامت VHAL را تعیین کنید.
ویژگی محصول فقط خواندنی
ro.carwatchdog.vhal_healthcheck.intervalدر Watchdog، فرکانس بررسی سلامت VHAL را تعریف میکند. فرکانس پیشفرض بررسی سلامت (وقتی این ویژگی تعریف نشده باشد) سه ثانیه است. اگر سه ثانیه برای بهروزرسانی ویژگی وسیله نقلیهVHAL_HEARTBEATتوسط سرویس VHAL کافی نیست، فرکانس بررسی سلامت VHAL را بسته به میزان پاسخگویی سرویس تعریف کنید.
اشکالزدایی فرآیندهای ناسالم که توسط نگهبان خاتمه یافتهاند
Watchdog وضعیت فرآیند را بررسی کرده و فرآیندهای ناسالم را خاتمه میدهد. هنگام خاتمه دادن به یک فرآیند ناسالم، Watchdog متن carwatchdog terminated <process name> (pid:<process id>) را در logcat ثبت میکند. این خط گزارش اطلاعاتی در مورد فرآیند خاتمه یافته مانند نام فرآیند و شناسه فرآیند ارائه میدهد.
- با اجرای دستور زیر میتوان متن فوقالذکر را در logcat جستجو کرد:
$ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"
برای مثال، وقتی برنامه KitchenSink یک کلاینت ثبتشده Watchdog است و به پینگهای Watchdog پاسخ نمیدهد، Watchdog هنگام خاتمه دادن به فرآیند ثبتشده KitchenSink، خطی مانند خط زیر را ثبت میکند.
05-01 09:50:19.683 578 5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)
- برای شناسایی علت اصلی عدم پاسخگویی، از dump فرآیند ذخیره شده در
/data/anrهمانطور که برای موارد ANR فعالیت استفاده میکنید، استفاده کنید. برای بازیابی فایل dump برای فرآیند خاتمه یافته از دستورات زیر استفاده کنید.$ adb root $ adb shell grep -Hn "pid process_pid" /data/anr/*
نمونه خروجی زیر مختص برنامه 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 -----
فایل dump مربوط به فرآیند خاتمه یافته KitchenSink در آدرس
/data/anr/anr_2020-05-01-09-50-18-290قرار دارد. تجزیه و تحلیل خود را با استفاده از فایل dump مربوط به فرآیند خاتمه یافته آغاز کنید.