Usa il watchdog dell'auto per eseguire il debug del VHAL. Monitor per watchdog auto
l'integrità dei processi non salubri. Per monitorare un processo
dal watchdog dell'auto, il processo deve essere registrato con il watchdog dell'auto. Quando
il watchdog dell'auto termina i processi non integro, il watchdog dell'auto scrive lo stato
i processi per data/anr
come per le altre richieste di non risposta
(ANR). In questo modo facilita il processo di debug.
Questo articolo descrive in che modo gli HAL e i servizi dei fornitori possono registrare un processo con il watchdog dell'auto.
HAL fornitore
In genere, l'HAL del fornitore utilizza un pool di thread per hwbinder
. Tuttavia,
il client watchdog dell'auto comunica con il daemon watchdog dell'auto tramite
binder
, che è diverso da hwbinder
. Pertanto,
è in uso un altro pool di thread per binder
.
Specifica l'aidl per il watchdog dell'auto nel file makefile
- Includi
carwatchdog_aidl_interface-ndk_platform
inshared_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", ], }
Aggiungi un criterio SELinux
-
Consenti a
system_server
di terminare il tuo HAL. Se non haisystem_server.te
, creane uno. È fortemente ti consigliamo di aggiungere un criterio SELinux a ciascun dispositivo. -
Consenti all'HAL del fornitore di utilizzare binder (macro
binder_use
) e aggiungi l'HAL del fornitore al dominio clientcarwatchdog
(macrocarwatchdog_client_domain
). Visualizza il codice seguente persystemserver.te
evehicle_default.te
:. server_di_sistema.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 classe client ereditando BnCarWatchdogClient
-
In
checkIfAlive
, esegui il controllo di integrità. Ad esempio, pubblica nel gestore di loop di thread. Se è integro, chiamaICarWatchdog::tellClientAlive
. Visualizza il codice seguente perWatchogClient.h
eWatchogClient.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(); }
Avvia il thread di binder e registra il client
- Crea un pool di thread per la comunicazione con binder. Se il fornitore HAL utilizza hwbinder per i suoi del tuo scopo, devi creare un altro pool di thread per le comunicazioni con il binder del watchdog dell'auto.
-
Cerca il daemon con il nome e chiama
ICarWatchdog::registerClient
. Il nome dell'interfaccia del daemon watchdog dell'auto èandroid.automotive.watchdog.ICarWatchdog/default
. -
In base alla reattività del servizio, seleziona uno dei tre seguenti tipi di timeout
supportato dal watchdog dell'auto, per poi passare il timeout nella chiamata
ICarWatchdog::registerClient
:- critico(3 s)
- moderato(5 s)
- normale(10 s)
VehicleService.cpp
eWatchogClient.cpp
:ServizioVeicolo.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; }
Servizi dei fornitori (nativi)
Specifica il makefile aidl del watchdog dell'auto
- Includi
carwatchdog_aidl_interface-ndk_platform
inshared_libs
.Android.bp
cc_binary { name: "sample_native_client", srcs: [ "src/*.cpp" ], shared_libs: [ "carwatchdog_aidl_interface-ndk_platform", "libbinder_ndk", ], vendor: true, }
Aggiungi un criterio SELinux
- Per aggiungere un criterio SELinux, consenti al dominio del servizio del fornitore di utilizzare binder
(macro
binder_use
) e aggiungi il dominio del servizio del fornitore alla dominio clientecarwatchdog
(macrocarwatchdog_client_domain
). Visualizza il codice seguente persample_client.te
efile_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)
contesti_file
/vendor/bin/sample_native_client u:object_r:sample_client_exec:s0
Implementare una classe client ereditando BnCarWatchdogClient
- Esegui un controllo di integrità in
checkIfAlive
. Un'opzione è pubblicare su il gestore di loop dei thread. Se è integro, chiamaICarWatchdog::tellClientAlive
. Visualizza il codice seguente perSampleNativeClient.h
eSampleNativeClient.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); }
Avvia un thread di binder e registra il client
Il nome dell'interfaccia del daemon watchdog dell'auto è
android.automotive.watchdog.ICarWatchdog/default
.
- Cerca il daemon con il nome e chiama
ICarWatchdog::registerClient
. Visualizza il codice seguente permain.cpp
eSampleNativeClient.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); }
Servizi dei fornitori (Android)
Implementare un client ereditando CarWatchdogClientCallback
- Modifica il nuovo file come segue:
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 il client
- Chiama
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); }
Annulla la registrazione del client
- Chiama
CarWatchdogManager.unregisterClient()
al termine del servizio:private void finishClient() { CarWatchdogManager manager = (CarWatchdogManager) car.getCarManager( Car.CAR_WATCHDOG_SERVICE); manager.unregisterClient(mClientCallback); }
Rileva processi terminati dal watchdog dell'auto
Processi di dismissione/uccisione dei cani delle auto (HAL del fornitore, servizi nativi del fornitore,
servizi Android forniti dal fornitore) che sono registrati nel watchdog dell'auto quando
è bloccato e non risponde. Questo dumping viene rilevato controllando i logcat. L'auto
il watchdog genera un log carwatchdog killed process_name (pid:process_id)
quando un processo problematico viene scaricato
o terminato. Pertanto:
$ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"
Vengono acquisiti i log pertinenti. Ad esempio, se l'app KitchenSink (un watchdog dell'auto) client) viene bloccato, una riga come quella riportata di seguito viene scritta nel log:
05-01 09:50:19.683 578 5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)
Per determinare perché o dove l'app KitchenSink si è bloccata, utilizza il dump del processo
archiviati all'indirizzo /data/anr
proprio come faresti per i casi di ANR delle attività.
$ adb root $ adb shell grep -Hn "pid process_pid" /data/anr/*
Il seguente output di esempio è specifico per l'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 -----
Individua il file di dump (ad esempio, /data/anr/anr_2020-05-01-09-50-18-290
)
nell'esempio precedente) e iniziare l'analisi.