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 "carwatchdogd"
18 #define DEBUG false // STOPSHIP if true.
19
20 #include "WatchdogProcessService.h"
21
22 #include <android-base/chrono_utils.h>
23 #include <android-base/file.h>
24 #include <android-base/properties.h>
25 #include <android-base/stringprintf.h>
26 #include <binder/IPCThreadState.h>
27
28 namespace android {
29 namespace automotive {
30 namespace watchdog {
31
32 using std::literals::chrono_literals::operator""s;
33 using android::base::Error;
34 using android::base::GetProperty;
35 using android::base::Result;
36 using android::base::StringAppendF;
37 using android::base::StringPrintf;
38 using android::base::WriteStringToFd;
39 using android::binder::Status;
40
41 namespace {
42
43 const std::vector<TimeoutLength> kTimeouts = {TimeoutLength::TIMEOUT_CRITICAL,
44 TimeoutLength::TIMEOUT_MODERATE,
45 TimeoutLength::TIMEOUT_NORMAL};
46
timeoutToDurationNs(const TimeoutLength & timeout)47 std::chrono::nanoseconds timeoutToDurationNs(const TimeoutLength& timeout) {
48 switch (timeout) {
49 case TimeoutLength::TIMEOUT_CRITICAL:
50 return 3s; // 3s and no buffer time.
51 case TimeoutLength::TIMEOUT_MODERATE:
52 return 6s; // 5s + 1s as buffer time.
53 case TimeoutLength::TIMEOUT_NORMAL:
54 return 12s; // 10s + 2s as buffer time.
55 }
56 }
57
pidArrayToString(const std::vector<int32_t> & pids)58 std::string pidArrayToString(const std::vector<int32_t>& pids) {
59 size_t size = pids.size();
60 if (size == 0) {
61 return "";
62 }
63 std::string buffer;
64 StringAppendF(&buffer, "%d", pids[0]);
65 for (int i = 1; i < size; i++) {
66 int pid = pids[i];
67 StringAppendF(&buffer, ", %d", pid);
68 }
69 return buffer;
70 }
71
isSystemShuttingDown()72 bool isSystemShuttingDown() {
73 std::string sysPowerCtl;
74 std::istringstream tokenStream(GetProperty("sys.powerctl", ""));
75 std::getline(tokenStream, sysPowerCtl, ',');
76 return sysPowerCtl == "reboot" || sysPowerCtl == "shutdown";
77 }
78
79 } // namespace
80
WatchdogProcessService(const sp<Looper> & handlerLooper)81 WatchdogProcessService::WatchdogProcessService(const sp<Looper>& handlerLooper) :
82 mHandlerLooper(handlerLooper), mLastSessionId(0) {
83 mMessageHandler = new MessageHandlerImpl(this);
84 mWatchdogEnabled = true;
85 for (const auto& timeout : kTimeouts) {
86 mClients.insert(std::make_pair(timeout, std::vector<ClientInfo>()));
87 mPingedClients.insert(std::make_pair(timeout, PingedClientMap()));
88 }
89 }
90
registerClient(const sp<ICarWatchdogClient> & client,TimeoutLength timeout)91 Status WatchdogProcessService::registerClient(const sp<ICarWatchdogClient>& client,
92 TimeoutLength timeout) {
93 Mutex::Autolock lock(mMutex);
94 return registerClientLocked(client, timeout, ClientType::Regular);
95 }
96
unregisterClient(const sp<ICarWatchdogClient> & client)97 Status WatchdogProcessService::unregisterClient(const sp<ICarWatchdogClient>& client) {
98 Mutex::Autolock lock(mMutex);
99 sp<IBinder> binder = BnCarWatchdog::asBinder(client);
100 // kTimeouts is declared as global static constant to cover all kinds of timeout (CRITICAL,
101 // MODERATE, NORMAL).
102 return unregisterClientLocked(kTimeouts, binder, ClientType::Regular);
103 }
104
registerMediator(const sp<ICarWatchdogClient> & mediator)105 Status WatchdogProcessService::registerMediator(const sp<ICarWatchdogClient>& mediator) {
106 Mutex::Autolock lock(mMutex);
107 // Mediator's timeout is always TIMEOUT_CRITICAL.
108 return registerClientLocked(mediator, TimeoutLength::TIMEOUT_CRITICAL, ClientType::Mediator);
109 }
110
unregisterMediator(const sp<ICarWatchdogClient> & mediator)111 Status WatchdogProcessService::unregisterMediator(const sp<ICarWatchdogClient>& mediator) {
112 std::vector<TimeoutLength> timeouts = {TimeoutLength::TIMEOUT_CRITICAL};
113 sp<IBinder> binder = BnCarWatchdog::asBinder(mediator);
114 Mutex::Autolock lock(mMutex);
115 return unregisterClientLocked(timeouts, binder, ClientType::Mediator);
116 }
117
registerMonitor(const sp<ICarWatchdogMonitor> & monitor)118 Status WatchdogProcessService::registerMonitor(const sp<ICarWatchdogMonitor>& monitor) {
119 Mutex::Autolock lock(mMutex);
120 sp<IBinder> binder = BnCarWatchdog::asBinder(monitor);
121 if (mMonitor != nullptr && binder == BnCarWatchdog::asBinder(mMonitor)) {
122 return Status::ok();
123 }
124 status_t ret = binder->linkToDeath(this);
125 if (ret != OK) {
126 ALOGW("Cannot register the monitor. The monitor is dead.");
127 return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "The monitor is dead.");
128 }
129 mMonitor = monitor;
130 if (DEBUG) {
131 ALOGD("Car watchdog monitor is registered");
132 }
133 return Status::ok();
134 }
135
unregisterMonitor(const sp<ICarWatchdogMonitor> & monitor)136 Status WatchdogProcessService::unregisterMonitor(const sp<ICarWatchdogMonitor>& monitor) {
137 Mutex::Autolock lock(mMutex);
138 if (mMonitor != monitor) {
139 ALOGW("Cannot unregister the monitor. The monitor has not been registered.");
140 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
141 "The monitor has not been registered.");
142 }
143 sp<IBinder> binder = BnCarWatchdog::asBinder(monitor);
144 binder->unlinkToDeath(this);
145 mMonitor = nullptr;
146 if (DEBUG) {
147 ALOGD("Car watchdog monitor is unregistered");
148 }
149 return Status::ok();
150 }
151
tellClientAlive(const sp<ICarWatchdogClient> & client,int32_t sessionId)152 Status WatchdogProcessService::tellClientAlive(const sp<ICarWatchdogClient>& client,
153 int32_t sessionId) {
154 Mutex::Autolock lock(mMutex);
155 return tellClientAliveLocked(client, sessionId);
156 }
157
tellMediatorAlive(const sp<ICarWatchdogClient> & mediator,const std::vector<int32_t> & clientsNotResponding,int32_t sessionId)158 Status WatchdogProcessService::tellMediatorAlive(const sp<ICarWatchdogClient>& mediator,
159 const std::vector<int32_t>& clientsNotResponding,
160 int32_t sessionId) {
161 Status status;
162 {
163 Mutex::Autolock lock(mMutex);
164 if (DEBUG) {
165 std::string buffer;
166 int size = clientsNotResponding.size();
167 if (size != 0) {
168 StringAppendF(&buffer, "%d", clientsNotResponding[0]);
169 for (int i = 1; i < clientsNotResponding.size(); i++) {
170 StringAppendF(&buffer, ", %d", clientsNotResponding[i]);
171 }
172 ALOGD("Mediator(session: %d) responded with non-responding clients: %s", sessionId,
173 buffer.c_str());
174 }
175 }
176 status = tellClientAliveLocked(mediator, sessionId);
177 }
178 if (status.isOk()) {
179 dumpAndKillAllProcesses(clientsNotResponding);
180 }
181 return status;
182 }
183
tellDumpFinished(const sp<ICarWatchdogMonitor> & monitor,int32_t pid)184 Status WatchdogProcessService::tellDumpFinished(const sp<ICarWatchdogMonitor>& monitor,
185 int32_t pid) {
186 Mutex::Autolock lock(mMutex);
187 if (mMonitor == nullptr || monitor == nullptr ||
188 BnCarWatchdog::asBinder(monitor) != BnCarWatchdog::asBinder(mMonitor)) {
189 return Status::
190 fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
191 "The monitor is not registered or an invalid monitor is given");
192 }
193 ALOGI("Process(pid: %d) has been dumped and killed", pid);
194 return Status::ok();
195 }
196
notifyPowerCycleChange(PowerCycle cycle)197 Status WatchdogProcessService::notifyPowerCycleChange(PowerCycle cycle) {
198 std::string buffer;
199 Mutex::Autolock lock(mMutex);
200 bool oldStatus = mWatchdogEnabled;
201 switch (cycle) {
202 case PowerCycle::POWER_CYCLE_SHUTDOWN:
203 mWatchdogEnabled = false;
204 buffer = "SHUTDOWN power cycle";
205 break;
206 case PowerCycle::POWER_CYCLE_SUSPEND:
207 mWatchdogEnabled = false;
208 buffer = "SUSPEND power cycle";
209 break;
210 case PowerCycle::POWER_CYCLE_RESUME:
211 mWatchdogEnabled = true;
212 for (const auto& timeout : kTimeouts) {
213 startHealthCheckingLocked(timeout);
214 }
215 buffer = "RESUME power cycle";
216 break;
217 default:
218 ALOGW("Unsupported power cycle: %d", cycle);
219 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
220 "Unsupported power cycle");
221 }
222 ALOGI("Received %s", buffer.c_str());
223 if (oldStatus != mWatchdogEnabled) {
224 ALOGI("Car watchdog is %s", mWatchdogEnabled ? "enabled" : "disabled");
225 }
226 return Status::ok();
227 }
228
notifyUserStateChange(userid_t userId,UserState state)229 Status WatchdogProcessService::notifyUserStateChange(userid_t userId, UserState state) {
230 std::string buffer;
231 Mutex::Autolock lock(mMutex);
232 switch (state) {
233 case UserState::USER_STATE_STARTED:
234 mStoppedUserId.erase(userId);
235 buffer = StringPrintf("user(%d) is started", userId);
236 break;
237 case UserState::USER_STATE_STOPPED:
238 mStoppedUserId.insert(userId);
239 buffer = StringPrintf("user(%d) is stopped", userId);
240 break;
241 default:
242 ALOGW("Unsupported user state: %d", state);
243 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Unsupported user state");
244 }
245 ALOGI("Received user state change: %s", buffer.c_str());
246 return Status::ok();
247 }
248
dump(int fd,const Vector<String16> &)249 Result<void> WatchdogProcessService::dump(int fd, const Vector<String16>& /*args*/) {
250 Mutex::Autolock lock(mMutex);
251 const char* indent = " ";
252 const char* doubleIndent = " ";
253 std::string buffer;
254 WriteStringToFd("CAR WATCHDOG PROCESS SERVICE\n", fd);
255 WriteStringToFd(StringPrintf("%sWatchdog enabled: %s\n", indent,
256 mWatchdogEnabled ? "true" : "false"),
257 fd);
258 WriteStringToFd(StringPrintf("%sRegistered clients\n", indent), fd);
259 int count = 1;
260 for (const auto& timeout : kTimeouts) {
261 std::vector<ClientInfo>& clients = mClients[timeout];
262 for (auto it = clients.begin(); it != clients.end(); it++, count++) {
263 WriteStringToFd(StringPrintf("%sClient #%d: %s\n", doubleIndent, count,
264 it->toString().c_str()),
265 fd);
266 }
267 }
268 WriteStringToFd(StringPrintf("%sMonitor registered: %s\n", indent,
269 mMonitor == nullptr ? "false" : "true"),
270 fd);
271 WriteStringToFd(StringPrintf("%sisSystemShuttingDown: %s\n", indent,
272 isSystemShuttingDown() ? "true" : "false"),
273 fd);
274 buffer = "none";
275 bool first = true;
276 for (const auto& userId : mStoppedUserId) {
277 if (first) {
278 buffer = StringPrintf("%d", userId);
279 first = false;
280 } else {
281 StringAppendF(&buffer, ", %d", userId);
282 }
283 }
284 WriteStringToFd(StringPrintf("%sStopped users: %s\n", indent, buffer.c_str()), fd);
285 return {};
286 }
287
doHealthCheck(int what)288 void WatchdogProcessService::doHealthCheck(int what) {
289 mHandlerLooper->removeMessages(mMessageHandler, what);
290 if (!isWatchdogEnabled()) {
291 return;
292 }
293 const TimeoutLength timeout = static_cast<TimeoutLength>(what);
294 dumpAndKillClientsIfNotResponding(timeout);
295
296 /* Generates a temporary/local vector containing clients.
297 * Using a local copy may send unnecessary ping messages to clients after they are unregistered.
298 * Clients should be able to handle them.
299 */
300 std::vector<ClientInfo> clientsToCheck;
301 PingedClientMap& pingedClients = mPingedClients[timeout];
302 {
303 Mutex::Autolock lock(mMutex);
304 pingedClients.clear();
305 clientsToCheck = mClients[timeout];
306 for (auto& clientInfo : clientsToCheck) {
307 if (mStoppedUserId.count(clientInfo.userId) > 0) {
308 continue;
309 }
310 int sessionId = getNewSessionId();
311 clientInfo.sessionId = sessionId;
312 pingedClients.insert(std::make_pair(sessionId, clientInfo));
313 }
314 }
315
316 for (const auto& clientInfo : clientsToCheck) {
317 Status status = clientInfo.client->checkIfAlive(clientInfo.sessionId, timeout);
318 if (!status.isOk()) {
319 ALOGW("Sending a ping message to client(pid: %d) failed: %s", clientInfo.pid,
320 status.exceptionMessage().c_str());
321 {
322 Mutex::Autolock lock(mMutex);
323 pingedClients.erase(clientInfo.sessionId);
324 }
325 }
326 }
327 // Though the size of pingedClients is a more specific measure, clientsToCheck is used as a
328 // conservative approach.
329 if (clientsToCheck.size() > 0) {
330 auto durationNs = timeoutToDurationNs(timeout);
331 mHandlerLooper->sendMessageDelayed(durationNs.count(), mMessageHandler, Message(what));
332 }
333 }
334
terminate()335 void WatchdogProcessService::terminate() {
336 Mutex::Autolock lock(mMutex);
337 for (const auto& timeout : kTimeouts) {
338 std::vector<ClientInfo>& clients = mClients[timeout];
339 for (auto it = clients.begin(); it != clients.end();) {
340 sp<IBinder> binder = BnCarWatchdog::asBinder((*it).client);
341 binder->unlinkToDeath(this);
342 it = clients.erase(it);
343 }
344 }
345 }
346
binderDied(const wp<IBinder> & who)347 void WatchdogProcessService::binderDied(const wp<IBinder>& who) {
348 Mutex::Autolock lock(mMutex);
349 IBinder* binder = who.unsafe_get();
350 // Check if dead binder is monitor.
351 sp<IBinder> monitor = BnCarWatchdog::asBinder(mMonitor);
352 if (monitor == binder) {
353 mMonitor = nullptr;
354 ALOGW("The monitor has died.");
355 return;
356 }
357 findClientAndProcessLocked(kTimeouts, binder,
358 [&](std::vector<ClientInfo>& clients,
359 std::vector<ClientInfo>::const_iterator it) {
360 ALOGW("Client(pid: %d) died", it->pid);
361 clients.erase(it);
362 });
363 }
364
isRegisteredLocked(const sp<ICarWatchdogClient> & client)365 bool WatchdogProcessService::isRegisteredLocked(const sp<ICarWatchdogClient>& client) {
366 sp<IBinder> binder = BnCarWatchdog::asBinder(client);
367 return findClientAndProcessLocked(kTimeouts, binder, nullptr);
368 }
369
registerClientLocked(const sp<ICarWatchdogClient> & client,TimeoutLength timeout,ClientType clientType)370 Status WatchdogProcessService::registerClientLocked(const sp<ICarWatchdogClient>& client,
371 TimeoutLength timeout, ClientType clientType) {
372 const char* clientName = clientType == ClientType::Regular ? "client" : "mediator";
373 if (isRegisteredLocked(client)) {
374 ALOGW("Cannot register the %s: the %s is already registered.", clientName, clientName);
375 return Status::ok();
376 }
377 sp<IBinder> binder = BnCarWatchdog::asBinder(client);
378 status_t status = binder->linkToDeath(this);
379 if (status != OK) {
380 std::string errorStr = StringPrintf("The %s is dead", clientName);
381 const char* errorCause = errorStr.c_str();
382 ALOGW("Cannot register the %s: %s", clientName, errorCause);
383 return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, errorCause);
384 }
385 std::vector<ClientInfo>& clients = mClients[timeout];
386 pid_t callingPid = IPCThreadState::self()->getCallingPid();
387 uid_t callingUid = IPCThreadState::self()->getCallingUid();
388 clients.push_back(ClientInfo(client, callingPid, callingUid, clientType));
389
390 // If the client array becomes non-empty, start health checking.
391 if (clients.size() == 1) {
392 startHealthCheckingLocked(timeout);
393 }
394 if (DEBUG) {
395 ALOGD("Car watchdog %s(pid: %d, timeout: %d) is registered", clientName, callingPid,
396 timeout);
397 }
398 return Status::ok();
399 }
400
unregisterClientLocked(const std::vector<TimeoutLength> & timeouts,sp<IBinder> binder,ClientType clientType)401 Status WatchdogProcessService::unregisterClientLocked(const std::vector<TimeoutLength>& timeouts,
402 sp<IBinder> binder, ClientType clientType) {
403 const char* clientName = clientType == ClientType::Regular ? "client" : "mediator";
404 bool result = findClientAndProcessLocked(timeouts, binder,
405 [&](std::vector<ClientInfo>& clients,
406 std::vector<ClientInfo>::const_iterator it) {
407 binder->unlinkToDeath(this);
408 clients.erase(it);
409 });
410 if (!result) {
411 std::string errorStr = StringPrintf("The %s has not been registered", clientName);
412 const char* errorCause = errorStr.c_str();
413 ALOGW("Cannot unregister the %s: %s", clientName, errorCause);
414 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, errorCause);
415 }
416 if (DEBUG) {
417 ALOGD("Car watchdog %s is unregistered", clientName);
418 }
419 return Status::ok();
420 }
421
tellClientAliveLocked(const sp<ICarWatchdogClient> & client,int32_t sessionId)422 Status WatchdogProcessService::tellClientAliveLocked(const sp<ICarWatchdogClient>& client,
423 int32_t sessionId) {
424 const sp<IBinder> binder = BnCarWatchdog::asBinder(client);
425 for (const auto& timeout : kTimeouts) {
426 PingedClientMap& clients = mPingedClients[timeout];
427 PingedClientMap::const_iterator it = clients.find(sessionId);
428 if (it == clients.cend() || binder != BnCarWatchdog::asBinder(it->second.client)) {
429 continue;
430 }
431 clients.erase(it);
432 return Status::ok();
433 }
434 return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT,
435 "The client is not registered or the session ID is not found");
436 }
437
findClientAndProcessLocked(const std::vector<TimeoutLength> timeouts,const sp<IBinder> binder,const Processor & processor)438 bool WatchdogProcessService::findClientAndProcessLocked(const std::vector<TimeoutLength> timeouts,
439 const sp<IBinder> binder,
440 const Processor& processor) {
441 for (const auto& timeout : timeouts) {
442 std::vector<ClientInfo>& clients = mClients[timeout];
443 for (auto it = clients.begin(); it != clients.end(); it++) {
444 if (BnCarWatchdog::asBinder((*it).client) != binder) {
445 continue;
446 }
447 if (processor != nullptr) {
448 processor(clients, it);
449 }
450 return true;
451 }
452 }
453 return false;
454 }
455
startHealthCheckingLocked(TimeoutLength timeout)456 Result<void> WatchdogProcessService::startHealthCheckingLocked(TimeoutLength timeout) {
457 PingedClientMap& clients = mPingedClients[timeout];
458 clients.clear();
459 int what = static_cast<int>(timeout);
460 auto durationNs = timeoutToDurationNs(timeout);
461 mHandlerLooper->sendMessageDelayed(durationNs.count(), mMessageHandler, Message(what));
462 return {};
463 }
464
dumpAndKillClientsIfNotResponding(TimeoutLength timeout)465 Result<void> WatchdogProcessService::dumpAndKillClientsIfNotResponding(TimeoutLength timeout) {
466 std::vector<int32_t> processIds;
467 std::vector<sp<ICarWatchdogClient>> clientsToNotify;
468 {
469 Mutex::Autolock lock(mMutex);
470 PingedClientMap& clients = mPingedClients[timeout];
471 for (PingedClientMap::const_iterator it = clients.cbegin(); it != clients.cend(); it++) {
472 pid_t pid = -1;
473 userid_t userId = -1;
474 sp<ICarWatchdogClient> client = it->second.client;
475 sp<IBinder> binder = BnCarWatchdog::asBinder(client);
476 std::vector<TimeoutLength> timeouts = {timeout};
477 findClientAndProcessLocked(timeouts, binder,
478 [&](std::vector<ClientInfo>& clients,
479 std::vector<ClientInfo>::const_iterator it) {
480 pid = (*it).pid;
481 userId = (*it).userId;
482 clients.erase(it);
483 });
484 if (pid != -1 && mStoppedUserId.count(userId) == 0) {
485 clientsToNotify.push_back(client);
486 processIds.push_back(pid);
487 }
488 }
489 }
490 for (auto&& client : clientsToNotify) {
491 client->prepareProcessTermination();
492 }
493 return dumpAndKillAllProcesses(processIds);
494 }
495
dumpAndKillAllProcesses(const std::vector<int32_t> & processesNotResponding)496 Result<void> WatchdogProcessService::dumpAndKillAllProcesses(
497 const std::vector<int32_t>& processesNotResponding) {
498 size_t size = processesNotResponding.size();
499 if (size == 0) {
500 return {};
501 }
502 std::string pidString = pidArrayToString(processesNotResponding);
503 sp<ICarWatchdogMonitor> monitor;
504 {
505 Mutex::Autolock lock(mMutex);
506 if (mMonitor == nullptr) {
507 std::string errorMsg =
508 StringPrintf("Cannot dump and kill processes(pid = %s): Monitor is not set",
509 pidString.c_str());
510 ALOGW("%s", errorMsg.c_str());
511 return Error() << errorMsg;
512 }
513 monitor = mMonitor;
514 }
515 if (isSystemShuttingDown()) {
516 ALOGI("Skip dumping and killing processes(%s): The system is shutting down",
517 pidString.c_str());
518 return {};
519 }
520 monitor->onClientsNotResponding(processesNotResponding);
521 if (DEBUG) {
522 ALOGD("Dumping and killing processes is requested: %s", pidString.c_str());
523 }
524 return {};
525 }
526
getNewSessionId()527 int32_t WatchdogProcessService::getNewSessionId() {
528 // Make sure that session id is always positive number.
529 if (++mLastSessionId <= 0) {
530 mLastSessionId = 1;
531 }
532 return mLastSessionId;
533 }
534
isWatchdogEnabled()535 bool WatchdogProcessService::isWatchdogEnabled() {
536 Mutex::Autolock lock(mMutex);
537 return mWatchdogEnabled;
538 }
539
toString()540 std::string WatchdogProcessService::ClientInfo::toString() {
541 std::string buffer;
542 StringAppendF(&buffer, "pid = %d, userId = %d, type = %s", pid, userId,
543 type == Regular ? "Regular" : "Mediator");
544 return buffer;
545 }
546
MessageHandlerImpl(const sp<WatchdogProcessService> & service)547 WatchdogProcessService::MessageHandlerImpl::MessageHandlerImpl(
548 const sp<WatchdogProcessService>& service) :
549 mService(service) {}
550
handleMessage(const Message & message)551 void WatchdogProcessService::MessageHandlerImpl::handleMessage(const Message& message) {
552 switch (message.what) {
553 case static_cast<int>(TimeoutLength::TIMEOUT_CRITICAL):
554 case static_cast<int>(TimeoutLength::TIMEOUT_MODERATE):
555 case static_cast<int>(TimeoutLength::TIMEOUT_NORMAL):
556 mService->doHealthCheck(message.what);
557 break;
558 default:
559 ALOGW("Unknown message: %d", message.what);
560 }
561 }
562
563 } // namespace watchdog
564 } // namespace automotive
565 } // namespace android
566