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 "carwatchdog_testclient"
18 
19 #include "WatchdogClient.h"
20 
21 #include <android-base/chrono_utils.h>
22 #include <android-base/file.h>
23 #include <android/binder_manager.h>
24 
25 #include <unordered_map>
26 
27 namespace aidl {
28 namespace android {
29 namespace automotive {
30 namespace watchdog {
31 
32 using ::android::Looper;
33 using ::android::Message;
34 using ::android::Mutex;
35 using ::android::sp;
36 
37 namespace {
38 
39 enum { WHAT_CHECK_ALIVE = 1, WHAT_BECOME_INACTIVE = 2, WHAT_TERMINATE = 3 };
40 
41 const std::unordered_map<std::string, TimeoutLength> kTimeoutMap =
42         {{"critical", TimeoutLength::TIMEOUT_CRITICAL},
43          {"moderate", TimeoutLength::TIMEOUT_MODERATE},
44          {"normal", TimeoutLength::TIMEOUT_NORMAL}};
45 
46 constexpr std::chrono::seconds kGetServiceTimeout = 5s;
47 constexpr std::chrono::milliseconds kGetServiceSleepInterval = 100ms;
48 
49 }  // namespace
50 
WatchdogClient(const sp<Looper> & handlerLooper)51 WatchdogClient::WatchdogClient(const sp<Looper>& handlerLooper) : mHandlerLooper(handlerLooper) {
52     mMessageHandler = new MessageHandlerImpl(this);
53 }
54 
checkIfAlive(int32_t sessionId,TimeoutLength timeout)55 ndk::ScopedAStatus WatchdogClient::checkIfAlive(int32_t sessionId, TimeoutLength timeout) {
56     if (mVerbose) {
57         ALOGI("Pinged by car watchdog daemon: session id = %d", sessionId);
58     }
59     Mutex::Autolock lock(mMutex);
60     mHandlerLooper->removeMessages(mMessageHandler, WHAT_CHECK_ALIVE);
61     mSession = HealthCheckSession(sessionId, timeout);
62     mHandlerLooper->sendMessage(mMessageHandler, Message(WHAT_CHECK_ALIVE));
63     return ndk::ScopedAStatus::ok();
64 }
65 
prepareProcessTermination()66 ndk::ScopedAStatus WatchdogClient::prepareProcessTermination() {
67     ALOGI("This process is being terminated by car watchdog");
68     return ndk::ScopedAStatus::ok();
69 }
70 
initialize(const CommandParam & param)71 bool WatchdogClient::initialize(const CommandParam& param) {
72     const auto startTime = std::chrono::steady_clock::now();
73     ndk::SpAIBinder binder;
74     while (std::chrono::steady_clock::now() - startTime < kGetServiceTimeout) {
75         binder = ndk::SpAIBinder(
76                 AServiceManager_checkService("android.automotive.watchdog.ICarWatchdog/default"));
77         if (binder.get() != nullptr) {
78             break;
79         }
80         // usleep takes microseconds as argument.
81         usleep(std::chrono::microseconds(kGetServiceSleepInterval).count());
82     }
83     if (binder.get() == nullptr) {
84         ALOGE("Getting carwatchdog daemon failed");
85         return false;
86     }
87     std::shared_ptr<ICarWatchdog> server = ICarWatchdog::fromBinder(binder);
88     if (server == nullptr) {
89         ALOGE("Failed to connect to carwatchdog daemon");
90         return false;
91     }
92     {
93         Mutex::Autolock lock(mMutex);
94         mWatchdogServer = server;
95         mIsClientActive = true;
96     }
97     mForcedKill = param.forcedKill;
98     mVerbose = param.verbose;
99     registerClient(param.timeout);
100 
101     if (param.inactiveAfterInSec >= 0) {
102         mHandlerLooper->sendMessageDelayed(seconds_to_nanoseconds(param.inactiveAfterInSec),
103                                            mMessageHandler, Message(WHAT_BECOME_INACTIVE));
104     }
105     if (param.terminateAfterInSec >= 0) {
106         mHandlerLooper->sendMessageDelayed(seconds_to_nanoseconds(param.terminateAfterInSec),
107                                            mMessageHandler, Message(WHAT_TERMINATE));
108     }
109     return true;
110 }
111 
finalize()112 void WatchdogClient::finalize() {
113     {
114         Mutex::Autolock lock(mMutex);
115         if (!mWatchdogServer) {
116             return;
117         }
118     }
119     unregisterClient();
120 }
121 
respondToWatchdog()122 void WatchdogClient::respondToWatchdog() {
123     int sessionId;
124     std::shared_ptr<ICarWatchdog> watchdogServer;
125     std::shared_ptr<ICarWatchdogClient> testClient;
126     {
127         Mutex::Autolock lock(mMutex);
128         if (!mIsClientActive || mTestClient == nullptr || mWatchdogServer == nullptr) {
129             return;
130         }
131         watchdogServer = mWatchdogServer;
132         testClient = mTestClient;
133         sessionId = mSession.id;
134     }
135     ndk::ScopedAStatus status = watchdogServer->tellClientAlive(testClient, sessionId);
136     if (!status.isOk()) {
137         ALOGE("Failed to call binder interface: %d", status.getStatus());
138         return;
139     }
140     if (mVerbose) {
141         ALOGI("Sent response to car watchdog daemon: session id = %d", sessionId);
142     }
143 }
144 
becomeInactive()145 void WatchdogClient::becomeInactive() {
146     Mutex::Autolock lock(mMutex);
147     mIsClientActive = false;
148     if (mVerbose) {
149         ALOGI("Became inactive");
150     }
151 }
152 
terminateProcess()153 void WatchdogClient::terminateProcess() {
154     if (!mForcedKill) {
155         unregisterClient();
156     }
157     raise(SIGKILL);
158 }
159 
registerClient(const std::string & timeout)160 void WatchdogClient::registerClient(const std::string& timeout) {
161     ndk::SpAIBinder binder = this->asBinder();
162     if (binder.get() == nullptr) {
163         ALOGW("Failed to get car watchdog client binder object");
164         return;
165     }
166     std::shared_ptr<ICarWatchdogClient> client = ICarWatchdogClient::fromBinder(binder);
167     if (client == nullptr) {
168         ALOGW("Failed to get ICarWatchdogClient from binder");
169         return;
170     }
171     std::shared_ptr<ICarWatchdog> watchdogServer;
172     {
173         Mutex::Autolock lock(mMutex);
174         if (mWatchdogServer == nullptr) {
175             return;
176         }
177         watchdogServer = mWatchdogServer;
178         mTestClient = client;
179     }
180     watchdogServer->registerClient(client, kTimeoutMap.at(timeout));
181     ALOGI("Successfully registered the client to car watchdog server");
182 }
183 
unregisterClient()184 void WatchdogClient::unregisterClient() {
185     std::shared_ptr<ICarWatchdog> watchdogServer;
186     std::shared_ptr<ICarWatchdogClient> testClient;
187     {
188         Mutex::Autolock lock(mMutex);
189         if (mWatchdogServer == nullptr || mTestClient == nullptr) {
190             return;
191         }
192         watchdogServer = mWatchdogServer;
193         testClient = mTestClient;
194         mTestClient = nullptr;
195     }
196     watchdogServer->unregisterClient(testClient);
197     ALOGI("Successfully unregistered the client from car watchdog server");
198 }
199 
MessageHandlerImpl(WatchdogClient * client)200 WatchdogClient::MessageHandlerImpl::MessageHandlerImpl(WatchdogClient* client) : mClient(client) {}
201 
handleMessage(const Message & message)202 void WatchdogClient::MessageHandlerImpl::handleMessage(const Message& message) {
203     switch (message.what) {
204         case WHAT_CHECK_ALIVE:
205             mClient->respondToWatchdog();
206             break;
207         case WHAT_BECOME_INACTIVE:
208             mClient->becomeInactive();
209             break;
210         case WHAT_TERMINATE:
211             mClient->terminateProcess();
212             break;
213         default:
214             ALOGW("Unknown message: %d", message.what);
215     }
216 }
217 
218 }  // namespace watchdog
219 }  // namespace automotive
220 }  // namespace android
221 }  // namespace aidl
222