مراقبة حالة النظام

تراقب مراقب النظام سلامة خدمات البائعين وخدمة VHAL، لإنهاء أي عملية غير صحية. عند إنهاء عملية غير صحية، تقوم مراقب النظام تفريغ حالة العملية إلى /data/anr كما هو الحال مع التطبيق الآخر "لا يستجيب" حالات التفريغ. ويسهّل ذلك عملية تصحيح الأخطاء.

مراقبة سلامة خدمة المورّدين

تتم مراقبة خدمات المورّدين على كل من الجانب الأصلي وجانب Java. لكي تتم مراقبة خدمة أحد المورّدين، يجب أن تسجِّل الخدمة عملية التحقّق من الصحة مع Watchdog من خلال تحديد مهلة محدّدة مسبقًا. يرصد Watchdog صحة عملية التحقّق من الصحة المسجّلة من خلال إرسال طلبات فحص لها على فترات متباينة نسبةً إلى مهلة الانتظار المحدّدة أثناء التسجيل. عندما يتم فحص اتصال عدم استجابة العملية خلال المهلة المحددة، تُعد العملية غير صحية.

مراقبة سلامة الخدمة الأصلية

تحديد ملف الحالة AIDL لـ مراقب النظام

  1. تضمين 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

  1. لإضافة سياسة 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

  1. في "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.

  1. ابحث عن الخادم الدائم الذي يحمل الاسم 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

  1. عدِّل الملف الجديد على النحو التالي:
    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() {}
    };

تسجيل العميل

  1. الاتصال بـ 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);
    }

إلغاء تسجيل العميل

  1. يمكنك الاتصال بالرقم CarWatchdogManager.unregisterClient() عند انتهاء الخدمة:
    private void finishClient() {
        CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(
            Car.CAR_WATCHDOG_SERVICE);
        manager.unregisterClient(mClientCallback);
    }

مراقبة حالة "القيادة الآلية في مواقف هامة"

على عكس مراقبة حالة خدمة المورّد، يراقب برنامج Watchdog حالة خدمة VHAL من خلال الاشتراك في سمة المركبة VHAL_HEARTBEAT. يتوقع مراقب النظام أن يتم تعديل قيمة هذه السمة مرة واحدة كل N ثانية. عندما لا يتم تعديل إشارة المتابعة خلال مهلة الانتظار هذه، يُنهي برنامج "الحارس" خدمة VHAL .

ملاحظة: لا يراقب برنامج Watchdog حالة خدمة VHAL إلا عندما تكون خاصية المركبة VHAL_HEARTBEAT متوافقة مع خدمة VHAL.

يمكن أن يختلف التنفيذ الداخلي لبروتوكول VHAL حسب المورّد. استخدِم نماذج الرموز البرمجية التالية كمراجع.

  1. تسجيل الخاصية "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;
    }
  2. عدِّل خاصية المركبة 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));
           }
    }
  3. (اختياري) حدِّد معدّل تكرار التحقّق من صحة VHAL.

    إذن الوصول إلى ro.carwatchdog.vhal_healthcheck.interval من مراقب النظام تحدد سمة المنتج تكرار التحقق من صحة VHAL. التحقّق التلقائي من الصحة معدل التكرار (عندما لا تكون هذه الخاصية محددة) ثلاث ثوانٍ. وإذا لم تكن ثلاث ثوانٍ بما يكفي لخدمة VHAL لتعديل خاصية المركبة في VHAL_HEARTBEAT تحديد معدل تكرار فحص حالة VHAL بناءً على استجابة الخدمة.

تصحيح الأخطاء في العمليات غير السليمة التي أنهتها مراقب النظام

يُرسِل برنامج "الحارس" حالة العملية ويُنهي العمليات غير الصالحة. عند الإنهاء عملية غير صحية، يسجل مراقب النظام النص carwatchdog terminated <process name> (pid:<process id>) إلى Logcat. يقدّم سطر السجلّ هذا معلومات عن العملية التي تم إنهاءها، مثل اسم العملية و رقم تعريفها.

  1. يمكن البحث في 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)
  2. لتحديد السبب الجذري لعدم الاستجابة، استخدم العملية تم تخزين تفريغ في /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 للعملية التي تم إنهاؤها.