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