Surveiller l'état du système

Watchdog surveille l'état des services des fournisseurs et du service VHAL. met fin à tout processus non opérationnel. Lorsqu'un processus non opérationnel s'arrête, le Watchdog vide l'état du processus sur /data/anr, comme pour les autres applications qui ne répondent pas (ANR). Cela facilite le processus de débogage.

Surveillance de l'état des services du fournisseur

Les services des fournisseurs sont surveillés à la fois côté natif et côté Java. Pour qu'un service du fournisseur soit surveillé, il doit enregistrer un processus de vérification de l'état auprès du Watchdog en spécifiant un délai avant expiration prédéfini. Watchdog surveille l'état d'un processus de vérification d'état enregistré en le pinguant à intervalles réguliers par rapport au délai avant expiration spécifié lors de l'enregistrement. Lorsqu'un processus pingé ne répond pas dans le délai avant expiration, il est considéré comme non opérationnel.

Surveillance de l'état des services natifs

Spécifier le fichier makefile AIDL Watchdog

  1. Inclure carwatchdog_aidl_interface-ndk_platform dans shared_libs.

    Android.bp

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

Ajouter une règle SELinux

  1. Pour ajouter une règle SELinux, autorisez le domaine du service du fournisseur à utiliser la liaison (macro binder_use), puis ajoutez le domaine du service fournisseur au Domaine du client carwatchdog (macro carwatchdog_client_domain). Consultez le code ci-dessous pour sample_client.te et file_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)

    file_contexts

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

Implémenter une classe client en héritant de BnCarWatchdogClient

  1. Dans checkIfAlive, effectuez une vérification de l'état. Une option consiste à publier sur le gestionnaire de boucle de thread. Si l'état est opérationnel, appelez ICarWatchdog::tellClientAlive. Consultez le code ci-dessous pour SampleNativeClient.h et 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);
    }

Démarrer un thread de liaison et enregistrer le client

Le nom de l'interface du daemon de surveillance de la voiture est android.automotive.watchdog.ICarWatchdog/default.

  1. Recherchez le daemon avec le nom et appelez ICarWatchdog::registerClient. Consultez le code ci-dessous pour main.cpp et SampleNativeClient.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);
    }

Surveillance de l'état du service Java

Implémenter un client en héritant de CarWatchdogClientCallback

  1. Modifiez le nouveau fichier comme suit :
    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() {}
    };

Enregistrer le client

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

Annuler l'enregistrement du client

  1. Appelez CarWatchdogManager.unregisterClient() lorsque le service est terminé :
    private void finishClient() {
        CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(
            Car.CAR_WATCHDOG_SERVICE);
        manager.unregisterClient(mClientCallback);
    }

Surveillance de l'état VHAL

Contrairement à la surveillance de l'état du service fournisseur, Watchdog surveille le service VHAL en vous abonnant à la propriété VHAL_HEARTBEAT du véhicule. Le chien de garde s'attend à ce que la valeur de cette propriété soit mise à jour toutes les N secondes. Lorsque la pulsation n'est pas mise à jour dans ce délai, Watchdog met fin à la VHAL Google Cloud.

Remarque:Watchdog surveille l'état du service VHAL uniquement lorsque La propriété de véhicule VHAL_HEARTBEAT est compatible avec le service VHAL.

L'implémentation interne de VHAL peut varier selon les fournisseurs. Utilisez les exemples de code suivants comme références.

  1. Enregistrez la propriété du véhicule VHAL_HEARTBEAT.

    Lorsque vous démarrez le service VHAL, enregistrez la propriété du véhicule VHAL_HEARTBEAT. Dans l'exemple ci-dessous, une unordered_map, qui mappe l'ID de propriété à la configuration est utilisé pour contenir toutes les configurations compatibles. La configuration de VHAL_HEARTBEAT est ajoutée à la carte afin que, lorsque VHAL_HEARTBEAT est interrogé, la configuration correspondante soit renvoyée.

    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. Mettez à jour la propriété du véhicule VHAL_HEARTBEAT.

    En fonction de la fréquence de vérification de l'état de VHAL (expliquée dans la section Définir la fréquence de vérification de l'état de VHAL), mettez à jour la propriété du véhicule VHAL_HEARTBEAT toutes les N secondes. Pour ce faire, vous pouvez utiliser RecurrentTimer pour appeler l'action qui vérifie l'état du VHAL et met à jour le véhicule VHAL_HEARTBEAT dans le délai imparti.

    Vous trouverez ci-dessous un exemple d'implémentation utilisant RecurrentTimer :

    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. (Facultatif) Définissez la fréquence des vérifications d'état VHAL.

    La propriété de produit en lecture seule ro.carwatchdog.vhal_healthcheck.interval du chien de garde définit la fréquence de vérification de l'état de VHAL. La fréquence de vérification de l'état par défaut (lorsque cette propriété n'est pas définie) est de trois secondes. Si trois secondes ne correspondent pas suffisant pour que le service VHAL mette à jour la propriété VHAL_HEARTBEAT du véhicule. définir la fréquence des vérifications d'état VHAL en fonction de la réactivité du service.

Déboguer les processus non opérationnels arrêtés par le Watchdog

Le chien de garde vide l'état du processus et met fin aux processus non opérationnels. Lors de l'arrêt un processus non opérationnel, Watchdog consigne le texte carwatchdog terminated <process name> (pid:<process id>) dans Logcat. Cette ligne de journal fournit des informations sur le processus terminé, telles que le nom et le processus ID.

  1. Vous pouvez rechercher le texte mentionné ci-dessus dans le Logcat en exécutant la commande suivante:
    $ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"

    Par exemple, lorsque l'application KitchenSink est un client Watchdog enregistré et ne répond pas aux pings Watchdog, celui-ci consigne une ligne comme celle-ci : lors de l'arrêt du processus KitchenSink.

    05-01 09:50:19.683   578  5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)
  2. Pour identifier la cause première de l'absence de réponse, utilisez le processus suivant : vide stocké dans /data/anr, comme vous l'utiliseriez pour une ANR d'activité cas d'utilisation. Pour récupérer le fichier de dump du processus arrêté, utilisez les commandes ci-dessous.
    $ adb root
    $ adb shell grep -Hn "pid process_pid" /data/anr/*

    L'exemple de résultat suivant est spécifique à l'application 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 -----

    Le fichier de vidage du processus KitchenSink arrêté se trouve à l'emplacement /data/anr/anr_2020-05-01-09-50-18-290. Commencez votre analyse en utilisant le fichier de dump ANR du processus arrêté.