1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "automotive.vehicle@2.0-watchdog"
18 
19 #include <common/include/vhal_v2_0/WatchdogClient.h>
20 
21 #include <android/binder_manager.h>
22 #include <android/hardware/automotive/vehicle/2.0/types.h>
23 
24 using aidl::android::automotive::watchdog::ICarWatchdog;
25 using aidl::android::automotive::watchdog::TimeoutLength;
26 
27 namespace {
28 
29 enum { WHAT_CHECK_ALIVE = 1 };
30 
31 }  // namespace
32 
33 namespace android {
34 namespace hardware {
35 namespace automotive {
36 namespace vehicle {
37 namespace V2_0 {
38 
WatchdogClient(const sp<Looper> & handlerLooper,VehicleHalManager * vhalManager)39 WatchdogClient::WatchdogClient(const sp<Looper>& handlerLooper, VehicleHalManager* vhalManager)
40     : mHandlerLooper(handlerLooper), mVhalManager(vhalManager), mCurrentSessionId(-1) {
41     mMessageHandler = new MessageHandlerImpl(this);
42 }
43 
checkIfAlive(int32_t sessionId,TimeoutLength)44 ndk::ScopedAStatus WatchdogClient::checkIfAlive(int32_t sessionId, TimeoutLength /*timeout*/) {
45     mHandlerLooper->removeMessages(mMessageHandler, WHAT_CHECK_ALIVE);
46     {
47         Mutex::Autolock lock(mMutex);
48         mCurrentSessionId = sessionId;
49     }
50     mHandlerLooper->sendMessage(mMessageHandler, Message(WHAT_CHECK_ALIVE));
51     return ndk::ScopedAStatus::ok();
52 }
53 
prepareProcessTermination()54 ndk::ScopedAStatus WatchdogClient::prepareProcessTermination() {
55     return ndk::ScopedAStatus::ok();
56 }
57 
initialize()58 bool WatchdogClient::initialize() {
59     ndk::SpAIBinder binder(
60             AServiceManager_getService("android.automotive.watchdog.ICarWatchdog/default"));
61     if (binder.get() == nullptr) {
62         ALOGE("Failed to get carwatchdog daemon");
63         return false;
64     }
65     std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
66     if (server == nullptr) {
67         ALOGE("Failed to connect to carwatchdog daemon");
68         return false;
69     }
70     mWatchdogServer = server;
71 
72     binder = this->asBinder();
73     if (binder.get() == nullptr) {
74         ALOGE("Failed to get car watchdog client binder object");
75         return false;
76     }
77     std::shared_ptr<ICarWatchdogClient> client = ICarWatchdogClient::fromBinder(binder);
78     if (client == nullptr) {
79         ALOGE("Failed to get ICarWatchdogClient from binder");
80         return false;
81     }
82     mTestClient = client;
83     mWatchdogServer->registerClient(client, TimeoutLength::TIMEOUT_NORMAL);
84     ALOGI("Successfully registered the client to car watchdog server");
85     return true;
86 }
87 
respondToWatchdog()88 void WatchdogClient::respondToWatchdog() {
89     if (mWatchdogServer == nullptr) {
90         ALOGW("Cannot respond to car watchdog daemon: car watchdog daemon is not connected");
91         return;
92     }
93     int sessionId;
94     {
95         Mutex::Autolock lock(mMutex);
96         sessionId = mCurrentSessionId;
97     }
98     if (isClientHealthy()) {
99         ndk::ScopedAStatus status = mWatchdogServer->tellClientAlive(mTestClient, sessionId);
100         if (!status.isOk()) {
101             ALOGE("Failed to call tellClientAlive(session id = %d): %d", sessionId,
102                   status.getStatus());
103             return;
104         }
105     }
106 }
107 
isClientHealthy() const108 bool WatchdogClient::isClientHealthy() const {
109     // We consider that default vehicle HAL is healthy if we can get PERF_VEHICLE_SPEED value.
110     StatusCode status = StatusCode::TRY_AGAIN;
111     VehiclePropValue propValue = {.prop = (int32_t)VehicleProperty::PERF_VEHICLE_SPEED};
112     while (status == StatusCode::TRY_AGAIN) {
113         mVhalManager->get(propValue,
114                           [&propValue, &status](StatusCode s, const VehiclePropValue& v) {
115                               status = s;
116                               if (s == StatusCode::OK) {
117                                   propValue = v;
118                               }
119                           });
120     }
121     return status == StatusCode::OK;
122 }
123 
MessageHandlerImpl(WatchdogClient * client)124 WatchdogClient::MessageHandlerImpl::MessageHandlerImpl(WatchdogClient* client) : mClient(client) {}
125 
handleMessage(const Message & message)126 void WatchdogClient::MessageHandlerImpl::handleMessage(const Message& message) {
127     switch (message.what) {
128         case WHAT_CHECK_ALIVE:
129             mClient->respondToWatchdog();
130             break;
131         default:
132             ALOGW("Unknown message: %d", message.what);
133     }
134 }
135 
136 }  // namespace V2_0
137 }  // namespace vehicle
138 }  // namespace automotive
139 }  // namespace hardware
140 }  // namespace android
141