araba bekçisi

Koleksiyonlar ile düzeninizi koruyun İçeriği tercihlerinize göre kaydedin ve kategorilere ayırın.

VHAL'da hata ayıklamaya yardımcı olması için araba bekçi köpeğini kullanın. Araba bekçisi, sağlıksız süreçlerin sağlığını izler ve öldürür. Bir işlemin araba bekçisi tarafından izlenmesi için, işlemin araba bekçisine kaydedilmesi gerekir. Araba bekçisi sağlıksız süreçleri öldürdüğünde, araba bekçisi diğer Uygulama Yanıt Vermiyor (ANR) dökümlerinde olduğu gibi süreçlerin durumunu data/anr yazar. Bunu yapmak hata ayıklama sürecini kolaylaştırır.

Bu makale, satıcı HAL'lerinin ve hizmetlerinin bir işlemi araba bekçi köpeğine nasıl kaydettirebileceğini açıklar.

Satıcı HAL

Tipik olarak, satıcı HAL, hwbinder için bir iş parçacığı havuzu kullanır. Ancak, car watchdog istemcisi car watchdog arka plan programı ile hwbinder farklı olan binder aracılığıyla iletişim kurar. Bu nedenle, binder için başka bir iş parçacığı havuzu kullanımda.

Makefile'de araba bekçisi yardımını belirtin

  1. carwatchdog_aidl_interface-ndk_platform shared_libs dahil edin:

    Android.bp :

    cc_defaults {
        name: "vhal_v2_0_defaults",
        shared_libs: [
            "libbinder_ndk",
            "libhidlbase",
            "liblog",
            "libutils",
            "android.hardware.automotive.vehicle@2.0",
            "carwatchdog_aidl_interface-ndk_platform",
        ],
        cflags: [
            "-Wall",
            "-Wextra",
            "-Werror",
        ],
    }
    

Bir SELinux Politikası ekleyin

  1. system_server öldürmesine izin verin. system_server.te sahip değilseniz, bir tane oluşturun. Her cihaza bir SELinux politikası eklemeniz şiddetle tavsiye edilir.
  2. Satıcı HAL'sinin bağlayıcıyı ( binder_use makrosu) kullanmasına izin verin ve satıcı carwatchdog istemci etki alanına ekleyin ( carwatchdog_client_domain makrosu). systemserver.te ve vehicle_default.te için aşağıdaki koda bakın:

    system_server.te

    # Allow system_server to kill vehicle HAL
    allow system_server hal_vehicle_server:process sigkill;
    

    hal_vehicle_default.te

    # Configuration for register VHAL to car watchdog
    carwatchdog_client_domain(hal_vehicle_default)
    binder_use(hal_vehicle_default)
    

BnCarWatchdogClient'i devralarak bir istemci sınıfı uygulayın

  1. checkIfAlive , sağlık kontrolü yapın. Örneğin, iş parçacığı döngüsü işleyicisine gönderin. Sağlıklıysa, ICarWatchdog::tellClientAlive . WatchogClient.h ve WatchogClient.cpp için aşağıdaki koda bakın:

    WatchogClient.h

    class WatchdogClient : public aidl::android::automotive::watchdog::BnCarWatchdogClient {
      public:
        explicit WatchdogClient(const ::android::sp<::android::Looper>& handlerLooper, VehicleHalManager* vhalManager);
    
    ndk::ScopedAStatus checkIfAlive(int32_t sessionId, aidl::android::automotive::watchdog::TimeoutLength timeout) override; ndk::ScopedAStatus prepareProcessTermination() override; };

    WatchogClient.cpp

    ndk::ScopedAStatus WatchdogClient::checkIfAlive(int32_t sessionId, TimeoutLength /*timeout*/) {
        // Implement or call your health check logic here
        return ndk::ScopedAStatus::ok();
    }
    

Bağlayıcı iş parçacığını başlatın ve istemciyi kaydedin

  1. Bağlayıcı iletişimi için bir iş parçacığı havuzu oluşturun. Satıcı HAL hwbinder'ı kendi amacı için kullanıyorsa, araba bekçisi bağlayıcı iletişimi için başka bir iş parçacığı havuzu oluşturmanız gerekir).
  2. Adı olan arka plan programını arayın ve ICarWatchdog::registerClient arayın. Araba bekçi köpeği arka plan programı arabirim adı android.automotive.watchdog.ICarWatchdog/default şeklindedir.
  3. Hizmetin yanıt verme hızına bağlı olarak, araba bekçisi tarafından desteklenen aşağıdaki üç zaman aşımı türünden birini seçin ve ardından ICarWatchdog::registerClient çağrısındaki zaman aşımını iletin:
    • kritik(3s)
    • orta (5s)
    • normal (10s)
    VehicleService.cpp ve WatchogClient.cpp için aşağıdaki koda bakın:

    AraçHizmet.cpp

    int main(int /* argc */, char* /* argv */ []) {
        // Set up thread pool for hwbinder
        configureRpcThreadpool(4, false /* callerWillJoin */);
    
        ALOGI("Registering as service...");
        status_t status = service->registerAsService();
    
        if (status != OK) {
            ALOGE("Unable to register vehicle service (%d)", status);
            return 1;
        }
    
        // Setup a binder thread pool to be a car watchdog client.
        ABinderProcess_setThreadPoolMaxThreadCount(1);
        ABinderProcess_startThreadPool();
        sp<Looper> looper(Looper::prepare(0 /* opts */));
        std::shared_ptr<WatchdogClient> watchdogClient =
                ndk::SharedRefBase::make<WatchdogClient>(looper, service.get());
        // The current health check is done in the main thread, so it falls short of capturing the real
        // situation. Checking through HAL binder thread should be considered.
        if (!watchdogClient->initialize()) {
            ALOGE("Failed to initialize car watchdog client");
            return 1;
        }
        ALOGI("Ready");
        while (true) {
            looper->pollAll(-1 /* timeoutMillis */);
        }
    
        return 1;
    }
    

    WatchogClient.cpp

    bool WatchdogClient::initialize() {
        ndk::SpAIBinder binder(AServiceManager_getService("android.automotive.watchdog.ICarWatchdog/default"));
        if (binder.get() == nullptr) {
            ALOGE("Failed to get carwatchdog daemon");
            return false;
        }
        std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
        if (server == nullptr) {
            ALOGE("Failed to connect to carwatchdog daemon");
            return false;
        }
        mWatchdogServer = server;
    
        binder = this->asBinder();
        if (binder.get() == nullptr) {
            ALOGE("Failed to get car watchdog client binder object");
            return false;
        }
        std::shared_ptr<ICarWatchdogClient> client = ICarWatchdogClient::fromBinder(binder);
        if (client == nullptr) {
            ALOGE("Failed to get ICarWatchdogClient from binder");
            return false;
        }
        mTestClient = client;
        mWatchdogServer->registerClient(client, TimeoutLength::TIMEOUT_NORMAL);
        ALOGI("Successfully registered the client to car watchdog server");
        return true;
    }
    

Satıcı Hizmetleri (Yerel)

Araba bekçisi aidl makefile'ı belirtin

  1. carwatchdog_aidl_interface-ndk_platform shared_libs dahil edin.

    Android.bp

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

Bir SELinux ilkesi ekleyin

  1. Bir SELinux ilkesi eklemek için, satıcı hizmet etki alanının bağlayıcıyı ( binder_use makrosu) kullanmasına izin verin ve satıcı hizmeti etki alanını carwatchdog istemci etki alanına ekleyin ( carwatchdog_client_domain makrosu). 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)
    

    dosya_bağlamları

    /vendor/bin/sample_native_client  u:object_r:sample_client_exec:s0
    

BnCarWatchdogClient'i devralarak bir istemci sınıfı uygulayın

  1. checkIfAlive içinde bir sağlık kontrolü yapın. Bir seçenek, iş parçacığı döngüsü işleyicisine göndermektir. Sağlıklıysa, ICarWatchdog::tellClientAlive . 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 bağlayıcı iş parçacığı başlatın ve istemciyi kaydedin

Araba bekçi köpeği arka plan programı arabirim adı android.automotive.watchdog.ICarWatchdog/default şeklindedir.

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

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

Satıcı Hizmetleri (Android)

CarWatchdogClientCallback'i devralarak bir istemci uygulayın

  1. Yeni dosyayı aşağıdaki gibi 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() {}
    };
    

Müşteriyi kaydedin

  1. CarWatchdogManager.registerClient() arayı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 et

  1. Hizmet bittiğinde CarWatchdogManager.unregisterClient() arayın:
    private void finishClient() {
        CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(
            Car.CAR_WATCHDOG_SERVICE);
        manager.unregisterClient(mClientCallback);
    }
    

Araba bekçisi tarafından sonlandırılan süreçleri tespit edin

Araba bekçisi, takıldıklarında ve yanıt vermediğinde araba bekçisine kayıtlı olan süreçleri (satıcı HAL, satıcı yerel hizmetleri, satıcı Android hizmetleri) boşaltır/öldürür. Bu tür damping, logcat'ler kontrol edilerek tespit edilir. Araba bekçisi, sorunlu bir süreç terk edildiğinde veya öldürüldüğünde, bir günlük carwatchdog killed process_name (pid:process_id) çıktısı verir. Bu nedenle:

$ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"

İlgili günlükler yakalanır. Örneğin, KitchenSink uygulaması (araba bekçisi istemcisi) takılırsa, günlüğe aşağıdakine benzer bir satır yazılır:

05-01 09:50:19.683   578  5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)

KitchenSink uygulamasının neden veya nerede takıldığını belirlemek için /data/anr konumunda depolanan işlem dökümünü, Activity ANR durumlarını kullandığınız gibi 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 -----

Döküm dosyasını bulun (örneğin, yukarıdaki örnekte /data/anr/anr_2020-05-01-09-50-18-290 ) ve analizinize başlayın.