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
19 #include "WatchdogInternalHandler.h"
20
21 #include "UidProcStatsCollector.h"
22
23 #include <aidl/android/automotive/watchdog/internal/BootPhase.h>
24 #include <aidl/android/automotive/watchdog/internal/GarageMode.h>
25 #include <android-base/file.h>
26 #include <binder/IPCThreadState.h>
27 #include <private/android_filesystem_config.h>
28
29 #include <packages/services/Car/service/proto/android/car/watchdog/carwatchdog_daemon_dump.proto.h>
30
31 namespace android {
32 namespace automotive {
33 namespace watchdog {
34
35 using ::aidl::android::automotive::watchdog::internal::BootPhase;
36 using ::aidl::android::automotive::watchdog::internal::ComponentType;
37 using ::aidl::android::automotive::watchdog::internal::GarageMode;
38 using ::aidl::android::automotive::watchdog::internal::ICarWatchdogMonitor;
39 using ::aidl::android::automotive::watchdog::internal::ICarWatchdogServiceForSystem;
40 using ::aidl::android::automotive::watchdog::internal::PowerCycle;
41 using ::aidl::android::automotive::watchdog::internal::ProcessIdentifier;
42 using ::aidl::android::automotive::watchdog::internal::ResourceOveruseConfiguration;
43 using ::aidl::android::automotive::watchdog::internal::StateType;
44 using ::aidl::android::automotive::watchdog::internal::ThreadPolicyWithPriority;
45 using ::aidl::android::automotive::watchdog::internal::UserPackageIoUsageStats;
46 using ::aidl::android::automotive::watchdog::internal::UserState;
47 using ::android::sp;
48 using ::android::String16;
49 using ::android::base::EqualsIgnoreCase;
50 using ::android::base::Error;
51 using ::android::base::Join;
52 using ::android::base::Result;
53 using ::android::base::Split;
54 using ::android::base::StringAppendF;
55 using ::android::base::StringPrintf;
56 using ::android::base::WriteStringToFd;
57 using ::android::car::feature::car_watchdog_anr_metrics;
58 using ::ndk::ScopedAStatus;
59
60 namespace {
61
62 constexpr const char* kDumpAllFlag = "-a";
63 constexpr const char* kHelpFlag = "--help";
64 constexpr const char* kHelpShortFlag = "-h";
65 constexpr const char* kDumpProtoFlag = "--proto";
66 constexpr const char* kHelpText =
67 "Car watchdog daemon dumpsys help page:\n"
68 "Format: dumpsys android.automotive.watchdog.ICarWatchdog/default [options]\n\n"
69 "%s or %s: Displays this help text.\n"
70 "When no options are specified, car watchdog report is generated.\n";
71 constexpr const char* kNullCarWatchdogServiceError =
72 "Must provide a non-null car watchdog service instance";
73 constexpr const char* kNullCarWatchdogMonitorError =
74 "Must provide a non-null car watchdog monitor instance";
75
toScopedAStatus(int32_t exceptionCode,const std::string & message)76 ScopedAStatus toScopedAStatus(int32_t exceptionCode, const std::string& message) {
77 ALOGW("%s", message.c_str());
78 return ScopedAStatus::fromExceptionCodeWithMessage(exceptionCode, message.c_str());
79 }
80
toScopedAStatus(const Result<void> & result)81 ScopedAStatus toScopedAStatus(const Result<void>& result) {
82 return toScopedAStatus(result.error().code(), result.error().message());
83 }
84
checkSystemUser(const std::string & methodName)85 ScopedAStatus checkSystemUser(const std::string& methodName) {
86 if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
87 return toScopedAStatus(EX_SECURITY,
88 StringPrintf("Calling process does not have proper "
89 "privilege to call %s",
90 methodName.c_str()));
91 }
92 return ScopedAStatus::ok();
93 }
94
95 } // namespace
96
init()97 Result<void> WatchdogInternalHandler::init() {
98 if (mWatchdogPerfService == nullptr || mIoOveruseMonitor == nullptr ||
99 mWatchdogProcessService == nullptr || mWatchdogServiceHelper == nullptr) {
100 std::string serviceList;
101 if (mWatchdogPerfService == nullptr) {
102 StringAppendF(&serviceList, "%s%s", (!serviceList.empty() ? ", " : ""),
103 "Watchdog performance service");
104 }
105 if (mIoOveruseMonitor == nullptr) {
106 StringAppendF(&serviceList, "%s%s", (!serviceList.empty() ? ", " : ""),
107 "I/O overuse monitor service");
108 }
109 if (mWatchdogProcessService == nullptr) {
110 StringAppendF(&serviceList, "%s%s", (!serviceList.empty() ? ", " : ""),
111 "Watchdog process service");
112 }
113 if (mWatchdogServiceHelper == nullptr) {
114 StringAppendF(&serviceList, "%s%s", (!serviceList.empty() ? ", " : ""),
115 "Watchdog service helper");
116 }
117 return Error(INVALID_OPERATION)
118 << serviceList << " must be initialized with non-null instance";
119 }
120 return {};
121 }
122
dump(int fd,const char ** args,uint32_t numArgs)123 binder_status_t WatchdogInternalHandler::dump(int fd, const char** args, uint32_t numArgs) {
124 if (numArgs == 0 || strcmp(args[0], kDumpAllFlag) == 0) {
125 return dumpServices(fd);
126 }
127 if (numArgs == 1 &&
128 (EqualsIgnoreCase(args[0], kHelpFlag) || EqualsIgnoreCase(args[0], kHelpShortFlag))) {
129 return dumpHelpText(fd, "");
130 }
131 if (EqualsIgnoreCase(args[0], kStartCustomCollectionFlag) ||
132 EqualsIgnoreCase(args[0], kEndCustomCollectionFlag)) {
133 if (auto result = mWatchdogPerfService->onCustomCollection(fd, args, numArgs);
134 !result.ok()) {
135 std::string mode =
136 EqualsIgnoreCase(args[0], kStartCustomCollectionFlag) ? "start" : "stop";
137 std::string errorMsg = StringPrintf("Failed to %s custom perf collection: %s",
138 mode.c_str(), result.error().message().c_str());
139 if (result.error().code() == BAD_VALUE) {
140 dumpHelpText(fd, errorMsg);
141 } else {
142 ALOGW("%s", errorMsg.c_str());
143 WriteStringToFd(StringPrintf("Error: %s\n", errorMsg.c_str()), fd);
144 }
145 return result.error().code();
146 }
147 std::string mode =
148 EqualsIgnoreCase(args[0], kStartCustomCollectionFlag) ? "started" : "stopped";
149 // The message returned on success is used in the integration tests. If this message is
150 // updated, the CarWatchdog's integration tests must be updated too.
151 WriteStringToFd(StringPrintf("Successfully %s custom perf collection\n", mode.c_str()), fd);
152 return OK;
153 }
154 if (numArgs == 2 && EqualsIgnoreCase(args[0], kResetResourceOveruseStatsFlag)) {
155 std::string value = std::string(args[1]);
156 std::vector<std::string> packageNames = Split(value, ",");
157 if (value.empty() || packageNames.empty()) {
158 dumpHelpText(fd,
159 StringPrintf("Must provide valid package names: [%s]\n", value.c_str()));
160 return BAD_VALUE;
161 }
162 if (auto result = mIoOveruseMonitor->resetIoOveruseStats(packageNames); !result.ok()) {
163 ALOGW("Failed to reset stats for packages: [%s]", value.c_str());
164 return FAILED_TRANSACTION;
165 }
166 return OK;
167 }
168 std::vector<const char*> argsVector;
169 for (uint32_t i = 0; i < numArgs; ++i) {
170 if (EqualsIgnoreCase(args[i], kDumpProtoFlag)) {
171 return dumpProto(fd);
172 }
173 argsVector.push_back(args[i]);
174 }
175 dumpHelpText(fd,
176 StringPrintf("Invalid car watchdog dumpsys options: [%s]\n",
177 Join(argsVector, " ").c_str()));
178 return dumpServices(fd);
179 }
180
dumpServices(int fd)181 status_t WatchdogInternalHandler::dumpServices(int fd) {
182 mWatchdogProcessService->onDump(fd);
183 if (auto result = mWatchdogPerfService->onDump(fd); !result.ok()) {
184 ALOGW("Failed to dump car watchdog perf service: %s", result.error().message().c_str());
185 return result.error().code();
186 }
187 if (auto result = mIoOveruseMonitor->onDump(fd); !result.ok()) {
188 ALOGW("Failed to dump I/O overuse monitor: %s", result.error().message().c_str());
189 return result.error().code();
190 }
191 return OK;
192 }
193
dumpProto(int fd)194 status_t WatchdogInternalHandler::dumpProto(int fd) {
195 util::ProtoOutputStream proto;
196 if (auto result = mWatchdogPerfService->onDumpProto(proto); !result.ok()) {
197 ALOGW("Failed to dump car watchdog perf service: %s", result.error().message().c_str());
198 return result.error().code();
199 }
200
201 mWatchdogProcessService->onDumpProto(proto);
202
203 proto.flush(fd);
204 return OK;
205 }
206
dumpHelpText(const int fd,const std::string & errorMsg)207 status_t WatchdogInternalHandler::dumpHelpText(const int fd, const std::string& errorMsg) {
208 if (!errorMsg.empty()) {
209 ALOGW("Error: %s", errorMsg.c_str());
210 if (!WriteStringToFd(StringPrintf("Error: %s\n\n", errorMsg.c_str()), fd)) {
211 ALOGW("Failed to write error message to fd");
212 return FAILED_TRANSACTION;
213 }
214 }
215 if (!WriteStringToFd(StringPrintf(kHelpText, kHelpFlag, kHelpShortFlag), fd) ||
216 !mWatchdogPerfService->dumpHelpText(fd) || !mIoOveruseMonitor->dumpHelpText(fd)) {
217 ALOGW("Failed to write help text to fd");
218 return FAILED_TRANSACTION;
219 }
220 return OK;
221 }
222
checkAndRegisterIoOveruseMonitor()223 void WatchdogInternalHandler::checkAndRegisterIoOveruseMonitor() {
224 if (mIoOveruseMonitor->isInitialized()) {
225 return;
226 }
227 if (const auto result = mWatchdogPerfService->registerDataProcessor(mIoOveruseMonitor);
228 !result.ok()) {
229 ALOGE("Failed to register I/O overuse monitor to watchdog performance service: %s",
230 result.error().message().c_str());
231 }
232 return;
233 }
234
registerCarWatchdogService(const std::shared_ptr<ICarWatchdogServiceForSystem> & service)235 ScopedAStatus WatchdogInternalHandler::registerCarWatchdogService(
236 const std::shared_ptr<ICarWatchdogServiceForSystem>& service) {
237 if (auto status = checkSystemUser(/*methodName=*/"registerCarWatchdogService");
238 !status.isOk()) {
239 return status;
240 }
241 if (service == nullptr) {
242 return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
243 }
244 /*
245 * I/O overuse monitor reads from system, vendor, and data partitions during initialization.
246 * When CarService is running these partitions are available to read, thus register the I/O
247 * overuse monitor on processing the request to register CarService.
248 */
249 checkAndRegisterIoOveruseMonitor();
250 auto status = mWatchdogServiceHelper->registerService(service);
251 if (status.isOk()) {
252 mWatchdogPerfService->onCarWatchdogServiceRegistered();
253 }
254 return status;
255 }
256
unregisterCarWatchdogService(const std::shared_ptr<ICarWatchdogServiceForSystem> & service)257 ScopedAStatus WatchdogInternalHandler::unregisterCarWatchdogService(
258 const std::shared_ptr<ICarWatchdogServiceForSystem>& service) {
259 if (auto status = checkSystemUser(/*methodName=*/"unregisterCarWatchdogService");
260 !status.isOk()) {
261 return status;
262 }
263 if (service == nullptr) {
264 return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
265 }
266 return mWatchdogServiceHelper->unregisterService(service);
267 }
268
registerMonitor(const std::shared_ptr<ICarWatchdogMonitor> & monitor)269 ScopedAStatus WatchdogInternalHandler::registerMonitor(
270 const std::shared_ptr<ICarWatchdogMonitor>& monitor) {
271 if (auto status = checkSystemUser(/*methodName=*/"registerMonitor"); !status.isOk()) {
272 return status;
273 }
274 if (monitor == nullptr) {
275 return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
276 }
277 return mWatchdogProcessService->registerMonitor(monitor);
278 }
279
unregisterMonitor(const std::shared_ptr<ICarWatchdogMonitor> & monitor)280 ScopedAStatus WatchdogInternalHandler::unregisterMonitor(
281 const std::shared_ptr<ICarWatchdogMonitor>& monitor) {
282 if (auto status = checkSystemUser(/*methodName=*/"unregisterMonitor"); !status.isOk()) {
283 return status;
284 }
285 if (monitor == nullptr) {
286 return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
287 }
288 return mWatchdogProcessService->unregisterMonitor(monitor);
289 }
290
tellCarWatchdogServiceAlive(const std::shared_ptr<ICarWatchdogServiceForSystem> & service,const std::vector<ProcessIdentifier> & clientsNotResponding,int32_t sessionId)291 ScopedAStatus WatchdogInternalHandler::tellCarWatchdogServiceAlive(
292 const std::shared_ptr<ICarWatchdogServiceForSystem>& service,
293 const std::vector<ProcessIdentifier>& clientsNotResponding, int32_t sessionId) {
294 if (auto status = checkSystemUser(/*methodName=*/"tellCarWatchdogServiceAlive");
295 !status.isOk()) {
296 return status;
297 }
298 if (service == nullptr) {
299 return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogServiceError);
300 }
301 return mWatchdogProcessService->tellCarWatchdogServiceAlive(service, clientsNotResponding,
302 sessionId);
303 }
304
tellDumpFinished(const std::shared_ptr<ICarWatchdogMonitor> & monitor,const std::vector<ProcessIdentifier> & processIdentifiers)305 ScopedAStatus WatchdogInternalHandler::tellDumpFinished(
306 const std::shared_ptr<ICarWatchdogMonitor>& monitor,
307 const std::vector<ProcessIdentifier>& processIdentifiers) {
308 if (auto status = checkSystemUser(/*methodName=*/"tellDumpFinished"); !status.isOk()) {
309 return status;
310 }
311 if (monitor == nullptr) {
312 return toScopedAStatus(EX_ILLEGAL_ARGUMENT, kNullCarWatchdogMonitorError);
313 }
314 return mWatchdogProcessService->tellDumpFinished(monitor, processIdentifiers);
315 }
316
notifySystemStateChange(StateType type,int32_t arg1,int32_t arg2)317 ScopedAStatus WatchdogInternalHandler::notifySystemStateChange(StateType type, int32_t arg1,
318 int32_t arg2) {
319 if (auto status = checkSystemUser(/*methodName=*/"notifySystemStateChange"); !status.isOk()) {
320 return status;
321 }
322 switch (type) {
323 case StateType::POWER_CYCLE: {
324 PowerCycle powerCycle = static_cast<PowerCycle>(static_cast<uint32_t>(arg1));
325 return handlePowerCycleChange(powerCycle);
326 }
327 case StateType::GARAGE_MODE: {
328 GarageMode garageMode = static_cast<GarageMode>(static_cast<uint32_t>(arg1));
329 mWatchdogPerfService->setSystemState(garageMode == GarageMode::GARAGE_MODE_OFF
330 ? SystemState::NORMAL_MODE
331 : SystemState::GARAGE_MODE);
332 if (car_watchdog_anr_metrics()) {
333 mWatchdogProcessService->setGarageMode(garageMode);
334 }
335 return ScopedAStatus::ok();
336 }
337 case StateType::USER_STATE: {
338 userid_t userId = static_cast<userid_t>(arg1);
339 UserState userState = static_cast<UserState>(static_cast<uint32_t>(arg2));
340 return handleUserStateChange(userId, userState);
341 }
342 case StateType::BOOT_PHASE: {
343 BootPhase phase = static_cast<BootPhase>(static_cast<uint32_t>(arg1));
344 if (phase >= BootPhase::BOOT_COMPLETED) {
345 if (const auto result = mWatchdogPerfService->onBootFinished(); !result.ok()) {
346 return toScopedAStatus(result);
347 }
348 }
349 return ScopedAStatus::ok();
350 }
351 }
352 return toScopedAStatus(EX_ILLEGAL_ARGUMENT, StringPrintf("Invalid state change type %d", type));
353 }
354
handlePowerCycleChange(PowerCycle powerCycle)355 ScopedAStatus WatchdogInternalHandler::handlePowerCycleChange(PowerCycle powerCycle) {
356 switch (powerCycle) {
357 case PowerCycle::POWER_CYCLE_SHUTDOWN_PREPARE:
358 ALOGI("Received SHUTDOWN_PREPARE power cycle");
359 mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
360 break;
361 case PowerCycle::POWER_CYCLE_SHUTDOWN_ENTER:
362 ALOGI("Received SHUTDOWN_ENTER power cycle");
363 mWatchdogProcessService->setEnabled(/*isEnabled=*/false);
364 mWatchdogPerfService->onShutdownEnter();
365 break;
366 case PowerCycle::POWER_CYCLE_SUSPEND_EXIT:
367 ALOGI("Received SUSPEND_EXIT power cycle");
368 mWatchdogPerfService->onSuspendExit();
369 break;
370 case PowerCycle::POWER_CYCLE_RESUME:
371 ALOGI("Received RESUME power cycle");
372 mWatchdogProcessService->setEnabled(/*isEnabled=*/true);
373 break;
374 default:
375 return toScopedAStatus(EX_ILLEGAL_ARGUMENT,
376 StringPrintf("Unsupported power cycle: %d", powerCycle));
377 }
378 return ScopedAStatus::ok();
379 }
380
handleUserStateChange(userid_t userId,const UserState & userState)381 ScopedAStatus WatchdogInternalHandler::handleUserStateChange(userid_t userId,
382 const UserState& userState) {
383 std::string stateDesc;
384 switch (userState) {
385 case UserState::USER_STATE_STARTED:
386 stateDesc = "started";
387 mWatchdogProcessService->onUserStateChange(userId, /*isStarted=*/true);
388 break;
389 case UserState::USER_STATE_SWITCHING:
390 stateDesc = "switching";
391 mWatchdogPerfService->onUserStateChange(userId, userState);
392 break;
393 case UserState::USER_STATE_UNLOCKING:
394 stateDesc = "unlocking";
395 mWatchdogPerfService->onUserStateChange(userId, userState);
396 break;
397 case UserState::USER_STATE_POST_UNLOCKED:
398 stateDesc = "post_unlocked";
399 mWatchdogPerfService->onUserStateChange(userId, userState);
400 break;
401 case UserState::USER_STATE_STOPPED:
402 stateDesc = "stopped";
403 mWatchdogProcessService->onUserStateChange(userId, /*isStarted=*/false);
404 break;
405 case UserState::USER_STATE_REMOVED:
406 stateDesc = "removed";
407 mIoOveruseMonitor->removeStatsForUser(userId);
408 break;
409 default:
410 // UserState::USER_STATE_UNLOCKED is not sent by CarService to the daemon. If signal is
411 // received, an exception will be thrown.
412 return toScopedAStatus(EX_ILLEGAL_ARGUMENT,
413 StringPrintf("Unsupported user state: %d", userState));
414 }
415 ALOGI("Received user state change: user(%" PRId32 ") is %s", userId, stateDesc.c_str());
416 return ScopedAStatus::ok();
417 }
418
updateResourceOveruseConfigurations(const std::vector<ResourceOveruseConfiguration> & configs)419 ScopedAStatus WatchdogInternalHandler::updateResourceOveruseConfigurations(
420 const std::vector<ResourceOveruseConfiguration>& configs) {
421 if (auto status = checkSystemUser(/*methodName=*/"updateResourceOveruseConfigurations");
422 !status.isOk()) {
423 return status;
424 }
425 // Maybe retry registring I/O overuse monitor if failed to initialize previously.
426 checkAndRegisterIoOveruseMonitor();
427 if (auto result = mIoOveruseMonitor->updateResourceOveruseConfigurations(configs);
428 !result.ok()) {
429 return toScopedAStatus(result);
430 }
431 return ScopedAStatus::ok();
432 }
433
getResourceOveruseConfigurations(std::vector<ResourceOveruseConfiguration> * configs)434 ScopedAStatus WatchdogInternalHandler::getResourceOveruseConfigurations(
435 std::vector<ResourceOveruseConfiguration>* configs) {
436 if (auto status = checkSystemUser(/*methodName=*/"getResourceOveruseConfigurations");
437 !status.isOk()) {
438 return status;
439 }
440 // Maybe retry registring I/O overuse monitor if failed to initialize previously.
441 checkAndRegisterIoOveruseMonitor();
442 if (auto result = mIoOveruseMonitor->getResourceOveruseConfigurations(configs); !result.ok()) {
443 return toScopedAStatus(result);
444 }
445 return ScopedAStatus::ok();
446 }
447
controlProcessHealthCheck(bool enable)448 ScopedAStatus WatchdogInternalHandler::controlProcessHealthCheck(bool enable) {
449 if (auto status = checkSystemUser(/*methodName=*/"controlProcessHealthCheck"); !status.isOk()) {
450 return status;
451 }
452 mWatchdogProcessService->setEnabled(enable);
453 return ScopedAStatus::ok();
454 }
455
setThreadPriority(int pid,int tid,int uid,int policy,int priority)456 ScopedAStatus WatchdogInternalHandler::setThreadPriority(int pid, int tid, int uid, int policy,
457 int priority) {
458 if (auto status = checkSystemUser(/*methodName=*/"setThreadPriority"); !status.isOk()) {
459 return status;
460 }
461 if (auto result = mThreadPriorityController->setThreadPriority(pid, tid, uid, policy, priority);
462 !result.ok()) {
463 return toScopedAStatus(result);
464 }
465 return ScopedAStatus::ok();
466 }
467
getThreadPriority(int pid,int tid,int uid,ThreadPolicyWithPriority * threadPolicyWithPriority)468 ScopedAStatus WatchdogInternalHandler::getThreadPriority(
469 int pid, int tid, int uid, ThreadPolicyWithPriority* threadPolicyWithPriority) {
470 if (auto status = checkSystemUser(/*methodName=*/"getThreadPriority"); !status.isOk()) {
471 return status;
472 }
473 if (auto result = mThreadPriorityController->getThreadPriority(pid, tid, uid,
474 threadPolicyWithPriority);
475 !result.ok()) {
476 return toScopedAStatus(result);
477 }
478 return ScopedAStatus::ok();
479 }
480
onAidlVhalPidFetched(int pid)481 ScopedAStatus WatchdogInternalHandler::onAidlVhalPidFetched(int pid) {
482 if (auto status = checkSystemUser(/*methodName=*/"onAidlVhalPidFetched"); !status.isOk()) {
483 return status;
484 }
485 mWatchdogProcessService->onAidlVhalPidFetched(pid);
486 return ScopedAStatus::ok();
487 }
488
setThreadPriorityController(std::unique_ptr<ThreadPriorityControllerInterface> threadPriorityController)489 void WatchdogInternalHandler::setThreadPriorityController(
490 std::unique_ptr<ThreadPriorityControllerInterface> threadPriorityController) {
491 mThreadPriorityController = std::move(threadPriorityController);
492 }
493
onTodayIoUsageStatsFetched(const std::vector<UserPackageIoUsageStats> & userPackageIoUsageStats)494 ScopedAStatus WatchdogInternalHandler::onTodayIoUsageStatsFetched(
495 const std::vector<UserPackageIoUsageStats>& userPackageIoUsageStats) {
496 if (auto status = checkSystemUser(/*methodName=*/"onTodayIoUsageStatsFetched");
497 !status.isOk()) {
498 return status;
499 }
500 if (auto result = mIoOveruseMonitor->onTodayIoUsageStatsFetched(userPackageIoUsageStats);
501 !result.ok()) {
502 return toScopedAStatus(result);
503 }
504 return ScopedAStatus::ok();
505 }
506
507 } // namespace watchdog
508 } // namespace automotive
509 } // namespace android
510