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

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

مراقبة صحة خدمة البائع

تتم مراقبة خدمات البائعين على كلا الجانبين الأصلي وجافا. لكي تتم مراقبة خدمة البائع، يجب أن تسجل الخدمة عملية فحص السلامة لدى الوكالة الدولية للطاقة عن طريق تحديد مهلة محددة مسبقًا. تقوم الوكالة الدولية للطاقة بمراقبة صحة عملية التحقق من الصحة المسجلة عن طريق اختبارها على فترات زمنية تتعلق بالمهلة المحددة أثناء التسجيل. عندما لا تستجيب العملية التي يتم اختبار الاتصال بها خلال المهلة المحددة، تعتبر العملية غير صحية.

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

حدد ملف تعريف 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);
    }
    

مراقبة صحة خدمة جافا

تنفيذ العميل عن طريق وراثة 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);
    }
    

مراقبة الصحة VHAL

على عكس مراقبة صحة خدمة البائع، تقوم Watchdog بمراقبة صحة خدمة VHAL من خلال الاشتراك في خاصية مركبة VHAL_HEARTBEAT . تتوقع Watchdog أن يتم تحديث قيمة هذه الخاصية مرة واحدة كل N ثانية. عندما لا يتم تحديث نبضات القلب خلال هذه المهلة، يقوم Watchdog بإنهاء خدمة VHAL.

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

يمكن أن يختلف التنفيذ الداخلي لـ VHAL حسب البائع. استخدم نماذج التعليمات البرمجية التالية كمراجع.

  1. قم بتسجيل ملكية مركبة VHAL_HEARTBEAT .

    عند بدء تشغيل خدمة VHAL، قم بتسجيل خاصية المركبة VHAL_HEARTBEAT . في المثال أدناه، يتم استخدام unordered_map ، الذي يقوم بتعيين معرف الخاصية إلى config للاحتفاظ بجميع التكوينات المدعومة. تتم إضافة تكوين 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 الخاصة بـ Watchdog تكرار فحص صحة VHAL. معدل تكرار التحقق من السلامة الافتراضي (عندما لا يتم تعريف هذه الخاصية) هو ثلاث ثوانٍ. إذا لم تكن ثلاث ثوانٍ كافية لخدمة VHAL لتحديث خاصية السيارة VHAL_HEARTBEAT ، فحدد تكرار فحص صحة VHAL اعتمادًا على استجابة الخدمة.

تصحيح العمليات غير الصحية التي أنهتها الوكالة الدولية للطاقة

تقوم الوكالة الدولية للطاقة بتفريغ حالة العملية وإنهاء العمليات غير الصحية. عند إنهاء عملية غير صحية، تقوم Watchdog بتسجيل النص 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 الخاص بالعملية المنتهية.