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