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