perro guardián del coche

Use el perro guardián del automóvil para ayudar a depurar el VHAL. Car watchdog monitorea la salud de los procesos no saludables y los elimina. Para que un proceso sea monitoreado por el perro guardián del automóvil, el proceso debe estar registrado con el perro guardián del automóvil. Cuando el mecanismo de vigilancia del automóvil elimina los procesos en mal estado, el mecanismo de vigilancia del automóvil escribe el estado de los procesos en data/anr como ocurre con otros volcados de aplicaciones que no responden (ANR). Si lo hace, facilita el proceso de depuración.

Este artículo describe cómo los HAL y los servicios del proveedor pueden registrar un proceso con el organismo de control del automóvil.

HAL del proveedor

Por lo general, el proveedor HAL usa un grupo de subprocesos para hwbinder . Sin embargo, el cliente de vigilancia del automóvil se comunica con el demonio de vigilancia del automóvil a través de binder , que difiere de hwbinder . Por lo tanto, se está utilizando otro grupo de subprocesos para el binder .

Especificar la ayuda del perro guardián del automóvil en el archivo MAKE

  1. Incluya carwatchdog_aidl_interface-ndk_platform en shared_libs :

    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",
        ],
    }
    

Agregar una política de SELinux

  1. Permita que system_server su HAL. Si no tiene system_server.te , cree uno. Se recomienda encarecidamente agregar una política de SELinux a cada dispositivo.
  2. Permita que el HAL del proveedor use el enlazador (macro binder_use ) y agregue el HAL del proveedor al dominio del cliente carwatchdog (macro carwatchdog_client_domain ). Consulte el siguiente código para systemserver.te y vehicle_default.te :

    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)
    

Implemente una clase de cliente heredando BnCarWatchdogClient

  1. En checkIfAlive , realice una verificación de estado. Por ejemplo, publique en el controlador de bucle de subprocesos. Si está en buen estado, llame a ICarWatchdog::tellClientAlive . Consulte el siguiente código para WatchogClient.h y WatchogClient.cpp :

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

Inicie el hilo de la carpeta y registre el cliente

  1. Cree un grupo de subprocesos para la comunicación del enlazador. Si el proveedor HAL usa hwbinder para sus propios fines, debe crear otro grupo de subprocesos para la comunicación del enlazador de vigilancia del automóvil).
  2. Busque el daemon con el nombre y llame a ICarWatchdog::registerClient . El nombre de la interfaz del demonio de vigilancia del automóvil es android.automotive.watchdog.ICarWatchdog/default .
  3. Según la capacidad de respuesta del servicio, seleccione uno de los siguientes tres tipos de tiempo de espera admitidos por el mecanismo de vigilancia del automóvil y luego pase el tiempo de espera en la llamada a ICarWatchdog::registerClient :
    • crítico (3s)
    • moderado (5s)
    • normales (10 s)
    Consulte el siguiente código para VehicleService.cpp y WatchogClient.cpp :

    VehicleService.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;
    }
    

Servicios de proveedores (nativos)

Especificar el archivo MAKE del asistente de vigilancia del automóvil

  1. Incluya carwatchdog_aidl_interface-ndk_platform en shared_libs .

    Android.bp

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

Agregar una política de SELinux

  1. Para agregar una política de SELinux, permita que el dominio de servicio del proveedor use binder (macro binder_use ) y agregue el dominio de servicio del proveedor al dominio del cliente carwatchdog (macro carwatchdog_client_domain ). Consulte el siguiente código para sample_client.te y file_contexts :

    ejemplo_cliente.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)
    

    contextos_de_archivo

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

Implemente una clase de cliente heredando BnCarWatchdogClient

  1. En checkIfAlive , realice una verificación de estado. Una opción es publicar en el controlador de bucle de subprocesos. Si está en buen estado, llame a ICarWatchdog::tellClientAlive . Consulte el siguiente código para SampleNativeClient.h y 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);
    }
    

Inicie un hilo de carpeta y registre el cliente

El nombre de la interfaz del demonio de vigilancia del automóvil es android.automotive.watchdog.ICarWatchdog/default .

  1. Busque el daemon con el nombre y llame a ICarWatchdog::registerClient . Consulte el siguiente código para main.cpp y SampleNativeClient.cpp :

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

Servicios de proveedores (Android)

Implemente un cliente heredando CarWatchdogClientCallback

  1. Edite el nuevo archivo de la siguiente manera:
    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() {}
    };
    

Registrar el cliente

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

Dar de baja al cliente

  1. Llame CarWatchdogManager.unregisterClient() cuando finalice el servicio:
    private void finishClient() {
        CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(
            Car.CAR_WATCHDOG_SERVICE);
        manager.unregisterClient(mClientCallback);
    }
    

Detectar procesos terminados por el perro guardián del automóvil

Procesos de volcados/eliminaciones del organismo de control del automóvil (HAL del proveedor, servicios nativos del proveedor, servicios de Android del proveedor) que están registrados en el organismo de control del automóvil cuando están atascados y no responden. Dicho vertido se detecta mediante la comprobación de logcats. El perro guardián del automóvil genera un registro que el perro guardián del automóvil carwatchdog killed process_name (pid:process_id) cuando se descarga o elimina un proceso problemático. Por lo tanto:

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

Se capturan los registros relevantes. Por ejemplo, si la aplicación KitchenSink (un cliente de control de automóviles) se atasca, se escribe una línea como la siguiente en el registro:

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

Para determinar por qué o dónde se atascó la aplicación KitchenSink, use el volcado de proceso almacenado en /data/anr tal como usaría los casos de Actividad ANR.

$ adb root
$ adb shell grep -Hn "pid process_pid" /data/anr/*

El siguiente resultado de muestra es específico de la aplicación 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 -----

Busque el archivo de volcado (por ejemplo, /data/anr/anr_2020-05-01-09-50-18-290 en el ejemplo anterior) y comience su análisis.