Giám sát tình trạng hệ thống

Bộ phận giám sát giám sát tình trạng của các dịch vụ của nhà cung cấp và dịch vụ VHAL, và chấm dứt bất kỳ quá trình không lành mạnh nào. Khi một quy trình không lành mạnh bị chấm dứt, Bộ đếm giờ phòng vệ kết xuất trạng thái xử lý vào /data/anr giống như với ứng dụng khác không phản hồi Tệp kết xuất (ANR). Việc này sẽ giúp quá trình gỡ lỗi thuận tiện hơn.

Giám sát 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. Dành cho nhà cung cấp là dịch vụ được giám sát, thì dịch vụ đó phải đăng ký quy trình kiểm tra sức khoẻ với Bộ đếm giờ phòng vệ bằng cách chỉ định thời gian chờ được xác định trước. Bộ đếm giờ phòng vệ giám sát tình trạng của một quy trình kiểm tra sức khoẻ đã đăng ký bằng cách ping quy trình đó trong một khoảng thời gian liên quan đến thời gian chờ được chỉ định trong quá trình đăng ký. Khi có tín hiệu ping không phản hồi trong thời gian chờ thì quá trình này được coi là không lành mạnh.

Giám sát tình trạng của dịch vụ gốc

Chỉ định tệp makefile AIDL của bộ theo dõi

  1. Đưa carwatchdog_aidl_interface-ndk_platform vào 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 trình liên kết (macro binder_use) và thêm miền dịch vụ của nhà cung cấp vào Miền ứng dụng carwatchdog (macro carwatchdog_client_domain). Xem mã bên dưới cho 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 ứng dụng khách bằng cách kế thừa BnCarWatchdogClient

  1. Trong checkIfAlive, hãy kiểm tra tình trạng. Một lựa chọn là đăng lên trình xử lý vòng lặp luồng. Nếu tình trạng hoạt động tốt, hãy gọi ICarWatchdog::tellClientAlive. Xem mã bên dưới cho 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 luồng liên kết và đăng ký ứng dụng

Tên giao diện trình nền của bộ đếm giờ phòng vệ của ô tô là android.automotive.watchdog.ICarWatchdog/default.

  1. Tìm trình nền có tên và gọi ICarWatchdog::registerClient. Xem mã bên dưới cho 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 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ý ứng dụ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);
    }
    

Huỷ đăng ký ứng dụng

  1. Gọi CarWatchdogManager.unregisterClient() khi dịch vụ hoàn tất:
    private void finishClient() {
        CarWatchdogManager manager =
            (CarWatchdogManager) car.getCarManager(
            Car.CAR_WATCHDOG_SERVICE);
        manager.unregisterClient(mClientCallback);
    }
    

Theo dõi tình trạng của VHAL

Không giống như dịch vụ giám sát tình trạng của dịch vụ của nhà cung cấp, Watchdog giám sát dịch vụ VHAL sức khoẻ bằng cách đăng ký thuộc tính xe VHAL_HEARTBEAT. Bộ theo dõi dự kiến giá trị của thuộc tính này được cập nhật N giây một lần. Khi nhịp tim không được cập nhật trong thời gian chờ này, Bộ theo dõi sẽ chấm dứt VHAL .

Lưu ý: Bộ đếm giờ phòng vệ 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 VHAL nội bộ có thể khác nhau tuỳ theo nhà cung cấp. Hãy sử dụng các mã mẫu sau 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 xe của VHAL_HEARTBEAT. Trong ví dụ bên dưới, unordered_map liên kết mã tài sản với cấu hình là dùng để lưu giữ mọi cấu hình được hỗ trợ. Đã thêm cấu hình cho VHAL_HEARTBEAT vào ánh xạ để khi VHAL_HEARTBEAT được truy vấn, cấu hình tương ứng sẽ bị trả lại.

    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. Hãy 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 của VHAL (được giải thích trong Xác định tần suất kiểm tra tình trạng của VHAL"), cập nhật thuộc tính xe VHAL_HEARTBEAT một lần N giây một lần. Có một cách để thực hiện việc này là dùng RecurrentTimer để gọi hành động giúp kiểm tra tình trạng VHAL và cập nhật xe VHAL_HEARTBEAT trong thời gian chờ.

    Dưới đây là ví dụ về cách triển khai bằ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. (Không bắt buộc) Xác định tần suất kiểm tra tình trạng của VHAL.

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

Gỡ lỗi các quy trình hoạt động không tốt do Bộ theo dõi chấm dứt

Bộ đếm giờ phòng vệ sẽ kết xuất trạng thái quy trình và chấm dứt những 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 bị chấm dứt như tên quy trình và quy trình Mã nhận dạng.

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

    Ví dụ: khi ứng dụng KitchenSink là một ứng dụng Watchdog đã đăng ký và Không phản hồi với ping của Bộ đếm giờ, Bộ theo dõi ghi lại một dòng như dưới đây 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 việc không phản hồi, hãy sử dụng quy trình này tệp kết xuất được lưu trữ tại /data/anr giống như cách bạn sử dụng cho ANR hoạt động trường hợp. Để truy xuất tệp kết xuất cho quy trình đã kết thúc, hãy sử dụng các lệnh dưới đây.
    $ adb root
    $ adb shell grep -Hn "pid process_pid" /data/anr/*
    

    Kết quả 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 nằm ở /data/anr/anr_2020-05-01-09-50-18-290. Bắt đầu phân tích bằng tệp kết xuất ANR của quy trình đã chấm dứt.