Theo dõi tình trạng hệ thống

Cơ quan giám sát giám sát tình trạng dịch vụ của nhà cung cấp và dịch vụ VHAL, đồng thời chấm dứt mọi quy trình không lành mạnh. Khi một quy trình không lành mạnh bị chấm dứt, Cơ quan giám sát sẽ chuyển trạng thái quy trình sang /data/anr giống như các kết xuất Ứng dụng không phản hồi (ANR) khác. Làm như vậy sẽ tạo điều kiện thuận lợi cho quá trình gỡ lỗi.

Theo dõi tình trạng dịch vụ của nhà cung cấp

Các dịch vụ của nhà cung cấp được giám sát ở cả phía gốc và phía Java. Để giám sát dịch vụ của Nhà cung cấp, dịch vụ đó phải đăng ký quy trình kiểm tra tình trạng với Cơ quan giám sát bằng cách chỉ định thời gian chờ được xác định trước. Cơ quan giám sát giám sát tình trạng của quy trình kiểm tra sức khỏe đã đăng ký bằng cách ping nó trong khoảng thời gian tương ứng với thời gian chờ được chỉ định trong quá trình đăng ký. Khi một quy trình được ping không phản hồi trong thời gian chờ, quy trình đó được coi là không lành mạnh.

Theo dõi sức khỏe dịch vụ bản địa

Chỉ định tệp makefile Watchdog AIDL

  1. Bao gồm carwatchdog_aidl_interface-ndk_platform trong shared_libs .

    Android.bp

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

Thêm chính sách SELinux

  1. Để thêm chính sách SELinux, hãy cho phép miền dịch vụ của nhà cung cấp sử dụng chất kết dính ( macro binder_use ) và thêm miền dịch vụ của nhà cung cấp vào miền máy khách carwatchdog ( macro carwatchdog_client_domain ). Xem mã bên dưới để biết sample_client.tefile_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
    

Triển khai lớp khách hàng bằng cách kế thừa BnCarWatchdogClient

  1. Trong checkIfAlive , thực hiện kiểm tra tình trạng. Một tùy chọn là đăng lên trình xử lý vòng lặp luồng. Nếu khỏe mạnh, hãy gọi ICarWatchdog::tellClientAlive . Xem mã bên dưới để biết SampleNativeClient.hSampleNativeClient.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);
    }
    

Bắt đầu một chuỗi liên kết và đăng ký ứng dụng khách

Tên giao diện daemon cơ quan giám sát ô tô là android.automotive.watchdog.ICarWatchdog/default .

  1. Tìm kiếm daemon có tên và gọi ICarWatchdog::registerClient . Xem mã bên dưới để biết main.cppSampleNativeClient.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);
    }
    

Giám sát tình trạng dịch vụ Java

Triển khai ứng dụng khách bằng cách kế thừa CarWatchdogClientCallback

  1. Chỉnh sửa tệp mới như sau:
    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() {}
    };
    

Đăng ký khách hàng

  1. Gọi 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);
    }
    

Hủy đăng ký khách hàng

  1. Gọi CarWatchdogManager.unregisterClient() khi dịch vụ kết thúc:
    private void finishClient() {
        CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(
            Car.CAR_WATCHDOG_SERVICE);
        manager.unregisterClient(mClientCallback);
    }
    

Theo dõi sức khỏe VHL

Không giống như giám sát tình trạng dịch vụ của nhà cung cấp, Watchdog giám sát tình trạng dịch vụ VHAL bằng cách đăng ký thuộc tính phương tiện VHAL_HEARTBEAT . Cơ quan giám sát hy vọng giá trị của thuộc tính này sẽ được cập nhật cứ sau N giây. Khi nhịp tim không được cập nhật trong thời gian chờ này, Watchdog sẽ chấm dứt dịch vụ VHAL.

Lưu ý: Cơ quan giám sát chỉ giám sát tình trạng dịch vụ VHAL khi thuộc tính xe VHAL_HEARTBEAT được dịch vụ VHAL hỗ trợ.

Việc triển khai nội bộ VHAL có thể khác nhau tùy theo nhà cung cấp. Sử dụng các mẫu mã sau đây làm tài liệu tham khảo.

  1. Đăng ký thuộc tính xe VHAL_HEARTBEAT .

    Khi bắt đầu dịch vụ VHAL, hãy đăng ký thuộc tính phương tiện VHAL_HEARTBEAT . Trong ví dụ bên dưới, unordered_map , ánh xạ ID thuộc tính tới cấu hình được sử dụng để chứa tất cả các cấu hình được hỗ trợ. Cấu hình cho VHAL_HEARTBEAT được thêm vào bản đồ để khi truy vấn VHAL_HEARTBEAT , cấu hình tương ứng sẽ được trả về.

    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. Cập nhật thuộc tính xe VHAL_HEARTBEAT .

    Dựa trên tần suất kiểm tra tình trạng VHAL (được giải thích trong Xác định tần suất kiểm tra tình trạng VHAL" ), hãy cập nhật thuộc tính xe VHAL_HEARTBEAT N giây một lần. Một cách để thực hiện việc này là sử dụng RecurrentTimer để gọi hành động kiểm tra tình trạng VHAL và cập nhật thuộc tính xe VHAL_HEARTBEAT trong thời gian chờ.

    Dưới đây là cách triển khai mẫu bằng cách sử dụng 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. ( Tùy chọn ) Xác định tần suất kiểm tra sức khỏe VHAL.

    Thuộc tính sản phẩm chỉ đọc ro.carwatchdog.vhal_healthcheck.interval của Watchdog xác định tần suất kiểm tra tình trạng VHAL. Tần suất kiểm tra tình trạng mặc định (khi thuộc tính này không được xác định) là ba giây. Nếu ba giây không đủ để dịch vụ VHAL cập nhật thuộc tính xe VHAL_HEARTBEAT , hãy xác định tần suất kiểm tra tình trạng VHAL tùy thuộc vào khả năng phản hồi của dịch vụ.

Gỡ lỗi các quy trình không lành mạnh do Watchdog chấm dứt

Cơ quan giám sát loại bỏ trạng thái quy trình và chấm dứt các quy trình không lành mạnh. Khi chấm dứt một quy trình không lành mạnh, Watchdog sẽ ghi lại văn bản carwatchdog terminated <process name> (pid:<process id>) vào logcat. Dòng nhật ký này cung cấp thông tin về quy trình đã kết thúc như tên quy trình và ID quy trình.

  1. Logcat có thể được tìm kiếm văn bản nói trên bằng cách chạy:
    $ adb logcat -s CarServiceHelper | fgrep "carwatchdog killed"
    

    Ví dụ: khi ứng dụng KitchenSink là ứng dụng khách Watchdog đã đăng ký và không phản hồi với các ping của Watchdog, Watchdog sẽ ghi lại một dòng như dòng bên dưới khi chấm dứt quy trình KitchenSink đã đăng ký.

    05-01 09:50:19.683   578  5777 W CarServiceHelper: carwatchdog killed com.google.android.car.kitchensink (pid: 5574)
    
  2. Để xác định nguyên nhân gốc rễ của tình trạng không phản hồi, hãy sử dụng kết xuất quy trình được lưu trữ tại /data/anr giống như cách bạn sử dụng cho các trường hợp ANR hoạt động. Để truy xuất tệp kết xuất cho quá trình đã kết thúc, hãy sử dụng các lệnh bên dưới.
    $ adb root
    $ adb shell grep -Hn "pid process_pid" /data/anr/*
    

    Đầu ra mẫu sau đây dành riêng cho ứng dụng 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 -----
    

    Tệp kết xuất cho quy trình KitchenSink đã chấm dứt được đặt tại /data/anr/anr_2020-05-01-09-50-18-290 . Bắt đầu phân tích của bạn bằng cách sử dụng tệp kết xuất ANR của quy trình đã chấm dứt.