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