Мониторинг состояния системы

Watchdog отслеживает состояние служб поставщика и службы VHAL и завершает любые неработоспособные процессы. При завершении неработоспособного процесса Watchdog записывает его состояние в /data/anr как и в случае с другими дампами Application Not Responding (ANR). Это упрощает процесс отладки.

Мониторинг состояния сервисов поставщика

Сервисы сторонних поставщиков отслеживаются как на стороне нативных приложений, так и на стороне Java. Для мониторинга сервиса стороннего поставщика необходимо зарегистрировать процесс проверки работоспособности в Watchdog, указав предварительно заданный тайм-аут. Watchdog отслеживает работоспособность зарегистрированного процесса проверки работоспособности, отправляя ему пинг с интервалом, пропорциональным тайм-ауту, указанному при регистрации. Если процесс, получивший пинг, не отвечает в течение тайм-аута, он считается неработоспособным.

Мониторинг состояния здоровья местных жителей

Укажите файл makefile для Watchdog AIDL.

  1. Включите carwatchdog_aidl_interface-ndk_platform в shared_libs .

    Android.bp

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

Добавить политику SELinux

  1. Чтобы добавить политику SELinux, разрешите домену службы поставщика использовать binder (макрос binder_use ) и добавьте домен службы поставщика в домен клиента carwatchdog (макрос carwatchdog_client_domain ). См. код ниже для sample_client.te и 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

Реализуйте класс клиента, унаследовав его от класса BnCarWatchdogClient.

  1. В checkIfAlive выполните проверку работоспособности. Один из вариантов — отправить запрос обработчику цикла потока. Если работоспособность положительная, вызовите ICarWatchdog::tellClientAlive . См. код ниже для SampleNativeClient.h и 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);
    }

Запустите поток привязки и зарегистрируйте клиента.

Интерфейс демона Car Watchdog называется android.automotive.watchdog.ICarWatchdog/default .

  1. Найдите демон с указанным именем и вызовите метод ICarWatchdog::registerClient . См. код ниже для main.cpp и 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);
    }

Мониторинг состояния Java-сервисов

Реализуйте клиент, унаследовав класс CarWatchdogClientCallback.

  1. Отредактируйте новый файл следующим образом:
    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() {}
    };

Зарегистрируйте клиента

  1. Вызовите 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);
    }

Отменить регистрацию клиента

  1. Вызовите метод CarWatchdogManager.unregisterClient() после завершения работы службы:
    private void finishClient() {
        CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(
            Car.CAR_WATCHDOG_SERVICE);
        manager.unregisterClient(mClientCallback);
    }

мониторинг здоровья VHAL

В отличие от мониторинга состояния служб поставщика, Watchdog отслеживает состояние службы VHAL, подписываясь на свойство VHAL_HEARTBEAT . Watchdog ожидает, что значение этого свойства будет обновляться каждые N секунд. Если в течение этого времени пульс не обновляется, Watchdog завершает работу службы VHAL.

Примечание: Сторожевой таймер отслеживает состояние службы VHAL только в том случае, если свойство транспортного средства VHAL_HEARTBEAT поддерживается службой VHAL.

Внутренняя реализация VHAL может различаться в зависимости от производителя. Используйте следующие примеры кода в качестве参考.

  1. Зарегистрируйте свойство транспортного средства VHAL_HEARTBEAT .

    При запуске службы VHAL зарегистрируйте свойство транспортного средства VHAL_HEARTBEAT . В приведенном ниже примере используется unordered_map , сопоставляющий идентификатор свойства с конфигурацией, для хранения всех поддерживаемых конфигураций. Конфигурация для VHAL_HEARTBEAT добавляется в карту, так что при запросе VHAL_HEARTBEAT возвращается соответствующая конфигурация.

    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. Обновите свойство транспортного средства VHAL_HEARTBEAT .

    В зависимости от частоты проверки работоспособности VHAL (подробнее см. в разделе «Определение частоты проверки работоспособности VHAL» ), обновляйте свойство транспортного средства VHAL_HEARTBEAT каждые N секунд. Один из способов сделать это — использовать RecurrentTimer для вызова действия, которое проверяет работоспособность VHAL и обновляет свойство транспортного средства VHAL_HEARTBEAT в течение заданного таймаута.

    Ниже представлен пример реализации с использованием 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. ( Необязательно ) Укажите частоту проверки состояния VHAL.

    Свойство ` ro.carwatchdog.vhal_healthcheck.interval доступное только для чтения, определяет частоту проверки работоспособности VHAL. Частота проверки работоспособности по умолчанию (если это свойство не определено) составляет три секунды. Если трех секунд недостаточно для обновления свойства автомобиля VHAL_HEARTBEAT службой VHAL, определите частоту проверки работоспособности VHAL в зависимости от скорости отклика службы.

Отладка неисправных процессов завершена системой контроля.

Watchdog выводит состояние процесса и завершает неработоспособные процессы. При завершении неработоспособного процесса Watchdog записывает в logcat текст carwatchdog terminated <process name> (pid:<process id>) . Эта строка лога содержит информацию о завершенном процессе, такую ​​как имя процесса и идентификатор процесса.

  1. Поиск указанного текста в logcat можно выполнить следующим образом:
    $ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"

    Например, когда приложение KitchenSink является зарегистрированным клиентом Watchdog и перестает отвечать на запросы Watchdog, Watchdog записывает в лог строку, подобную приведенной ниже, при завершении зарегистрированного процесса KitchenSink.

    05-01 09:50:19.683   578  5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)
  2. Для определения первопричины зависания используйте дамп процесса, хранящийся в /data/anr так же, как и в случаях ANR активности. Чтобы получить файл дампа для завершившегося процесса, используйте следующие команды.
    $ adb root
    $ adb shell grep -Hn "pid process_pid" /data/anr/*

    Приведенный ниже пример выходных данных относится именно к приложению 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 -----

    Файл дампа завершенного процесса KitchenSink находится по адресу /data/anr/anr_2020-05-01-09-50-18-290 . Начните анализ, используя файл дампа ANR завершенного процесса.