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 "WatchdogPerfService.h"
21
22 #include <android-base/file.h>
23 #include <android-base/parseint.h>
24 #include <android-base/stringprintf.h>
25 #include <android-base/strings.h>
26 #include <android/util/ProtoOutputStream.h>
27 #include <log/log.h>
28 #include <processgroup/sched_policy.h>
29
30 #include <pthread.h>
31
32 #include <iterator>
33 #include <vector>
34
35 #include <carwatchdog_daemon_dump.proto.h>
36 #include <health_check_client_info.proto.h>
37 #include <performance_stats.proto.h>
38
39 namespace android {
40 namespace automotive {
41 namespace watchdog {
42
43 namespace {
44
45 using ::aidl::android::automotive::watchdog::internal::ResourceStats;
46 using ::aidl::android::automotive::watchdog::internal::UserState;
47 using ::android::sp;
48 using ::android::String16;
49 using ::android::String8;
50 using ::android::base::EqualsIgnoreCase;
51 using ::android::base::Error;
52 using ::android::base::Join;
53 using ::android::base::ParseUint;
54 using ::android::base::Result;
55 using ::android::base::Split;
56 using ::android::base::StringAppendF;
57 using ::android::base::StringPrintf;
58 using ::android::base::WriteStringToFd;
59 using ::android::util::ProtoOutputStream;
60
61 const int32_t kMaxCachedUnsentResourceStats = 10;
62 const std::chrono::nanoseconds kPrevUnsentResourceStatsDelayNs = 3s;
63 // Minimum required collection polling interval between subsequent collections.
64 const std::chrono::nanoseconds kMinEventInterval = 1s;
65 const std::chrono::seconds kDefaultSystemEventCollectionInterval = 1s;
66 const std::chrono::seconds kDefaultPeriodicCollectionInterval = 20s;
67 const std::chrono::seconds kDefaultPeriodicMonitorInterval = 5s;
68 const std::chrono::nanoseconds kCustomCollectionInterval = 10s;
69 const std::chrono::nanoseconds kCustomCollectionDuration = 30min;
70
71 constexpr const char* kServiceName = "WatchdogPerfService";
72 static const std::string kDumpMajorDelimiter = std::string(100, '-') + "\n"; // NOLINT
73 constexpr const char* kHelpText =
74 "\n%s dump options:\n"
75 "%s: Starts custom performance data collection. Customize the collection behavior with "
76 "the following optional arguments:\n"
77 "\t%s <seconds>: Modifies the collection interval. Default behavior is to collect once "
78 "every %lld seconds.\n"
79 "\t%s <seconds>: Modifies the maximum collection duration. Default behavior is to collect "
80 "until %ld minutes before automatically stopping the custom collection and discarding "
81 "the collected data.\n"
82 "\t%s <package name>,<package name>,...: Comma-separated value containing package names. "
83 "When provided, the results are filtered only to the provided package names. Default "
84 "behavior is to list the results for the top N packages.\n"
85 "%s: Stops custom performance data collection and generates a dump of "
86 "the collection report.\n\n"
87 "When no options are specified, the car watchdog report contains the performance data "
88 "collected during boot-time and over the last few minutes before the report generation.\n";
89
parseSecondsFlag(const char ** args,uint32_t numArgs,size_t pos)90 Result<std::chrono::seconds> parseSecondsFlag(const char** args, uint32_t numArgs, size_t pos) {
91 if (numArgs <= pos) {
92 return Error() << "Value not provided";
93 }
94 uint64_t value;
95 if (std::string strValue = std::string(args[pos]); !ParseUint(strValue, &value)) {
96 return Error() << "Invalid value " << strValue << ", must be an integer";
97 }
98 return std::chrono::seconds(value);
99 }
100
toString(std::variant<EventType,SwitchMessage> what)101 constexpr const char* toString(std::variant<EventType, SwitchMessage> what) {
102 return std::visit(
103 [&](const auto& v) -> const char* {
104 switch (static_cast<int>(v)) {
105 case EventType::INIT:
106 return "INIT";
107 case EventType::TERMINATED:
108 return "TERMINATED";
109 case EventType::BOOT_TIME_COLLECTION:
110 return "BOOT_TIME_COLLECTION";
111 case EventType::PERIODIC_COLLECTION:
112 return "PERIODIC_COLLECTION";
113 case EventType::USER_SWITCH_COLLECTION:
114 return "USER_SWITCH_COLLECTION";
115 case EventType::WAKE_UP_COLLECTION:
116 return "WAKE_UP_COLLECTION";
117 case EventType::CUSTOM_COLLECTION:
118 return "CUSTOM_COLLECTION";
119 case EventType::PERIODIC_MONITOR:
120 return "PERIODIC_MONITOR";
121 case EventType::LAST_EVENT:
122 return "LAST_EVENT";
123 case SwitchMessage::END_BOOTTIME_COLLECTION:
124 return "END_BOOTTIME_COLLECTION";
125 case SwitchMessage::END_USER_SWITCH_COLLECTION:
126 return "END_USER_SWITCH_COLLECTION";
127 case SwitchMessage::END_WAKE_UP_COLLECTION:
128 return "END_WAKE_UP_COLLECTION";
129 case SwitchMessage::END_CUSTOM_COLLECTION:
130 return "END_CUSTOM_COLLECTION";
131 default:
132 return "INVALID_EVENT_OR_SWITCH_MESSAGE";
133 }
134 },
135 what);
136 }
137
toProtoEventType(EventType eventType)138 constexpr int toProtoEventType(EventType eventType) {
139 switch (eventType) {
140 case EventType::INIT:
141 return PerformanceProfilerDump::INIT;
142 case EventType::TERMINATED:
143 return PerformanceProfilerDump::TERMINATED;
144 case EventType::BOOT_TIME_COLLECTION:
145 return PerformanceProfilerDump::BOOT_TIME_COLLECTION;
146 case EventType::PERIODIC_COLLECTION:
147 return PerformanceProfilerDump::PERIODIC_COLLECTION;
148 case EventType::USER_SWITCH_COLLECTION:
149 return PerformanceProfilerDump::USER_SWITCH_COLLECTION;
150 case EventType::WAKE_UP_COLLECTION:
151 return PerformanceProfilerDump::WAKE_UP_COLLECTION;
152 case EventType::CUSTOM_COLLECTION:
153 return PerformanceProfilerDump::CUSTOM_COLLECTION;
154 default:
155 return PerformanceProfilerDump::EVENT_TYPE_UNSPECIFIED;
156 }
157 }
158
toString(SystemState systemState)159 constexpr const char* toString(SystemState systemState) {
160 switch (systemState) {
161 case SystemState::NORMAL_MODE:
162 return "NORMAL_MODE";
163 case SystemState::GARAGE_MODE:
164 return "GARAGE_MODE";
165 default:
166 return "UNKNOWN MODE";
167 }
168 }
169
isEmpty(const ResourceStats & resourceStats)170 bool isEmpty(const ResourceStats& resourceStats) {
171 return !resourceStats.resourceUsageStats.has_value() &&
172 !resourceStats.resourceOveruseStats.has_value();
173 }
174
175 } // namespace
176
toString() const177 std::string WatchdogPerfService::EventMetadata::toString() const {
178 std::string buffer;
179 const auto intervalInSecs =
180 std::chrono::duration_cast<std::chrono::seconds>(pollingIntervalNs).count();
181 StringAppendF(&buffer, "Event polling interval: %lld second%s\n", intervalInSecs,
182 ((intervalInSecs > 1) ? "s" : ""));
183 if (!filterPackages.empty()) {
184 std::vector<std::string> packages(filterPackages.begin(), filterPackages.end());
185 StringAppendF(&buffer, "Filtered results to packages: %s\n", Join(packages, ", ").c_str());
186 }
187 return buffer;
188 }
189
registerDataProcessor(sp<DataProcessorInterface> processor)190 Result<void> WatchdogPerfService::registerDataProcessor(sp<DataProcessorInterface> processor) {
191 if (processor == nullptr) {
192 return Error() << "Must provide a valid data processor";
193 }
194 if (const auto result = processor->init(); !result.ok()) {
195 return Error() << "Failed to initialize " << processor->name().c_str() << ": "
196 << result.error().message();
197 }
198 Mutex::Autolock lock(mMutex);
199 mDataProcessors.push_back(processor);
200 if (DEBUG) {
201 ALOGD("Successfully registered %s to %s", processor->name().c_str(), kServiceName);
202 }
203 return {};
204 }
205
start()206 Result<void> WatchdogPerfService::start() {
207 {
208 Mutex::Autolock lock(mMutex);
209 if (mCurrCollectionEvent != EventType::INIT || mCollectionThread.joinable()) {
210 return Error(INVALID_OPERATION) << "Cannot start " << kServiceName << " more than once";
211 }
212 if (mWatchdogServiceHelper == nullptr) {
213 return Error(INVALID_OPERATION) << "No watchdog service helper is registered";
214 }
215 std::chrono::nanoseconds systemEventCollectionInterval =
216 std::chrono::duration_cast<std::chrono::nanoseconds>(
217 std::chrono::seconds(sysprop::systemEventCollectionInterval().value_or(
218 kDefaultSystemEventCollectionInterval.count())));
219 std::chrono::nanoseconds periodicCollectionInterval =
220 std::chrono::duration_cast<std::chrono::nanoseconds>(
221 std::chrono::seconds(sysprop::periodicCollectionInterval().value_or(
222 kDefaultPeriodicCollectionInterval.count())));
223 std::chrono::nanoseconds periodicMonitorInterval =
224 std::chrono::duration_cast<std::chrono::nanoseconds>(
225 std::chrono::seconds(sysprop::periodicMonitorInterval().value_or(
226 kDefaultPeriodicMonitorInterval.count())));
227 mBoottimeCollection = {
228 .eventType = EventType::BOOT_TIME_COLLECTION,
229 .pollingIntervalNs = systemEventCollectionInterval,
230 };
231 mPeriodicCollection = {
232 .eventType = EventType::PERIODIC_COLLECTION,
233 .pollingIntervalNs = periodicCollectionInterval,
234 };
235 mUserSwitchCollection = {{
236 .eventType = EventType::USER_SWITCH_COLLECTION,
237 .pollingIntervalNs = systemEventCollectionInterval,
238 }};
239 mWakeUpCollection = {
240 .eventType = EventType::WAKE_UP_COLLECTION,
241 .pollingIntervalNs = systemEventCollectionInterval,
242 };
243 mPeriodicMonitor = {
244 .eventType = EventType::PERIODIC_MONITOR,
245 .pollingIntervalNs = periodicMonitorInterval,
246 };
247 if (mDataProcessors.empty()) {
248 ALOGE("Terminating %s: No data processor is registered", kServiceName);
249 mCurrCollectionEvent = EventType::TERMINATED;
250 return Error() << "No data processor is registered";
251 }
252 mUidStatsCollector->init();
253 mProcStatCollector->init();
254 mProcDiskStatsCollector->init();
255 }
256
257 mCollectionThread = std::thread([&]() {
258 {
259 Mutex::Autolock lock(mMutex);
260 if (EventType expected = EventType::INIT; mCurrCollectionEvent != expected) {
261 ALOGE("Skipping performance data collection as the current collection event "
262 "%s != %s",
263 toString(mCurrCollectionEvent), toString(expected));
264 return;
265 }
266 notifySystemStartUpLocked();
267 mCurrCollectionEvent = EventType::BOOT_TIME_COLLECTION;
268 mBoottimeCollection.lastPollUptimeNs = mHandlerLooper->now();
269 mHandlerLooper->setLooper(Looper::prepare(/*opts=*/0));
270 mHandlerLooper->sendMessage(sp<WatchdogPerfService>::fromExisting(this),
271 EventType::BOOT_TIME_COLLECTION);
272 }
273 if (set_sched_policy(0, SP_BACKGROUND) != 0) {
274 ALOGW("Failed to set background scheduling priority to %s thread", kServiceName);
275 }
276 if (int result = pthread_setname_np(pthread_self(), "WatchdogPerfSvc"); result != 0) {
277 ALOGE("Failed to set %s thread name: %d", kServiceName, result);
278 }
279 ALOGI("Starting %s performance data collection", toString(mCurrCollectionEvent));
280 bool isCollectionActive = true;
281 /*
282 * Loop until the collection is not active -- performance collection runs on this thread in
283 * a handler.
284 */
285 while (isCollectionActive) {
286 mHandlerLooper->pollAll(/*timeoutMillis=*/-1);
287 Mutex::Autolock lock(mMutex);
288 isCollectionActive = mCurrCollectionEvent != EventType::TERMINATED;
289 }
290 });
291 return {};
292 }
293
terminate()294 void WatchdogPerfService::terminate() {
295 {
296 Mutex::Autolock lock(mMutex);
297 if (mCurrCollectionEvent == EventType::TERMINATED) {
298 ALOGE("%s was terminated already", kServiceName);
299 return;
300 }
301 ALOGE("Terminating %s as car watchdog is terminating", kServiceName);
302 if (mCurrCollectionEvent != EventType::INIT) {
303 /*
304 * Looper runs only after EventType::INIT has completed so remove looper messages
305 * and wake the looper only when the current collection has changed from INIT.
306 */
307 mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
308 mHandlerLooper->wake();
309 }
310 for (const auto& processor : mDataProcessors) {
311 processor->terminate();
312 }
313 mCurrCollectionEvent = EventType::TERMINATED;
314 mUnsentResourceStats.clear();
315 }
316 if (mCollectionThread.joinable()) {
317 mCollectionThread.join();
318 if (DEBUG) {
319 ALOGD("%s collection thread terminated", kServiceName);
320 }
321 }
322 }
323
setSystemState(SystemState systemState)324 void WatchdogPerfService::setSystemState(SystemState systemState) {
325 Mutex::Autolock lock(mMutex);
326 if (mSystemState != systemState) {
327 ALOGI("%s switching from %s to %s", kServiceName, toString(mSystemState),
328 toString(systemState));
329 }
330 mSystemState = systemState;
331 }
332
onCarWatchdogServiceRegistered()333 void WatchdogPerfService::onCarWatchdogServiceRegistered() {
334 Mutex::Autolock lock(mMutex);
335 for (const auto& processor : mDataProcessors) {
336 processor->onCarWatchdogServiceRegistered();
337 }
338 if (mUnsentResourceStats.empty()) {
339 return;
340 }
341 mHandlerLooper->sendMessage(sp<WatchdogPerfService>::fromExisting(this),
342 TaskMessage::SEND_RESOURCE_STATS);
343 }
344
onBootFinished()345 Result<void> WatchdogPerfService::onBootFinished() {
346 Mutex::Autolock lock(mMutex);
347 if (EventType expected = EventType::BOOT_TIME_COLLECTION; mCurrCollectionEvent != expected) {
348 /*
349 * This case happens when either the WatchdogPerfService has prematurely terminated before
350 * boot complete notification is received or multiple boot complete notifications are
351 * received. In either case don't return error as this will lead to runtime exception and
352 * cause system to boot loop.
353 */
354 ALOGE("Current performance data collection event %s != %s", toString(mCurrCollectionEvent),
355 toString(expected));
356 return {};
357 }
358 mHandlerLooper->sendMessageAtTime(mHandlerLooper->now() + mPostSystemEventDurationNs.count(),
359 sp<WatchdogPerfService>::fromExisting(this),
360 SwitchMessage::END_BOOTTIME_COLLECTION);
361 if (DEBUG) {
362 ALOGD("Boot complete signal received.");
363 }
364 return {};
365 }
366
onUserStateChange(userid_t userId,const UserState & userState)367 Result<void> WatchdogPerfService::onUserStateChange(userid_t userId, const UserState& userState) {
368 Mutex::Autolock lock(mMutex);
369 if (mCurrCollectionEvent == EventType::BOOT_TIME_COLLECTION ||
370 mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
371 mUserSwitchCollection.from = mUserSwitchCollection.to;
372 mUserSwitchCollection.to = userId;
373 ALOGI("Current collection: %s. Ignoring user switch from userId = %d to userId = %d)",
374 toString(mCurrCollectionEvent), mUserSwitchCollection.from, mUserSwitchCollection.to);
375 // Ignoring the user switch events because the boot-time and custom collections take
376 // precedence over other collections.
377 if (mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
378 ALOGW("Unable to start %s. Current performance data collection event: %s",
379 toString(EventType::USER_SWITCH_COLLECTION), toString(mCurrCollectionEvent));
380 }
381 return {};
382 }
383 switch (static_cast<int>(userState)) {
384 case static_cast<int>(UserState::USER_STATE_SWITCHING):
385 // TODO(b/243984863): Handle multi-user switching scenario.
386 mUserSwitchCollection.from = mUserSwitchCollection.to;
387 mUserSwitchCollection.to = userId;
388 if (mCurrCollectionEvent != EventType::PERIODIC_COLLECTION &&
389 mCurrCollectionEvent != EventType::USER_SWITCH_COLLECTION) {
390 ALOGE("Unable to start %s. Current performance data collection event: %s",
391 toString(EventType::USER_SWITCH_COLLECTION), toString(mCurrCollectionEvent));
392 return {};
393 }
394 startUserSwitchCollection();
395 ALOGI("Switching to %s (userIds: from = %d, to = %d)", toString(mCurrCollectionEvent),
396 mUserSwitchCollection.from, mUserSwitchCollection.to);
397 break;
398 case static_cast<int>(UserState::USER_STATE_UNLOCKING):
399 if (mCurrCollectionEvent != EventType::PERIODIC_COLLECTION) {
400 if (mCurrCollectionEvent != EventType::USER_SWITCH_COLLECTION) {
401 ALOGE("Unable to start %s. Current performance data collection event: %s",
402 toString(EventType::USER_SWITCH_COLLECTION),
403 toString(mCurrCollectionEvent));
404 }
405 return {};
406 }
407 if (mUserSwitchCollection.to != userId) {
408 return {};
409 }
410 startUserSwitchCollection();
411 ALOGI("Switching to %s (userId: %d)", toString(mCurrCollectionEvent), userId);
412 break;
413 case static_cast<int>(UserState::USER_STATE_POST_UNLOCKED): {
414 if (mCurrCollectionEvent != EventType::USER_SWITCH_COLLECTION) {
415 ALOGE("Ignoring USER_STATE_POST_UNLOCKED because no user switch collection in "
416 "progress. Current performance data collection event: %s.",
417 toString(mCurrCollectionEvent));
418 return {};
419 }
420 if (mUserSwitchCollection.to != userId) {
421 ALOGE("Ignoring USER_STATE_POST_UNLOCKED signal for user id: %d. "
422 "Current user being switched to: %d",
423 userId, mUserSwitchCollection.to);
424 return {};
425 }
426 auto thiz = sp<WatchdogPerfService>::fromExisting(this);
427 mHandlerLooper->removeMessages(thiz, SwitchMessage::END_USER_SWITCH_COLLECTION);
428 nsecs_t endUserSwitchCollectionTime =
429 mHandlerLooper->now() + mPostSystemEventDurationNs.count();
430 mHandlerLooper->sendMessageAtTime(endUserSwitchCollectionTime, thiz,
431 SwitchMessage::END_USER_SWITCH_COLLECTION);
432 break;
433 }
434 default:
435 ALOGE("Unsupported user state: %d", static_cast<int>(userState));
436 return {};
437 }
438 if (DEBUG) {
439 ALOGD("Handled user state change: userId = %d, userState = %d", userId,
440 static_cast<int>(userState));
441 }
442 return {};
443 }
444
startUserSwitchCollection()445 Result<void> WatchdogPerfService::startUserSwitchCollection() {
446 auto thiz = sp<WatchdogPerfService>::fromExisting(this);
447 mHandlerLooper->removeMessages(thiz);
448 mUserSwitchCollection.lastPollUptimeNs = mHandlerLooper->now();
449 // End |EventType::USER_SWITCH_COLLECTION| after a timeout because the user switch end
450 // signal won't be received within a few seconds when the switch is blocked due to a
451 // keyguard event. Otherwise, polling beyond a few seconds will lead to unnecessary data
452 // collection.
453 mHandlerLooper->sendMessageAtTime(mHandlerLooper->now() + mUserSwitchTimeoutNs.count(), thiz,
454 SwitchMessage::END_USER_SWITCH_COLLECTION);
455 mCurrCollectionEvent = EventType::USER_SWITCH_COLLECTION;
456 mHandlerLooper->sendMessage(thiz, EventType::USER_SWITCH_COLLECTION);
457 return {};
458 }
459
onSuspendExit()460 Result<void> WatchdogPerfService::onSuspendExit() {
461 Mutex::Autolock lock(mMutex);
462 if (mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
463 // Ignoring the suspend exit event because the custom collection takes
464 // precedence over other collections.
465 ALOGE("Unable to start %s. Current performance data collection event: %s",
466 toString(EventType::WAKE_UP_COLLECTION), toString(mCurrCollectionEvent));
467 return {};
468 }
469 if (mCurrCollectionEvent == EventType::WAKE_UP_COLLECTION) {
470 ALOGE("The current performance data collection event is already %s",
471 toString(EventType::WAKE_UP_COLLECTION));
472 return {};
473 }
474 notifySystemStartUpLocked();
475 auto thiz = sp<WatchdogPerfService>::fromExisting(this);
476 mHandlerLooper->removeMessages(thiz);
477 nsecs_t now = mHandlerLooper->now();
478 mWakeUpCollection.lastPollUptimeNs = now;
479 mHandlerLooper->sendMessageAtTime(now + mWakeUpDurationNs.count(), thiz,
480 SwitchMessage::END_WAKE_UP_COLLECTION);
481 mCurrCollectionEvent = EventType::WAKE_UP_COLLECTION;
482 mHandlerLooper->sendMessage(thiz, EventType::WAKE_UP_COLLECTION);
483 ALOGI("Switching to %s", toString(mCurrCollectionEvent));
484 return {};
485 }
486
onShutdownEnter()487 Result<void> WatchdogPerfService::onShutdownEnter() {
488 Mutex::Autolock lock(mMutex);
489 if (mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
490 ALOGI("Unable to switch to %s during shutdown enter. Current performance data collection "
491 "event: %s",
492 toString(EventType::PERIODIC_COLLECTION), toString(mCurrCollectionEvent));
493 return {};
494 }
495 switchToPeriodicLocked(/*startNow=*/true);
496 return {};
497 }
498
onCustomCollection(int fd,const char ** args,uint32_t numArgs)499 Result<void> WatchdogPerfService::onCustomCollection(int fd, const char** args, uint32_t numArgs) {
500 if (numArgs == 0) {
501 return Error(BAD_VALUE) << "No custom collection dump arguments";
502 }
503
504 if (EqualsIgnoreCase(args[0], kStartCustomCollectionFlag)) {
505 if (numArgs > 7) {
506 return Error(BAD_VALUE) << "Number of arguments to start custom performance data "
507 << "collection cannot exceed 7";
508 }
509 std::chrono::nanoseconds interval = kCustomCollectionInterval;
510 std::chrono::nanoseconds maxDuration = kCustomCollectionDuration;
511 std::unordered_set<std::string> filterPackages;
512 for (uint32_t i = 1; i < numArgs; ++i) {
513 if (EqualsIgnoreCase(args[i], kIntervalFlag)) {
514 const auto& result = parseSecondsFlag(args, numArgs, i + 1);
515 if (!result.ok()) {
516 return Error(BAD_VALUE)
517 << "Failed to parse " << kIntervalFlag << ": " << result.error();
518 }
519 interval = std::chrono::duration_cast<std::chrono::nanoseconds>(*result);
520 ++i;
521 continue;
522 }
523 if (EqualsIgnoreCase(args[i], kMaxDurationFlag)) {
524 const auto& result = parseSecondsFlag(args, numArgs, i + 1);
525 if (!result.ok()) {
526 return Error(BAD_VALUE)
527 << "Failed to parse " << kMaxDurationFlag << ": " << result.error();
528 }
529 maxDuration = std::chrono::duration_cast<std::chrono::nanoseconds>(*result);
530 ++i;
531 continue;
532 }
533 if (EqualsIgnoreCase(args[i], kFilterPackagesFlag)) {
534 if (numArgs < i + 1) {
535 return Error(BAD_VALUE)
536 << "Must provide value for '" << kFilterPackagesFlag << "' flag";
537 }
538 std::vector<std::string> packages = Split(std::string(args[i + 1]), ",");
539 std::copy(packages.begin(), packages.end(),
540 std::inserter(filterPackages, filterPackages.end()));
541 ++i;
542 continue;
543 }
544 return Error(BAD_VALUE) << "Unknown flag " << args[i]
545 << " provided to start custom performance data collection";
546 }
547 if (const auto& result = startCustomCollection(interval, maxDuration, filterPackages);
548 !result.ok()) {
549 return result;
550 }
551 return {};
552 }
553 if (EqualsIgnoreCase(args[0], kEndCustomCollectionFlag)) {
554 if (numArgs != 1) {
555 ALOGW("Number of arguments to stop custom performance data collection cannot exceed 1. "
556 "Stopping the data collection.");
557 WriteStringToFd("Number of arguments to stop custom performance data collection "
558 "cannot exceed 1. Stopping the data collection.",
559 fd);
560 }
561 return endCustomCollection(fd);
562 }
563 return Error(BAD_VALUE) << "Custom perf collection dump arguments start neither with "
564 << kStartCustomCollectionFlag << " nor with "
565 << kEndCustomCollectionFlag << " flags";
566 }
567
onDump(int fd) const568 Result<void> WatchdogPerfService::onDump(int fd) const {
569 Mutex::Autolock lock(mMutex);
570 if (mCurrCollectionEvent == EventType::TERMINATED) {
571 ALOGW("%s not active. Dumping cached data", kServiceName);
572 if (!WriteStringToFd(StringPrintf("%s not active. Dumping cached data.", kServiceName),
573 fd)) {
574 return Error(FAILED_TRANSACTION) << "Failed to write " << kServiceName << " status";
575 }
576 }
577
578 if (const auto& result = dumpCollectorsStatusLocked(fd); !result.ok()) {
579 return Error(FAILED_TRANSACTION) << result.error();
580 }
581
582 if (!WriteStringToFd(StringPrintf("\n%s%s report:\n%sBoot-time collection information:\n%s\n",
583 kDumpMajorDelimiter.c_str(), kServiceName,
584 kDumpMajorDelimiter.c_str(), std::string(33, '=').c_str()),
585 fd) ||
586 !WriteStringToFd(mBoottimeCollection.toString(), fd) ||
587 !WriteStringToFd(StringPrintf("\nWake-up collection information:\n%s\n",
588 std::string(31, '=').c_str()),
589 fd) ||
590 !WriteStringToFd(mWakeUpCollection.toString(), fd) ||
591 !WriteStringToFd(StringPrintf("\nUser-switch collection information:\n%s\n",
592 std::string(35, '=').c_str()),
593 fd) ||
594 !WriteStringToFd(mUserSwitchCollection.toString(), fd) ||
595 !WriteStringToFd(StringPrintf("\nPeriodic collection information:\n%s\n",
596 std::string(32, '=').c_str()),
597 fd) ||
598 !WriteStringToFd(mPeriodicCollection.toString(), fd)) {
599 return Error(FAILED_TRANSACTION)
600 << "Failed to dump the boot-time and periodic collection reports.";
601 }
602
603 for (const auto& processor : mDataProcessors) {
604 if (const auto result = processor->onDump(fd); !result.ok()) {
605 return result;
606 }
607 }
608
609 WriteStringToFd(kDumpMajorDelimiter, fd);
610 return {};
611 }
612
onDumpProto(ProtoOutputStream & outProto) const613 Result<void> WatchdogPerfService::onDumpProto(ProtoOutputStream& outProto) const {
614 Mutex::Autolock lock(mMutex);
615 if (mCurrCollectionEvent == EventType::TERMINATED) {
616 ALOGW("%s not active. Dumping cached data", kServiceName);
617 }
618
619 uint64_t performanceProfilerDumpToken =
620 outProto.start(CarWatchdogDaemonDump::PERFORMANCE_PROFILER_DUMP);
621
622 outProto.write(PerformanceProfilerDump::CURRENT_EVENT, toProtoEventType(mCurrCollectionEvent));
623
624 DataProcessorInterface::CollectionIntervals collectionIntervals =
625 {.mBoottimeIntervalMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
626 mBoottimeCollection.pollingIntervalNs),
627 .mPeriodicIntervalMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
628 mPeriodicCollection.pollingIntervalNs),
629 .mUserSwitchIntervalMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
630 mUserSwitchCollection.pollingIntervalNs),
631 .mWakeUpIntervalMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
632 mWakeUpCollection.pollingIntervalNs),
633 .mCustomIntervalMillis = std::chrono::duration_cast<std::chrono::milliseconds>(
634 mCustomCollection.pollingIntervalNs)};
635
636 // Populate Performance Stats
637 for (const auto& processor : mDataProcessors) {
638 processor->onDumpProto(collectionIntervals, outProto);
639 }
640
641 outProto.end(performanceProfilerDumpToken);
642
643 return {};
644 }
645
dumpHelpText(int fd) const646 bool WatchdogPerfService::dumpHelpText(int fd) const {
647 return WriteStringToFd(StringPrintf(kHelpText, kServiceName, kStartCustomCollectionFlag,
648 kIntervalFlag,
649 std::chrono::duration_cast<std::chrono::seconds>(
650 kCustomCollectionInterval)
651 .count(),
652 kMaxDurationFlag,
653 std::chrono::duration_cast<std::chrono::minutes>(
654 kCustomCollectionDuration)
655 .count(),
656 kFilterPackagesFlag, kEndCustomCollectionFlag),
657 fd);
658 }
659
dumpCollectorsStatusLocked(int fd) const660 Result<void> WatchdogPerfService::dumpCollectorsStatusLocked(int fd) const {
661 if (!mUidStatsCollector->enabled() &&
662 !WriteStringToFd(StringPrintf("UidStatsCollector failed to access proc and I/O files"),
663 fd)) {
664 return Error() << "Failed to write UidStatsCollector status";
665 }
666 if (!mProcStatCollector->enabled() &&
667 !WriteStringToFd(StringPrintf("ProcStat collector failed to access the file %s",
668 mProcStatCollector->filePath().c_str()),
669 fd)) {
670 return Error() << "Failed to write ProcStat collector status";
671 }
672 return {};
673 }
674
startCustomCollection(std::chrono::nanoseconds interval,std::chrono::nanoseconds maxDuration,const std::unordered_set<std::string> & filterPackages)675 Result<void> WatchdogPerfService::startCustomCollection(
676 std::chrono::nanoseconds interval, std::chrono::nanoseconds maxDuration,
677 const std::unordered_set<std::string>& filterPackages) {
678 if (interval < kMinEventInterval || maxDuration < kMinEventInterval) {
679 return Error(INVALID_OPERATION)
680 << "Collection polling interval and maximum duration must be >= "
681 << std::chrono::duration_cast<std::chrono::milliseconds>(kMinEventInterval).count()
682 << " milliseconds";
683 }
684 Mutex::Autolock lock(mMutex);
685 if (mCurrCollectionEvent == EventType::CUSTOM_COLLECTION) {
686 return Error(INVALID_OPERATION) << "Cannot start custom collection more than once";
687 }
688 nsecs_t now = mHandlerLooper->now();
689 mCustomCollection = {
690 .eventType = EventType::CUSTOM_COLLECTION,
691 .pollingIntervalNs = interval,
692 .lastPollUptimeNs = now,
693 .filterPackages = filterPackages,
694 };
695
696 auto thiz = sp<WatchdogPerfService>::fromExisting(this);
697 mHandlerLooper->removeMessages(thiz);
698 mHandlerLooper->sendMessageAtTime(now + maxDuration.count(), thiz,
699 SwitchMessage::END_CUSTOM_COLLECTION);
700 mCurrCollectionEvent = EventType::CUSTOM_COLLECTION;
701 mHandlerLooper->sendMessage(thiz, EventType::CUSTOM_COLLECTION);
702 ALOGI("Starting %s performance data collection", toString(mCurrCollectionEvent));
703 return {};
704 }
705
endCustomCollection(int fd)706 Result<void> WatchdogPerfService::endCustomCollection(int fd) {
707 Mutex::Autolock lock(mMutex);
708 if (mCurrCollectionEvent != EventType::CUSTOM_COLLECTION) {
709 return Error(INVALID_OPERATION) << "No custom collection is running";
710 }
711
712 auto thiz = sp<WatchdogPerfService>::fromExisting(this);
713 mHandlerLooper->removeMessages(thiz);
714 mHandlerLooper->sendMessage(thiz, SwitchMessage::END_CUSTOM_COLLECTION);
715
716 if (const auto result = dumpCollectorsStatusLocked(fd); !result.ok()) {
717 return Error(FAILED_TRANSACTION) << result.error();
718 }
719
720 if (!WriteStringToFd(StringPrintf("%sPerformance data report for custom collection:\n%s",
721 kDumpMajorDelimiter.c_str(), kDumpMajorDelimiter.c_str()),
722 fd) ||
723 !WriteStringToFd(mCustomCollection.toString(), fd)) {
724 return Error(FAILED_TRANSACTION) << "Failed to write custom collection report.";
725 }
726
727 for (const auto& processor : mDataProcessors) {
728 if (const auto result = processor->onCustomCollectionDump(fd); !result.ok()) {
729 return Error(FAILED_TRANSACTION)
730 << processor->name() << " failed on " << toString(mCurrCollectionEvent)
731 << " collection: " << result.error();
732 }
733 }
734
735 if (DEBUG) {
736 ALOGD("Custom event finished");
737 }
738 WriteStringToFd(kDumpMajorDelimiter, fd);
739 return {};
740 }
741
switchToPeriodicLocked(bool startNow)742 void WatchdogPerfService::switchToPeriodicLocked(bool startNow) {
743 if (mCurrCollectionEvent == EventType::PERIODIC_COLLECTION) {
744 ALOGW("The current performance data collection event is already %s",
745 toString(mCurrCollectionEvent));
746 return;
747 }
748 auto thiz = sp<WatchdogPerfService>::fromExisting(this);
749 mHandlerLooper->removeMessages(thiz);
750 mCurrCollectionEvent = EventType::PERIODIC_COLLECTION;
751 mPeriodicCollection.lastPollUptimeNs = mHandlerLooper->now();
752 if (startNow) {
753 mHandlerLooper->sendMessage(thiz, EventType::PERIODIC_COLLECTION);
754 } else {
755 mPeriodicCollection.lastPollUptimeNs += mPeriodicCollection.pollingIntervalNs.count();
756 mHandlerLooper->sendMessageAtTime(mPeriodicCollection.lastPollUptimeNs, thiz,
757 EventType::PERIODIC_COLLECTION);
758 }
759 mPeriodicMonitor.lastPollUptimeNs =
760 mHandlerLooper->now() + mPeriodicMonitor.pollingIntervalNs.count();
761 mHandlerLooper->sendMessageAtTime(mPeriodicMonitor.lastPollUptimeNs, thiz,
762 EventType::PERIODIC_MONITOR);
763 ALOGI("Switching to %s and %s", toString(mCurrCollectionEvent),
764 toString(EventType::PERIODIC_MONITOR));
765 }
766
handleMessage(const Message & message)767 void WatchdogPerfService::handleMessage(const Message& message) {
768 Result<void> result;
769
770 switch (message.what) {
771 case static_cast<int>(EventType::BOOT_TIME_COLLECTION):
772 result = processCollectionEvent(&mBoottimeCollection);
773 break;
774 case static_cast<int>(SwitchMessage::END_BOOTTIME_COLLECTION):
775 mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
776 if (result = processCollectionEvent(&mBoottimeCollection); result.ok()) {
777 Mutex::Autolock lock(mMutex);
778 switchToPeriodicLocked(/*startNow=*/false);
779 }
780 break;
781 case static_cast<int>(EventType::PERIODIC_COLLECTION):
782 result = processCollectionEvent(&mPeriodicCollection);
783 break;
784 case static_cast<int>(EventType::USER_SWITCH_COLLECTION):
785 result = processCollectionEvent(&mUserSwitchCollection);
786 break;
787 case static_cast<int>(EventType::WAKE_UP_COLLECTION):
788 result = processCollectionEvent(&mWakeUpCollection);
789 break;
790 case static_cast<int>(SwitchMessage::END_USER_SWITCH_COLLECTION):
791 case static_cast<int>(SwitchMessage::END_WAKE_UP_COLLECTION): {
792 mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
793 EventMetadata* eventMetadata =
794 message.what == static_cast<int>(SwitchMessage::END_USER_SWITCH_COLLECTION)
795 ? &mUserSwitchCollection
796 : &mWakeUpCollection;
797 if (result = processCollectionEvent(eventMetadata); result.ok()) {
798 Mutex::Autolock lock(mMutex);
799 switchToPeriodicLocked(/*startNow=*/false);
800 }
801 break;
802 }
803 case static_cast<int>(EventType::CUSTOM_COLLECTION):
804 result = processCollectionEvent(&mCustomCollection);
805 break;
806 case static_cast<int>(EventType::PERIODIC_MONITOR):
807 result = processMonitorEvent(&mPeriodicMonitor);
808 break;
809 case static_cast<int>(SwitchMessage::END_CUSTOM_COLLECTION): {
810 Mutex::Autolock lock(mMutex);
811 if (EventType expected = EventType::CUSTOM_COLLECTION;
812 mCurrCollectionEvent != expected) {
813 ALOGW("Skipping END_CUSTOM_COLLECTION message as the current collection %s != %s",
814 toString(mCurrCollectionEvent), toString(expected));
815 return;
816 }
817 mCustomCollection = {};
818 for (const auto& processor : mDataProcessors) {
819 /*
820 * Clear custom collection cache on the data processors when the custom collection
821 * ends.
822 */
823 processor->onCustomCollectionDump(-1);
824 }
825 switchToPeriodicLocked(/*startNow=*/true);
826 return;
827 }
828 case static_cast<int>(TaskMessage::SEND_RESOURCE_STATS):
829 result = sendResourceStats();
830 break;
831 default:
832 result = Error() << "Unknown message: " << message.what;
833 }
834
835 if (!result.ok()) {
836 Mutex::Autolock lock(mMutex);
837 ALOGE("Terminating %s: %s", kServiceName, result.error().message().c_str());
838 /*
839 * DO NOT CALL terminate() as it tries to join the collection thread but this code is
840 * executed on the collection thread. Thus it will result in a deadlock.
841 */
842 mCurrCollectionEvent = EventType::TERMINATED;
843 mHandlerLooper->removeMessages(sp<WatchdogPerfService>::fromExisting(this));
844 mHandlerLooper->wake();
845 }
846 }
847
processCollectionEvent(WatchdogPerfService::EventMetadata * metadata)848 Result<void> WatchdogPerfService::processCollectionEvent(
849 WatchdogPerfService::EventMetadata* metadata) {
850 Mutex::Autolock lock(mMutex);
851 /*
852 * Messages sent to the looper are intrinsically racy such that a message from the previous
853 * collection event may land in the looper after the current collection has already begun. Thus
854 * verify the current collection event before starting the collection.
855 */
856 if (mCurrCollectionEvent != metadata->eventType) {
857 ALOGW("Skipping %s event on collection event %s", toString(metadata->eventType),
858 toString(mCurrCollectionEvent));
859 return {};
860 }
861 if (DEBUG) {
862 ALOGD("Processing %s collection event", toString(metadata->eventType));
863 }
864 if (metadata->pollingIntervalNs < kMinEventInterval) {
865 return Error()
866 << "Collection polling interval of "
867 << std::chrono::duration_cast<std::chrono::seconds>(metadata->pollingIntervalNs)
868 .count()
869 << " seconds for " << toString(metadata->eventType)
870 << " collection cannot be less than "
871 << std::chrono::duration_cast<std::chrono::seconds>(kMinEventInterval).count()
872 << " seconds";
873 }
874 if (const auto result = collectLocked(metadata); !result.ok()) {
875 return Error() << toString(metadata->eventType) << " collection failed: " << result.error();
876 }
877 metadata->lastPollUptimeNs += metadata->pollingIntervalNs.count();
878 mHandlerLooper->sendMessageAtTime(metadata->lastPollUptimeNs,
879 sp<WatchdogPerfService>::fromExisting(this),
880 metadata->eventType);
881 return {};
882 }
883
collectLocked(WatchdogPerfService::EventMetadata * metadata)884 Result<void> WatchdogPerfService::collectLocked(WatchdogPerfService::EventMetadata* metadata) {
885 if (!mUidStatsCollector->enabled() && !mProcStatCollector->enabled()) {
886 return Error() << "No collectors enabled";
887 }
888
889 auto now = std::chrono::time_point_cast<std::chrono::milliseconds>(
890 std::chrono::system_clock::now());
891 int64_t timeSinceBootMillis = kGetElapsedTimeSinceBootMillisFunc();
892
893 if (mUidStatsCollector->enabled()) {
894 if (const auto result = mUidStatsCollector->collect(); !result.ok()) {
895 return Error() << "Failed to collect per-uid proc and I/O stats: " << result.error();
896 }
897 }
898
899 if (mProcStatCollector->enabled()) {
900 if (const auto result = mProcStatCollector->collect(); !result.ok()) {
901 return Error() << "Failed to collect proc stats: " << result.error();
902 }
903 }
904
905 ResourceStats resourceStats = {};
906
907 for (const auto& processor : mDataProcessors) {
908 Result<void> result;
909 switch (mCurrCollectionEvent) {
910 case EventType::BOOT_TIME_COLLECTION:
911 result = processor->onBoottimeCollection(now, mUidStatsCollector,
912 mProcStatCollector, &resourceStats);
913 break;
914 case EventType::PERIODIC_COLLECTION:
915 result = processor->onPeriodicCollection(now, mSystemState, mUidStatsCollector,
916 mProcStatCollector, &resourceStats);
917 break;
918 case EventType::USER_SWITCH_COLLECTION: {
919 WatchdogPerfService::UserSwitchEventMetadata* userSwitchMetadata =
920 static_cast<WatchdogPerfService::UserSwitchEventMetadata*>(metadata);
921 result = processor->onUserSwitchCollection(now, userSwitchMetadata->from,
922 userSwitchMetadata->to,
923 mUidStatsCollector, mProcStatCollector);
924 break;
925 }
926 case EventType::WAKE_UP_COLLECTION:
927 result = processor->onWakeUpCollection(now, mUidStatsCollector, mProcStatCollector);
928 break;
929 case EventType::CUSTOM_COLLECTION:
930 result = processor->onCustomCollection(now, mSystemState, metadata->filterPackages,
931 mUidStatsCollector, mProcStatCollector,
932 &resourceStats);
933 break;
934 default:
935 result = Error() << "Invalid collection event " << toString(mCurrCollectionEvent);
936 }
937 if (!result.ok()) {
938 return Error() << processor->name() << " failed on " << toString(mCurrCollectionEvent)
939 << " collection: " << result.error();
940 }
941 }
942
943 if (!isEmpty(resourceStats)) {
944 if (resourceStats.resourceUsageStats.has_value()) {
945 resourceStats.resourceUsageStats->durationInMillis =
946 timeSinceBootMillis - mLastCollectionTimeMillis;
947 }
948 cacheUnsentResourceStatsLocked(std::move(resourceStats));
949 }
950
951 mLastCollectionTimeMillis = timeSinceBootMillis;
952
953 if (mUnsentResourceStats.empty() || !mWatchdogServiceHelper->isServiceConnected()) {
954 if (DEBUG && !mWatchdogServiceHelper->isServiceConnected()) {
955 ALOGD("Cannot send resource stats since CarWatchdogService not connected.");
956 }
957 return {};
958 }
959
960 // Send message to send resource stats
961 mHandlerLooper->sendMessage(sp<WatchdogPerfService>::fromExisting(this),
962 TaskMessage::SEND_RESOURCE_STATS);
963
964 return {};
965 }
966
processMonitorEvent(WatchdogPerfService::EventMetadata * metadata)967 Result<void> WatchdogPerfService::processMonitorEvent(
968 WatchdogPerfService::EventMetadata* metadata) {
969 if (metadata->eventType != static_cast<int>(EventType::PERIODIC_MONITOR)) {
970 return Error() << "Invalid monitor event " << toString(metadata->eventType);
971 }
972 if (DEBUG) {
973 ALOGD("Processing %s monitor event", toString(metadata->eventType));
974 }
975 if (metadata->pollingIntervalNs < kMinEventInterval) {
976 return Error()
977 << "Monitor polling interval of "
978 << std::chrono::duration_cast<std::chrono::seconds>(metadata->pollingIntervalNs)
979 .count()
980 << " seconds for " << toString(metadata->eventType) << " event cannot be less than "
981 << std::chrono::duration_cast<std::chrono::seconds>(kMinEventInterval).count()
982 << " seconds";
983 }
984 Mutex::Autolock lock(mMutex);
985 if (!mProcDiskStatsCollector->enabled()) {
986 return Error() << "Cannot access proc disk stats for monitoring";
987 }
988 time_t now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
989 if (const auto result = mProcDiskStatsCollector->collect(); !result.ok()) {
990 return Error() << "Failed to collect disk stats: " << result.error();
991 }
992 auto* currCollectionMetadata = getCurrentCollectionMetadataLocked();
993 if (currCollectionMetadata == nullptr) {
994 return Error() << "No metadata available for current collection event: "
995 << toString(mCurrCollectionEvent);
996 }
997 bool requestedCollection = false;
998 auto thiz = sp<WatchdogPerfService>::fromExisting(this);
999 const auto requestCollection = [&]() mutable {
1000 if (requestedCollection) {
1001 return;
1002 }
1003 const nsecs_t prevUptimeNs = currCollectionMetadata->lastPollUptimeNs -
1004 currCollectionMetadata->pollingIntervalNs.count();
1005 nsecs_t uptimeNs = mHandlerLooper->now();
1006 if (const auto delta = std::abs(uptimeNs - prevUptimeNs);
1007 delta < kMinEventInterval.count()) {
1008 return;
1009 }
1010 currCollectionMetadata->lastPollUptimeNs = uptimeNs;
1011 mHandlerLooper->removeMessages(thiz, currCollectionMetadata->eventType);
1012 mHandlerLooper->sendMessage(thiz, currCollectionMetadata->eventType);
1013 requestedCollection = true;
1014 };
1015 for (const auto& processor : mDataProcessors) {
1016 if (const auto result =
1017 processor->onPeriodicMonitor(now, mProcDiskStatsCollector, requestCollection);
1018 !result.ok()) {
1019 return Error() << processor->name() << " failed on " << toString(metadata->eventType)
1020 << ": " << result.error();
1021 }
1022 }
1023 metadata->lastPollUptimeNs += metadata->pollingIntervalNs.count();
1024 if (metadata->lastPollUptimeNs == currCollectionMetadata->lastPollUptimeNs) {
1025 /*
1026 * If the |PERIODIC_MONITOR| and *_COLLECTION events overlap, skip the |PERIODIC_MONITOR|
1027 * event.
1028 */
1029 metadata->lastPollUptimeNs += metadata->pollingIntervalNs.count();
1030 }
1031 mHandlerLooper->sendMessageAtTime(metadata->lastPollUptimeNs, thiz, metadata->eventType);
1032 return {};
1033 }
1034
sendResourceStats()1035 Result<void> WatchdogPerfService::sendResourceStats() {
1036 std::vector<ResourceStats> unsentResourceStats = {};
1037 {
1038 Mutex::Autolock lock(mMutex);
1039 nsecs_t now = mHandlerLooper->now();
1040 for (auto it = mUnsentResourceStats.begin(); it != mUnsentResourceStats.end();) {
1041 if (now - std::get<nsecs_t>(*it) >= kPrevUnsentResourceStatsMaxDurationNs.count()) {
1042 // Drop the expired stats
1043 it = mUnsentResourceStats.erase(it);
1044 continue;
1045 }
1046 unsentResourceStats.push_back(std::get<ResourceStats>(*it));
1047 ++it;
1048 }
1049 }
1050 if (unsentResourceStats.empty()) {
1051 return {};
1052 }
1053 if (auto status = mWatchdogServiceHelper->onLatestResourceStats(unsentResourceStats);
1054 !status.isOk()) {
1055 ALOGW("Failed to push the unsent resource stats to watchdog service: %s",
1056 status.getDescription().c_str());
1057 return {};
1058 }
1059 Mutex::Autolock lock(mMutex);
1060 mUnsentResourceStats.clear();
1061 if (DEBUG) {
1062 ALOGD("Pushed latest resource usage and I/O overuse stats to watchdog service");
1063 }
1064 return {};
1065 }
1066
notifySystemStartUpLocked()1067 Result<void> WatchdogPerfService::notifySystemStartUpLocked() {
1068 for (const auto& processor : mDataProcessors) {
1069 if (const auto result = processor->onSystemStartup(); !result.ok()) {
1070 ALOGE("%s failed to process system startup event", processor->name().c_str());
1071 return Error() << processor->name() << " failed to process system startup event";
1072 }
1073 }
1074 return {};
1075 }
1076
cacheUnsentResourceStatsLocked(ResourceStats resourceStats)1077 void WatchdogPerfService::cacheUnsentResourceStatsLocked(ResourceStats resourceStats) {
1078 mUnsentResourceStats.push_back(
1079 std::make_tuple(mHandlerLooper->now(), std::move(resourceStats)));
1080 if (mUnsentResourceStats.size() > kMaxCachedUnsentResourceStats) {
1081 mUnsentResourceStats.erase(mUnsentResourceStats.begin());
1082 }
1083 }
1084
getCurrentCollectionMetadataLocked()1085 WatchdogPerfService::EventMetadata* WatchdogPerfService::getCurrentCollectionMetadataLocked() {
1086 switch (mCurrCollectionEvent) {
1087 case EventType::BOOT_TIME_COLLECTION:
1088 return &mBoottimeCollection;
1089 case EventType::PERIODIC_COLLECTION:
1090 return &mPeriodicCollection;
1091 case EventType::USER_SWITCH_COLLECTION:
1092 return &mUserSwitchCollection;
1093 case EventType::WAKE_UP_COLLECTION:
1094 return &mWakeUpCollection;
1095 case EventType::CUSTOM_COLLECTION:
1096 return &mCustomCollection;
1097 default:
1098 return nullptr;
1099 }
1100 }
1101
1102 } // namespace watchdog
1103 } // namespace automotive
1104 } // namespace android
1105