Usa el perro guardián del vehículo para depurar el VHAL. Monitores de perros guardián de automóviles
el estado de los procesos en mal estado
y los elimina. Para que un proceso se supervise
por el perro guardián del vehículo, el proceso debe registrarse con el perro guardián del vehículo. Cuándo
el perro guardián del vehículo finaliza los procesos en mal estado, el perro guardián del vehículo escribe el estado
los procesos a data/anr
, como con otra Aplicación no responde
(ANR). Hacerlo facilita el proceso de depuración.
En este artículo, se describe cómo las HAL y los servicios del proveedor pueden registrar un proceso con el perro guardián del vehículo.
HAL del proveedor
Por lo general, la HAL del proveedor usa un conjunto de subprocesos para hwbinder
. Sin embargo,
el cliente de perro guardián del vehículo se comunica con el daemon de perro guardián del vehículo a través de
binder
, que es diferente de hwbinder
. Por lo tanto,
hay otro conjunto de subprocesos en uso para binder
.
Especifica el ID de perro guardián del vehículo en el archivo makefile
- Incluye
carwatchdog_aidl_interface-ndk_platform
enshared_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", ], }
Agrega una política de SELinux
-
Permite que
system_server
cierre tu HAL. Si no tienessystem_server.te
, crea una. Es muy importante se recomendó agregar una política SELinux a cada dispositivo. -
Permitir que la HAL del proveedor use Binder (macro
binder_use
) y agrega la HAL del proveedor al dominio del clientecarwatchdog
. (macrocarwatchdog_client_domain
). Consulta el siguiente código parasystemserver.te
yvehicle_default.te
:sistema_servidor.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)
Implementa una clase de cliente heredando BnCarWatchdogClient
-
En
checkIfAlive
, realiza la verificación de estado. Por ejemplo, puedes publicar de bucle de subprocesos. Si está en buen estado, llama aICarWatchdog::tellClientAlive
. Consulta el siguiente código paraWatchogClient.h
yWatchogClient.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(); }
Inicia el subproceso de Binder y registra el cliente
- Crea un conjunto de subprocesos para la comunicación de Binder. Si el proveedor HAL usa hwbinder para su para tu propio propósito, debes crear otro conjunto de subprocesos para la comunicación de Binder de perro guardián del vehículo.
-
Busca el daemon con el nombre y llama a
ICarWatchdog::registerClient
. El nombre de la interfaz del daemon de perro guardián del vehículo esandroid.automotive.watchdog.ICarWatchdog/default
-
En función de la capacidad de respuesta del servicio, selecciona uno de los siguientes tres tipos de tiempo de espera
compatible con el perro guardián del vehículo y luego pasa el tiempo de espera en la llamada a
ICarWatchdog::registerClient
:- crítica(3 s)
- moderado(5 s)
- normal(10s)
VehicleService.cpp
yWatchogClient.cpp
:. VehículoService.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)
Especifica el archivo makefile de la ayuda de perro guardián del vehículo
- Incluye
carwatchdog_aidl_interface-ndk_platform
enshared_libs
.Android.bp
cc_binary { name: "sample_native_client", srcs: [ "src/*.cpp" ], shared_libs: [ "carwatchdog_aidl_interface-ndk_platform", "libbinder_ndk", ], vendor: true, }
Agrega una política SELinux
- Para agregar una política de SELinux, permite que el dominio del servicio del proveedor use Binder
(macro
binder_use
) y agrega el dominio de servicio del proveedor al Dominio de clientecarwatchdog
(macrocarwatchdog_client_domain
). Consulta el siguiente código parasample_client.te
yfile_contexts
:cliente_ejemplo.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_archivo
/vendor/bin/sample_native_client u:object_r:sample_client_exec:s0
Implementa una clase de cliente heredando BnCarWatchdogClient
- En
checkIfAlive
, realiza una verificación de estado. Una opción es publicar en el controlador de bucles de subprocesos. Si está en buen estado, llama aICarWatchdog::tellClientAlive
. Consulta el siguiente código paraSampleNativeClient.h
ySampleNativeClient.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); }
Inicia un subproceso de Binder y registra el cliente
El nombre de la interfaz del daemon de perro guardián del vehículo es
android.automotive.watchdog.ICarWatchdog/default
- Busca el daemon con el nombre y llama a
ICarWatchdog::registerClient
. Consulta el siguiente código paramain.cpp
ySampleNativeClient.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); }
Servicios de proveedores (Android)
Cómo implementar un cliente heredando CarWatchdogClientCallback
- Edita el archivo nuevo como se indica a continuación:
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() {} };
Registra el cliente
- Llamar a
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); }
Cancela el registro del cliente
- Llama a
CarWatchdogManager.unregisterClient()
cuando finalice el servicio:private void finishClient() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager( Car.CAR_WATCHDOG_SERVICE); manager.unregisterClient(mClientCallback); }
Detecta procesos finalizados por el perro guardián del vehículo
Procesos de volcado y cierre de perro guardián de automóviles (HAL del proveedor, servicios nativos del proveedor,
servicios de Android del proveedor) que estén registrados en el perro guardián del vehículo cuando
atascado y no responde. Este volcado se detecta mediante la verificación de los logcats. El auto
el perro guardián genera un registro carwatchdog killed process_name (pid:process_id)
cuando un proceso problemático se vuelca o finaliza. Por lo tanto:
$ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"
Se capturan los registros relevantes. Por ejemplo, si la app KitchenSink (un perro guardián de vehículos cliente) se bloquea, se escribe una línea como la que se muestra a continuación 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 detuvo la app de KitchenSink, usa el volcado de procesos
se almacena en /data/anr
del mismo modo que usarías los casos de ANR de actividad.
$ adb root $ adb shell grep -Hn "pid process_pid" /data/anr/*
El siguiente resultado de muestra es específico de la app 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 -----
Busca el archivo de volcado (por ejemplo, /data/anr/anr_2020-05-01-09-50-18-290
).
en el ejemplo anterior) y comienza tu análisis.