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

Сторожевой таймер контролирует работоспособность служб поставщика и службы VHAL и завершает любой неработоспособный процесс. Когда неработоспособный процесс завершается, Watchdog сохраняет состояние процесса в /data/anr как и в случае с другими дампами приложений, не отвечающих (ANR). Это облегчит процесс отладки.

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

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

Мониторинг работоспособности встроенного сервиса

Укажите make-файл 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_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);
    }
    

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

Имя интерфейса демона автомобильного сторожевого таймера — 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.

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

Отладка неработоспособных процессов, прекращенных Watchdog

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

  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 завершенного процесса.