Sistem sağlığını izleyin

Watchdog, satıcı hizmetlerinin ve VHAL hizmetinin durumunu izler ve sağlıksız süreçleri sonlandırır. Sağlıksız bir süreç sonlandırıldığında, Watchdog diğer Yanıt Vermeyen Uygulama (ANR) dökümlerinde olduğu gibi işlem durumunu /data/anr dizinine aktarır. Bunu yapmak hata ayıklama işlemini kolaylaştırır.

Satıcı hizmet durumunun izlenmesi

Satıcı hizmetleri hem yerel hem de Java tarafında izlenir. Bir Satıcı hizmetinin izlenebilmesi için, hizmetin önceden tanımlanmış bir zaman aşımı belirterek Watchdog'a bir sağlık kontrolü süreci kaydetmesi gerekir. Watchdog, kayıt sırasında belirtilen zaman aşımına göre belirli bir aralıkta ping atarak kayıtlı bir sağlık kontrolü sürecinin durumunu izler. Pinglenen bir süreç zaman aşımı süresi içinde yanıt vermediğinde, sürecin sağlıksız olduğu kabul edilir.

Yerel hizmet durumu izleme

Watchdog AIDL makefile dosyasını belirtin

  1. carwatchdog_aidl_interface-ndk_platform shared_libs ekleyin.

    Android.bp

    cc_binary {
        name: "sample_native_client",
        srcs: [
            "src/*.cpp"
        ],
        shared_libs: [
            "carwatchdog_aidl_interface-ndk_platform",
            "libbinder_ndk",
        ],
        vendor: true,
    }
    

SELinux ilkesi ekleme

  1. Bir SELinux politikası eklemek için satıcı hizmet etki alanının bağlayıcıyı ( binder_use makrosu) kullanmasına izin verin ve satıcı hizmet etki alanını carwatchdog istemci etki alanına ( carwatchdog_client_domain makrosu) ekleyin. sample_client.te ve file_contexts için aşağıdaki koda bakın:

    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'i devralarak bir istemci sınıfı uygulayın

  1. checkIfAlive bir durum kontrolü gerçekleştirin. Bir seçenek iş parçacığı döngüsü işleyicisine göndermektir. Sağlıklıysa ICarWatchdog::tellClientAlive arayın. SampleNativeClient.h ve SampleNativeClient.cpp için aşağıdaki koda bakın:

    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);
    }
    

Bir ciltleyici iş parçacığı başlatın ve istemciyi kaydedin

Araba gözlemcisi arka plan programı arayüz adı android.automotive.watchdog.ICarWatchdog/default şeklindedir.

  1. Adıyla birlikte arka plan programını arayın ve ICarWatchdog::registerClient öğesini arayın. main.cpp ve SampleNativeClient.cpp için aşağıdaki koda bakın:

    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 hizmetinin durumunu izleme

CarWatchdogClientCallback'i devralarak bir istemci uygulayın

  1. Yeni dosyayı şu şekilde düzenleyin:
    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() {}
    };
    

İstemciyi kaydedin

  1. CarWatchdogManager.registerClient() öğesini çağırın:
    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);
    }
    

İstemcinin kaydını iptal edin

  1. Hizmet tamamlandığında CarWatchdogManager.unregisterClient() öğesini çağırın:
    private void finishClient() {
        CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(
            Car.CAR_WATCHDOG_SERVICE);
        manager.unregisterClient(mClientCallback);
    }
    

VHAL sağlık takibi

Satıcı hizmet durumu izlemenin aksine Watchdog, VHAL_HEARTBEAT araç özelliğine abone olarak VHAL hizmet durumunu izler. Watchdog, bu özelliğin değerinin her N saniyede bir güncellenmesini beklemektedir. Bu zaman aşımı süresi içerisinde kalp atışı güncellenmediğinde Watchdog VHAL hizmetini sonlandırır.

Not: Watchdog, VHAL hizmetinin durumunu yalnızca VHAL_HEARTBEAT araç özelliği VHAL hizmeti tarafından desteklendiğinde izler.

VHAL dahili uygulaması satıcıya göre değişebilir. Aşağıdaki kod örneklerini referans olarak kullanın.

  1. VHAL_HEARTBEAT araç özelliğini kaydedin.

    VHAL hizmetini başlatırken VHAL_HEARTBEAT araç özelliğini kaydedin. Aşağıdaki örnekte, özellik kimliğini config ile eşleştiren unordered_map , desteklenen tüm yapılandırmaları tutmak için kullanılır. VHAL_HEARTBEAT için yapılandırma haritaya eklenir, böylece VHAL_HEARTBEAT sorgulandığında ilgili yapılandırma döndürülür.

    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 araç özelliğini güncelleyin.

    VHAL durum denetimi sıklığına bağlı olarak ( VHAL durum denetiminin sıklığını tanımlama" bölümünde açıklanmıştır), VHAL_HEARTBEAT araç özelliğini her N saniyede bir güncelleyin. Bunu yapmanın bir yolu, VHAL durumunu kontrol eden eylemi çağırmak için RecurrentTimer kullanmaktır ve VHAL_HEARTBEAT araç özelliğini zaman aşımı içerisinde günceller.

    Aşağıda RecurrentTimer kullanan örnek bir uygulama gösterilmektedir:

    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. ( İsteğe bağlı ) VHAL durum kontrolünün sıklığını tanımlayın.

    Watchdog'un ro.carwatchdog.vhal_healthcheck.interval salt okunur ürün özelliği, VHAL durum kontrolü sıklığını tanımlar. Varsayılan durum denetimi sıklığı (bu özellik tanımlanmadığında) üç saniyedir. VHAL hizmetinin VHAL_HEARTBEAT araç özelliğini güncellemesi için üç saniye yeterli değilse, hizmetin yanıt verme durumuna bağlı olarak VHAL durum denetimi sıklığını tanımlayın.

Watchdog tarafından sonlandırılan sağlıksız işlemlerde hata ayıklama

Watchdog süreç durumunu atar ve sağlıksız süreçleri sonlandırır. Sağlıksız bir süreci sonlandırırken Watchdog, carwatchdog terminated <process name> (pid:<process id>) metnini logcat'e kaydeder. Bu günlük satırı, sonlandırılan işlem hakkında işlem adı ve işlem kimliği gibi bilgiler sağlar.

  1. Logcat yukarıda belirtilen metni aşağıdaki komutu çalıştırarak arayabilir:
    $ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"
    

    Örneğin, KitchenSink uygulaması kayıtlı bir Watchdog istemcisi olduğunda ve Watchdog ping'lerine yanıt vermediğinde, Watchdog kayıtlı KitchenSink işlemini sonlandırırken aşağıdaki satıra benzer bir satırı günlüğe kaydeder.

    05-01 09:50:19.683   578  5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)
    
  2. Yanıt vermemenin temel nedenini belirlemek için, etkinlik ANR vakalarında kullandığınız gibi /data/anr konumunda depolanan işlem dökümünü kullanın. Sonlandırılan işlemin döküm dosyasını almak için aşağıdaki komutları kullanın.
    $ adb root
    $ adb shell grep -Hn "pid process_pid" /data/anr/*
    

    Aşağıdaki örnek çıktı KitchenSink uygulamasına özeldir:

    $ 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 -----
    

    Sonlandırılan KitchenSink işleminin döküm dosyası /data/anr/anr_2020-05-01-09-50-18-290 konumunda bulunur. Sonlandırılan işlemin ANR döküm dosyasını kullanarak analizinizi başlatın.