يراقب برنامج Watchdog حالة خدمات المورّدين وخدمة VHAL، ويُنهي
أي عملية غير سليمة. عند إنهاء عملية غير طبيعية، يُرسِل برنامج Watchdog
حالة العملية إلى /data/anr
كما هو الحال مع عمليات تفريغ أخطاء "التطبيق لا يستجيب" (ANR) الأخرى. ويسهّل ذلك عملية تصحيح الأخطاء.
مراقبة حالة خدمة المورّد
تتم مراقبة خدمات المورّدين على كل من الجانب الأصلي وجانب Java. لكي تتم مراقبة خدمة أحد المورّدين، يجب أن تسجِّل الخدمة عملية التحقّق من الصحة مع Watchdog من خلال تحديد مهلة محدّدة مسبقًا. يرصد "المراقب" حالة عملية التحقّق من الصحة المسجّلة من خلال إرسال طلب فحص لها على فترات زمنية متعلّقة بالمهلة المحدّدة أثناء التسجيل. عندما لا تستجيب العملية التي تم إرسال طلب فحص لها خلال مهلة الانتظار، تُعتبر العملية غير طبيعية.
مراقبة حالة الخدمة الأصلية
تحديد ملف make الخاص بلغة تعريف واجهة نظام Android (AIDL) لمراقب النظام
- أدرِج
carwatchdog_aidl_interface-ndk_platform
فيshared_libs
.Android.bp
cc_binary { name: "sample_native_client", srcs: [ "src/*.cpp" ], shared_libs: [ "carwatchdog_aidl_interface-ndk_platform", "libbinder_ndk", ], vendor: true, }
إضافة سياسة SELinux
- لإضافة سياسة SELinux، اسمح لنطاق خدمة المورّد باستخدام الرابط
(الماكرو
binder_use
) وأضِف نطاق خدمة المورّد إلىcarwatchdog
نطاق العميل (الماكروcarwatchdog_client_domain
). اطّلِع على الرمز أدناه لكل منsample_client.te
و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
تنفيذ فئة عميل من خلال اكتساب فئة BnCarWatchdogClient
- في
checkIfAlive
، عليك إجراء عملية التحقّق من الصحة. أحد الخيارات هو نشر المحتوى على معالِج حلقة السلسلة. إذا كان الجهاز يعمل بشكل سليم، يُرجى الاتصال برقمICarWatchdog::tellClientAlive
. اطّلِع على الرمز أدناه لكل منSampleNativeClient.h
و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); }
بدء سلسلة محادثات بين العناصر وتسجيل العميل
اسم واجهة برنامج التشغيل الخفي لمراقب نظام السيارة هو
android.automotive.watchdog.ICarWatchdog/default
.
- ابحث عن الخادم الدائم الذي يحمل الاسم
ICarWatchdog::registerClient
. اطّلِع على الرمز أدناه لكل منmain.cpp
و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); }
مراقبة حالة خدمة Java
تنفيذ عميل من خلال اكتساب 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); }
مراقبة حالة "القيادة الآلية في مواقف المرور المزدحمة"
على عكس مراقبة حالة خدمة المورّد، تتحقّق أداة Watchdog من حالة خدمة VHAL
من خلال الاشتراك في سمة المركبة VHAL_HEARTBEAT
.
يتوقّع برنامج Watchdog أن يتم تعديل قيمة هذه السمة مرّة واحدة كل N ثانية.
عندما لا يتم تعديل إشارة المتابعة خلال مهلة الانتظار هذه، يُنهي برنامج "الحارس" خدمة 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
للمراقبة فقط في أداة "الحارس" معدّل تكرار التحقّق من حالة VHAL. المدة التلقائية لفحص الحالة (في حال عدم تحديد هذه السمة) هي ثلاث ثوانٍ. إذا لم تكن ثلاث ثوانٍ كافية لخدمة VHAL لتعديل سمة المركبةVHAL_HEARTBEAT
، حدِّد معدّل تكرار التحقّق من حالة VHAL استنادًا إلى استجابة الخدمة.
تصحيح أخطاء العمليات غير الصالحة التي أنهاها برنامج "الحارس"
يُرسِل برنامج "الحارس" حالة العملية ويُنهي العمليات غير الصالحة. عند إنهاء
عملية غير طبيعية، يسجِّل 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)
- لتحديد السبب الأساسي لعدم الاستجابة، استخدِم عملية تسجيل أثر
العملية المخزّنة في
/data/anr
تمامًا كما تفعل مع حالات ANR للنشاط. لاسترداد ملف الذاكرة المؤقتة للعملية التي تم إنهاؤها، استخدِم الأوامر التالية.$ 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 -----
يمكن العثور على ملف "الترميز المضغوط" لعملية KitchenSink التي تم إنهاءها على العنوان
/data/anr/anr_2020-05-01-09-50-18-290
. ابدأ التحليل باستخدام ملف ANR dump الخاص بالعملية التي تم إنهاءها.