1 /*
2  * Copyright 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 #include "MockPressureMonitor.h"
18 #include "MockProcStatCollector.h"
19 #include "MockUidStatsCollector.h"
20 #include "MockWatchdogServiceHelper.h"
21 #include "PackageInfoTestUtils.h"
22 #include "PerformanceProfiler.h"
23 
24 #include <WatchdogProperties.sysprop.h>
25 #include <android-base/file.h>
26 #include <gmock/gmock.h>
27 #include <utils/RefBase.h>
28 
29 #include <android_car_feature.h>
30 #include <sys/types.h>
31 #include <unistd.h>
32 
33 #include <algorithm>
34 #include <string>
35 #include <type_traits>
36 #include <vector>
37 
38 #include <carwatchdog_daemon_dump.pb.h>
39 #include <performance_stats.pb.h>
40 
41 namespace android {
42 namespace automotive {
43 namespace watchdog {
44 
45 namespace {
46 
47 using ::aidl::android::automotive::watchdog::internal::ResourceStats;
48 using ::aidl::android::automotive::watchdog::internal::ResourceUsageStats;
49 using ::aidl::android::automotive::watchdog::internal::UidResourceUsageStats;
50 using ::android::RefBase;
51 using ::android::sp;
52 using ::android::base::ReadFdToString;
53 using ::android::base::Result;
54 using ::android::base::StringAppendF;
55 using ::android::car::feature::car_watchdog_memory_profiling;
56 using ::android::util::ProtoReader;
57 using ::google::protobuf::RepeatedPtrField;
58 using ::testing::_;
59 using ::testing::AllOf;
60 using ::testing::ElementsAreArray;
61 using ::testing::Eq;
62 using ::testing::ExplainMatchResult;
63 using ::testing::Field;
64 using ::testing::IsSubsetOf;
65 using ::testing::Matcher;
66 using ::testing::Pointer;
67 using ::testing::Property;
68 using ::testing::Return;
69 using ::testing::Test;
70 using ::testing::UnorderedElementsAreArray;
71 using ::testing::VariantWith;
72 
73 using PressureLevelDurationPair = std::pair<PressureMonitorInterface::PressureLevel, int64_t>;
74 using PressureLevelTransitions = std::vector<PressureLevelDurationPair>;
75 using PressureLevelDurations =
76         std::unordered_map<PressureMonitorInterface::PressureLevel, std::chrono::milliseconds>;
77 
78 constexpr int kTestBaseUserId = 100;
79 constexpr bool kTestIsSmapsRollupSupported = true;
80 constexpr int kTestTopNStatsPerCategory = 5;
81 constexpr int kTestTopNStatsPerSubcategory = 5;
82 constexpr int kTestMaxUserSwitchEvents = 3;
83 constexpr size_t kTestPeriodicCollectionBufferSize = 3;
84 constexpr std::chrono::seconds kTestSystemEventDataCacheDurationSec = 60s;
85 const auto kTestNowMillis = std::chrono::time_point_cast<std::chrono::milliseconds>(
86         std::chrono::system_clock::from_time_t(1'683'270'000));
87 constexpr int64_t kTestElapsedRealtimeSinceBootMillis = 19'000;
88 
applyFeatureFilter(UserPackageSummaryStats * userPackageSummaryStatsOut)89 void applyFeatureFilter(UserPackageSummaryStats* userPackageSummaryStatsOut) {
90     if (car_watchdog_memory_profiling()) {
91         return;
92     }
93     userPackageSummaryStatsOut->totalRssKb = 0;
94     userPackageSummaryStatsOut->totalPssKb = 0;
95     userPackageSummaryStatsOut->topNMemStats = {};
96 }
97 
98 MATCHER_P(IoStatsViewEq, expected, "") {
99     return ExplainMatchResult(AllOf(Field("bytes", &UserPackageStats::IoStatsView::bytes,
100                                           ElementsAreArray(expected.bytes)),
101                                     Field("fsync", &UserPackageStats::IoStatsView::fsync,
102                                           ElementsAreArray(expected.fsync))),
103                               arg, result_listener);
104 }
105 
106 MATCHER_P(ProcessValueEq, expected, "") {
107     return ExplainMatchResult(AllOf(Field("comm",
108                                           &UserPackageStats::ProcSingleStatsView::ProcessValue::
109                                                   comm,
110                                           Eq(expected.comm)),
111                                     Field("value",
112                                           &UserPackageStats::ProcSingleStatsView::ProcessValue::
113                                                   value,
114                                           Eq(expected.value))),
115                               arg, result_listener);
116 }
117 
118 MATCHER_P(ProcSingleStatsViewEq, expected, "") {
119     std::vector<Matcher<const UserPackageStats::ProcSingleStatsView::ProcessValue&>>
120             processValueMatchers;
121     processValueMatchers.reserve(expected.topNProcesses.size());
122     for (const auto& processValue : expected.topNProcesses) {
123         processValueMatchers.push_back(ProcessValueEq(processValue));
124     }
125     return ExplainMatchResult(AllOf(Field("value", &UserPackageStats::ProcSingleStatsView::value,
126                                           Eq(expected.value)),
127                                     Field("topNProcesses",
128                                           &UserPackageStats::ProcSingleStatsView::topNProcesses,
129                                           ElementsAreArray(processValueMatchers))),
130                               arg, result_listener);
131 }
132 
133 MATCHER_P(ProcessCpuValueEq, expected, "") {
134     return ExplainMatchResult(AllOf(Field("pid",
135                                           &UserPackageStats::ProcCpuStatsView::ProcessCpuValue::pid,
136                                           Eq(expected.pid)),
137                                     Field("comm",
138                                           &UserPackageStats::ProcCpuStatsView::ProcessCpuValue::
139                                                   comm,
140                                           Eq(expected.comm)),
141                                     Field("cpuTimeMillis",
142                                           &UserPackageStats::ProcCpuStatsView::ProcessCpuValue::
143                                                   cpuTimeMillis,
144                                           Eq(expected.cpuTimeMillis)),
145                                     Field("cpuCycles",
146                                           &UserPackageStats::ProcCpuStatsView::ProcessCpuValue::
147                                                   cpuCycles,
148                                           Eq(expected.cpuCycles))),
149                               arg, result_listener);
150 }
151 
152 MATCHER_P(ProcCpuStatsViewEq, expected, "") {
153     std::vector<Matcher<const UserPackageStats::ProcCpuStatsView::ProcessCpuValue&>>
154             processValueMatchers;
155     processValueMatchers.reserve(expected.topNProcesses.size());
156     for (const auto& processValue : expected.topNProcesses) {
157         processValueMatchers.push_back(ProcessCpuValueEq(processValue));
158     }
159     return ExplainMatchResult(AllOf(Field("cpuTimeMillis",
160                                           &UserPackageStats::ProcCpuStatsView::cpuTimeMillis,
161                                           Eq(expected.cpuTimeMillis)),
162                                     Field("cpuCycles",
163                                           &UserPackageStats::ProcCpuStatsView::cpuCycles,
164                                           Eq(expected.cpuCycles)),
165                                     Field("topNProcesses",
166                                           &UserPackageStats::ProcCpuStatsView::topNProcesses,
167                                           ElementsAreArray(processValueMatchers))),
168                               arg, result_listener);
169 }
170 
171 MATCHER_P(MemoryStatsEq, expected, "") {
172     return ExplainMatchResult(AllOf(Field("rssKb", &UserPackageStats::MemoryStats::rssKb,
173                                           Eq(expected.rssKb)),
174                                     Field("pssKb", &UserPackageStats::MemoryStats::pssKb,
175                                           Eq(expected.pssKb)),
176                                     Field("ussKb", &UserPackageStats::MemoryStats::ussKb,
177                                           Eq(expected.ussKb)),
178                                     Field("swapPssKb", &UserPackageStats::MemoryStats::swapPssKb,
179                                           Eq(expected.swapPssKb))),
180                               arg, result_listener);
181 }
182 
183 MATCHER_P(ProcessMemoryStatsEq, expected, "") {
184     return ExplainMatchResult(AllOf(Field("comm",
185                                           &UserPackageStats::UidMemoryStats::ProcessMemoryStats::
186                                                   comm,
187                                           Eq(expected.comm)),
188                                     Field("memoryStats",
189                                           &UserPackageStats::UidMemoryStats::ProcessMemoryStats::
190                                                   memoryStats,
191                                           MemoryStatsEq(expected.memoryStats))),
192                               arg, result_listener);
193 }
194 
195 MATCHER_P(UidMemoryStatsEq, expected, "") {
196     std::vector<Matcher<const UserPackageStats::UidMemoryStats::ProcessMemoryStats&>>
197             processValueMatchers;
198     processValueMatchers.reserve(expected.topNProcesses.size());
199     for (const auto& processValue : expected.topNProcesses) {
200         processValueMatchers.push_back(ProcessMemoryStatsEq(processValue));
201     }
202     return ExplainMatchResult(AllOf(Field("memoryStats",
203                                           &UserPackageStats::UidMemoryStats::memoryStats,
204                                           MemoryStatsEq(expected.memoryStats)),
205                                     Field("isSmapsRollupSupported",
206                                           &UserPackageStats::UidMemoryStats::isSmapsRollupSupported,
207                                           Eq(expected.isSmapsRollupSupported)),
208                                     Field("topNProcesses",
209                                           &UserPackageStats::UidMemoryStats::topNProcesses,
210                                           ElementsAreArray(processValueMatchers))),
211                               arg, result_listener);
212 }
213 
214 MATCHER_P(UserPackageStatsEq, expected, "") {
215     const auto uidMatcher = Field("uid", &UserPackageStats::uid, Eq(expected.uid));
216     const auto packageNameMatcher =
217             Field("genericPackageName", &UserPackageStats::genericPackageName,
218                   Eq(expected.genericPackageName));
219     return std::visit(
__anon725ac8c50202(const auto& statsView) 220             [&](const auto& statsView) -> bool {
221                 using T = std::decay_t<decltype(statsView)>;
222                 if constexpr (std::is_same_v<T, UserPackageStats::IoStatsView>) {
223                     return ExplainMatchResult(AllOf(uidMatcher, packageNameMatcher,
224                                                     Field("statsView:IoStatsView",
225                                                           &UserPackageStats::statsView,
226                                                           VariantWith<
227                                                                   UserPackageStats::IoStatsView>(
228                                                                   IoStatsViewEq(statsView)))),
229                                               arg, result_listener);
230                 } else if constexpr (std::is_same_v<T, UserPackageStats::ProcSingleStatsView>) {
231                     return ExplainMatchResult(AllOf(uidMatcher, packageNameMatcher,
232                                                     Field("statsView:ProcSingleStatsView",
233                                                           &UserPackageStats::statsView,
234                                                           VariantWith<UserPackageStats::
235                                                                               ProcSingleStatsView>(
236                                                                   ProcSingleStatsViewEq(
237                                                                           statsView)))),
238                                               arg, result_listener);
239                 } else if constexpr (std::is_same_v<T, UserPackageStats::ProcCpuStatsView>) {
240                     return ExplainMatchResult(AllOf(uidMatcher, packageNameMatcher,
241                                                     Field("statsView:ProcCpuStatsView",
242                                                           &UserPackageStats::statsView,
243                                                           VariantWith<UserPackageStats::
244                                                                               ProcCpuStatsView>(
245                                                                   ProcCpuStatsViewEq(statsView)))),
246                                               arg, result_listener);
247                 } else if constexpr (std::is_same_v<T, UserPackageStats::UidMemoryStats>) {
248                     return ExplainMatchResult(AllOf(uidMatcher, packageNameMatcher,
249                                                     Field("statsView:UidMemoryStats",
250                                                           &UserPackageStats::statsView,
251                                                           VariantWith<
252                                                                   UserPackageStats::UidMemoryStats>(
253                                                                   UidMemoryStatsEq(statsView)))),
254                                               arg, result_listener);
255                 }
256                 *result_listener << "Unexpected variant in UserPackageStats::stats";
257                 return false;
258             },
259             expected.statsView);
260 }
261 
262 MATCHER_P(UserPackageSummaryStatsEq, expected, "") {
__anon725ac8c50302(const std::vector<UserPackageStats>& stats) 263     const auto& userPackageStatsMatchers = [&](const std::vector<UserPackageStats>& stats) {
264         std::vector<Matcher<const UserPackageStats&>> matchers;
265         for (const auto& curStats : stats) {
266             matchers.push_back(UserPackageStatsEq(curStats));
267         }
268         return ElementsAreArray(matchers);
269     };
__anon725ac8c50402(const int64_t expected[][UID_STATES]) 270     const auto& totalIoStatsArrayMatcher = [&](const int64_t expected[][UID_STATES]) {
271         std::vector<Matcher<const int64_t[UID_STATES]>> matchers;
272         for (int i = 0; i < METRIC_TYPES; ++i) {
273             matchers.push_back(ElementsAreArray(expected[i], UID_STATES));
274         }
275         return ElementsAreArray(matchers);
276     };
277     return ExplainMatchResult(AllOf(Field("topNCpuTimes", &UserPackageSummaryStats::topNCpuTimes,
278                                           userPackageStatsMatchers(expected.topNCpuTimes)),
279                                     Field("topNIoReads", &UserPackageSummaryStats::topNIoReads,
280                                           userPackageStatsMatchers(expected.topNIoReads)),
281                                     Field("topNIoWrites", &UserPackageSummaryStats::topNIoWrites,
282                                           userPackageStatsMatchers(expected.topNIoWrites)),
283                                     Field("topNIoBlocked", &UserPackageSummaryStats::topNIoBlocked,
284                                           userPackageStatsMatchers(expected.topNIoBlocked)),
285                                     Field("topNMajorFaults",
286                                           &UserPackageSummaryStats::topNMajorFaults,
287                                           userPackageStatsMatchers(expected.topNMajorFaults)),
288                                     Field("topNMemStats", &UserPackageSummaryStats::topNMemStats,
289                                           userPackageStatsMatchers(expected.topNMemStats)),
290                                     Field("totalIoStats", &UserPackageSummaryStats::totalIoStats,
291                                           totalIoStatsArrayMatcher(expected.totalIoStats)),
292                                     Field("taskCountByUid",
293                                           &UserPackageSummaryStats::taskCountByUid,
294                                           IsSubsetOf(expected.taskCountByUid)),
295                                     Field("totalCpuTimeMillis",
296                                           &UserPackageSummaryStats::totalCpuTimeMillis,
297                                           Eq(expected.totalCpuTimeMillis)),
298                                     Field("totalCpuCycles",
299                                           &UserPackageSummaryStats::totalCpuCycles,
300                                           Eq(expected.totalCpuCycles)),
301                                     Field("totalMajorFaults",
302                                           &UserPackageSummaryStats::totalMajorFaults,
303                                           Eq(expected.totalMajorFaults)),
304                                     Field("totalRssKb", &UserPackageSummaryStats::totalRssKb,
305                                           Eq(expected.totalRssKb)),
306                                     Field("totalPssKb", &UserPackageSummaryStats::totalPssKb,
307                                           Eq(expected.totalPssKb)),
308                                     Field("majorFaultsPercentChange",
309                                           &UserPackageSummaryStats::majorFaultsPercentChange,
310                                           Eq(expected.majorFaultsPercentChange))),
311                               arg, result_listener);
312 }
313 
314 MATCHER_P(SystemSummaryStatsEq, expected, "") {
315     return ExplainMatchResult(AllOf(Field("cpuIoWaitTimeMillis",
316                                           &SystemSummaryStats::cpuIoWaitTimeMillis,
317                                           Eq(expected.cpuIoWaitTimeMillis)),
318                                     Field("cpuIdleTimeMillis",
319                                           &SystemSummaryStats::cpuIdleTimeMillis,
320                                           Eq(expected.cpuIdleTimeMillis)),
321                                     Field("totalCpuTimeMillis",
322                                           &SystemSummaryStats::totalCpuTimeMillis,
323                                           Eq(expected.totalCpuTimeMillis)),
324                                     Field("totalCpuCycles", &SystemSummaryStats::totalCpuCycles,
325                                           Eq(expected.totalCpuCycles)),
326                                     Field("contextSwitchesCount",
327                                           &SystemSummaryStats::contextSwitchesCount,
328                                           Eq(expected.contextSwitchesCount)),
329                                     Field("ioBlockedProcessCount",
330                                           &SystemSummaryStats::ioBlockedProcessCount,
331                                           Eq(expected.ioBlockedProcessCount)),
332                                     Field("totalProcessCount",
333                                           &SystemSummaryStats::totalProcessCount,
334                                           Eq(expected.totalProcessCount))),
335                               arg, result_listener);
336 }
337 
338 MATCHER_P(PerfStatsRecordEq, expected, "") {
339     return ExplainMatchResult(AllOf(Field(&PerfStatsRecord::collectionTimeMillis,
340                                           Eq(expected.collectionTimeMillis)),
341                                     Field(&PerfStatsRecord::systemSummaryStats,
342                                           SystemSummaryStatsEq(expected.systemSummaryStats)),
343                                     Field(&PerfStatsRecord::userPackageSummaryStats,
344                                           UserPackageSummaryStatsEq(
345                                                   expected.userPackageSummaryStats)),
346                                     Field(&PerfStatsRecord::memoryPressureLevelDurations,
347                                           UnorderedElementsAreArray(
348                                                   expected.memoryPressureLevelDurations))),
349                               arg, result_listener);
350 }
351 
constructPerfStatsRecordMatchers(const std::vector<PerfStatsRecord> & records)352 const std::vector<Matcher<const PerfStatsRecord&>> constructPerfStatsRecordMatchers(
353         const std::vector<PerfStatsRecord>& records) {
354     std::vector<Matcher<const PerfStatsRecord&>> matchers;
355     for (const auto& record : records) {
356         matchers.push_back(PerfStatsRecordEq(record));
357     }
358     return matchers;
359 }
360 
361 MATCHER_P(CollectionInfoEq, expected, "") {
362     return ExplainMatchResult(AllOf(Field("maxCacheSize", &CollectionInfo::maxCacheSize,
363                                           Eq(expected.maxCacheSize)),
364                                     Field("records", &CollectionInfo::records,
365                                           ElementsAreArray(constructPerfStatsRecordMatchers(
366                                                   expected.records)))),
367                               arg, result_listener);
368 }
369 
370 MATCHER_P(UserSwitchCollectionInfoEq, expected, "") {
371     return ExplainMatchResult(AllOf(Field("from", &UserSwitchCollectionInfo::from,
372                                           Eq(expected.from)),
373                                     Field("to", &UserSwitchCollectionInfo::to, Eq(expected.to)),
374                                     Field("maxCacheSize", &UserSwitchCollectionInfo::maxCacheSize,
375                                           Eq(expected.maxCacheSize)),
376                                     Field("records", &UserSwitchCollectionInfo::records,
377                                           ElementsAreArray(constructPerfStatsRecordMatchers(
378                                                   expected.records)))),
379                               arg, result_listener);
380 }
381 
382 MATCHER_P(UserSwitchCollectionsEq, expected, "") {
383     std::vector<Matcher<const UserSwitchCollectionInfo&>> userSwitchCollectionMatchers;
384     for (const auto& curCollection : expected) {
385         userSwitchCollectionMatchers.push_back(UserSwitchCollectionInfoEq(curCollection));
386     }
387     return ExplainMatchResult(ElementsAreArray(userSwitchCollectionMatchers), arg, result_listener);
388 }
389 
countOccurrences(std::string str,std::string subStr)390 int countOccurrences(std::string str, std::string subStr) {
391     size_t pos = 0;
392     int occurrences = 0;
393     while ((pos = str.find(subStr, pos)) != std::string::npos) {
394         ++occurrences;
395         pos += subStr.length();
396     }
397     return occurrences;
398 }
399 
sampleUidStats(auto int64Multiplier,auto uint64Multiplier,bool isSmapsRollupSupported=true)400 std::tuple<std::vector<UidStats>, UserPackageSummaryStats> sampleUidStats(
401         auto int64Multiplier, auto uint64Multiplier, bool isSmapsRollupSupported = true) {
402     /* The number of returned sample stats are less that the top N stats per category/sub-category.
403      * The top N stats per category/sub-category is set to % during test setup. Thus, the default
404      * testing behavior is # reported stats < top N stats.
405      */
406     std::vector<UidStats>
407             uidStats{{.packageInfo = constructPackageInfo("mount", 1009),
408                       .cpuTimeMillis = int64Multiplier(50),
409                       .ioStats = {/*fgRdBytes=*/0,
410                                   /*bgRdBytes=*/int64Multiplier(14'000),
411                                   /*fgWrBytes=*/0,
412                                   /*bgWrBytes=*/int64Multiplier(16'000),
413                                   /*fgFsync=*/0, /*bgFsync=*/int64Multiplier(100)},
414                       .procStats = {.cpuTimeMillis = int64Multiplier(50),
415                                     .cpuCycles = 4000,
416                                     .totalMajorFaults = uint64Multiplier(11'000),
417                                     .totalTasksCount = 1,
418                                     .ioBlockedTasksCount = 1,
419                                     .totalRssKb = 2010,
420                                     .totalPssKb = 1635,
421                                     .processStatsByPid =
422                                             {{/*pid=*/100,
423                                               {/*comm=*/"disk I/O", /*startTime=*/234,
424                                                /*cpuTimeMillis=*/int64Multiplier(50),
425                                                /*totalCpuCycles=*/4000,
426                                                /*totalMajorFaults=*/uint64Multiplier(11'000),
427                                                /*totalTasksCount=*/1,
428                                                /*ioBlockedTasksCount=*/1,
429                                                /*cpuCyclesByTid=*/{{100, 4000}},
430                                                /*rssKb=*/2010, /*pssKb=*/1635,
431                                                /*ussKb=*/1286, /*swapPssKb=*/600}}}}},
432                      {.packageInfo =
433                               constructPackageInfo("com.google.android.car.kitchensink", 1002001),
434                       .cpuTimeMillis = int64Multiplier(60),
435                       .ioStats = {/*fgRdBytes=*/0,
436                                   /*bgRdBytes=*/int64Multiplier(3'400),
437                                   /*fgWrBytes=*/0,
438                                   /*bgWrBytes=*/int64Multiplier(6'700),
439                                   /*fgFsync=*/0,
440                                   /*bgFsync=*/int64Multiplier(200)},
441                       .procStats = {.cpuTimeMillis = int64Multiplier(50),
442                                     .cpuCycles = 10'000,
443                                     .totalMajorFaults = uint64Multiplier(22'445),
444                                     .totalTasksCount = 5,
445                                     .ioBlockedTasksCount = 3,
446                                     .totalRssKb = 2000,
447                                     .totalPssKb = 1645,
448                                     .processStatsByPid =
449                                             {{/*pid=*/1001,
450                                               {/*comm=*/"CTS", /*startTime=*/789,
451                                                /*cpuTimeMillis=*/int64Multiplier(30),
452                                                /*totalCpuCycles=*/5000,
453                                                /*totalMajorFaults=*/uint64Multiplier(10'100),
454                                                /*totalTasksCount=*/3,
455                                                /*ioBlockedTasksCount=*/2,
456                                                /*cpuCyclesByTid=*/{{1001, 3000}, {1002, 2000}},
457                                                /*rssKb=*/1000, /*pssKb=*/770,
458                                                /*ussKb=*/656, /*swapPssKb=*/200}},
459                                              {/*pid=*/1000,
460                                               {/*comm=*/"KitchenSinkApp", /*startTime=*/467,
461                                                /*cpuTimeMillis=*/int64Multiplier(25),
462                                                /*totalCpuCycles=*/4000,
463                                                /*totalMajorFaults=*/uint64Multiplier(12'345),
464                                                /*totalTasksCount=*/2,
465                                                /*ioBlockedTasksCount=*/1,
466                                                /*cpuCyclesByTid=*/{{1000, 4000}},
467                                                /*rssKb=*/1000, /*pssKb=*/875,
468                                                /*ussKb=*/630, /*swapPssKb=*/400}}}}},
469                      {.packageInfo = constructPackageInfo("", 1012345),
470                       .cpuTimeMillis = int64Multiplier(100),
471                       .ioStats = {/*fgRdBytes=*/int64Multiplier(1'000),
472                                   /*bgRdBytes=*/int64Multiplier(4'200),
473                                   /*fgWrBytes=*/int64Multiplier(300),
474                                   /*bgWrBytes=*/int64Multiplier(5'600),
475                                   /*fgFsync=*/int64Multiplier(600),
476                                   /*bgFsync=*/int64Multiplier(300)},
477                       .procStats = {.cpuTimeMillis = int64Multiplier(100),
478                                     .cpuCycles = 50'000,
479                                     .totalMajorFaults = uint64Multiplier(50'900),
480                                     .totalTasksCount = 4,
481                                     .ioBlockedTasksCount = 2,
482                                     .totalRssKb = 1000,
483                                     .totalPssKb = 865,
484                                     .processStatsByPid =
485                                             {{/*pid=*/2345,
486                                               {/*comm=*/"MapsApp", /*startTime=*/6789,
487                                                /*cpuTimeMillis=*/int64Multiplier(100),
488                                                /*totalCpuCycles=*/50'000,
489                                                /*totalMajorFaults=*/uint64Multiplier(50'900),
490                                                /*totalTasksCount=*/4,
491                                                /*ioBlockedTasksCount=*/2,
492                                                /*cpuCyclesByTid=*/{{2345, 50'000}},
493                                                /*rssKb=*/1000, /*pssKb=*/865,
494                                                /*ussKb=*/656, /*swapPssKb=*/200}}}}},
495                      {.packageInfo = constructPackageInfo("com.google.radio", 1015678),
496                       .cpuTimeMillis = 0,
497                       .ioStats = {/*fgRdBytes=*/0,
498                                   /*bgRdBytes=*/0,
499                                   /*fgWrBytes=*/0,
500                                   /*bgWrBytes=*/0,
501                                   /*fgFsync=*/0, /*bgFsync=*/0},
502                       .procStats = {.cpuTimeMillis = 0,
503                                     .cpuCycles = 0,
504                                     .totalMajorFaults = 0,
505                                     .totalTasksCount = 4,
506                                     .ioBlockedTasksCount = 0,
507                                     .processStatsByPid = {
508                                             {/*pid=*/2345,
509                                              {/*comm=*/"RadioApp", /*startTime=*/10789,
510                                               /*cpuTimeMillis=*/0,
511                                               /*totalCpuCycles=*/0,
512                                               /*totalMajorFaults=*/0,
513                                               /*totalTasksCount=*/4,
514                                               /*ioBlockedTasksCount=*/0,
515                                               /*cpuCyclesByTid=*/{}}}}}}};
516 
517     std::vector<UserPackageStats> topNMemStatsRankedByPss =
518             {{1002001, "com.google.android.car.kitchensink",
519               UserPackageStats::UidMemoryStats{{/*rssKb=*/2000, /*pssKb=*/1645,
520                                                 /*ussKb=*/1286, /*swapPssKb=*/600},
521                                                isSmapsRollupSupported,
522                                                {{"KitchenSinkApp",
523                                                  {/*rssKb=*/1000, /*pssKb=*/875,
524                                                   /*ussKb=*/630, /*swapPssKb=*/400}},
525                                                 {"CTS",
526                                                  {/*rssKb=*/1000, /*pssKb=*/770,
527                                                   /*ussKb=*/656, /*swapPssKb=*/200}}}}},
528              {1009, "mount",
529               UserPackageStats::UidMemoryStats{{/*rssKb=*/2010, /*pssKb=*/1635,
530                                                 /*ussKb=*/1286, /*swapPssKb=*/600},
531                                                isSmapsRollupSupported,
532                                                {{"disk I/O",
533                                                  {/*rssKb=*/2010, /*pssKb=*/1635,
534                                                   /*ussKb=*/1286, /*swapPssKb=*/600}}}}},
535              {1012345, "1012345",
536               UserPackageStats::UidMemoryStats{{/*rssKb=*/1000, /*pssKb=*/865,
537                                                 /*ussKb=*/656, /*swapPssKb=*/200},
538                                                isSmapsRollupSupported,
539                                                {{"MapsApp",
540                                                  {/*rssKb=*/1000, /*pssKb=*/865,
541                                                   /*ussKb=*/656, /*swapPssKb=*/200}}}}}};
542     std::vector<UserPackageStats> topNMemStatsRankedByRss =
543             {{1009, "mount",
544               UserPackageStats::UidMemoryStats{{/*rssKb=*/2010, /*pssKb=*/1635,
545                                                 /*ussKb=*/1286, /*swapPssKb=*/600},
546                                                isSmapsRollupSupported,
547                                                {{"disk I/O",
548                                                  {/*rssKb=*/2010, /*pssKb=*/1635,
549                                                   /*ussKb=*/1286, /*swapPssKb=*/600}}}}},
550              {1002001, "com.google.android.car.kitchensink",
551               UserPackageStats::UidMemoryStats{{/*rssKb=*/2000, /*pssKb=*/1645,
552                                                 /*ussKb=*/1286, /*swapPssKb=*/600},
553                                                isSmapsRollupSupported,
554                                                {{"KitchenSinkApp",
555                                                  {/*rssKb=*/1000, /*pssKb=*/875,
556                                                   /*ussKb=*/630, /*swapPssKb=*/400}},
557                                                 {"CTS",
558                                                  {/*rssKb=*/1000, /*pssKb=*/770,
559                                                   /*ussKb=*/656, /*swapPssKb=*/200}}}}},
560              {1012345, "1012345",
561               UserPackageStats::UidMemoryStats{{/*rssKb=*/1000, /*pssKb=*/865,
562                                                 /*ussKb=*/656, /*swapPssKb=*/200},
563                                                isSmapsRollupSupported,
564                                                {{"MapsApp",
565                                                  {/*rssKb=*/1000, /*pssKb=*/865,
566                                                   /*ussKb=*/656, /*swapPssKb=*/200}}}}}};
567     UserPackageSummaryStats userPackageSummaryStats{
568             .topNCpuTimes = {{1012345, "1012345",
569                               UserPackageStats::ProcCpuStatsView{int64Multiplier(100),
570                                                                  50'000,
571                                                                  {{2345, "MapsApp",
572                                                                    int64Multiplier(100), 50'000}}}},
573                              {1002001, "com.google.android.car.kitchensink",
574                               UserPackageStats::ProcCpuStatsView{int64Multiplier(60),
575                                                                  10'000,
576                                                                  {{1001, "CTS", int64Multiplier(30),
577                                                                    5000},
578                                                                   {1000, "KitchenSinkApp",
579                                                                    int64Multiplier(25), 4000}}}},
580                              {1009, "mount",
581                               UserPackageStats::ProcCpuStatsView{int64Multiplier(50),
582                                                                  4000,
583                                                                  {{100, "disk I/O",
584                                                                    int64Multiplier(50), 4000}}}}},
585             .topNIoReads = {{1009, "mount",
586                              UserPackageStats::IoStatsView{{0, int64Multiplier(14'000)},
587                                                            {0, int64Multiplier(100)}}},
588                             {1012345, "1012345",
589                              UserPackageStats::IoStatsView{{int64Multiplier(1'000),
590                                                             int64Multiplier(4'200)},
591                                                            {int64Multiplier(600),
592                                                             int64Multiplier(300)}}},
593                             {1002001, "com.google.android.car.kitchensink",
594                              UserPackageStats::IoStatsView{{0, int64Multiplier(3'400)},
595                                                            {0, int64Multiplier(200)}}}},
596             .topNIoWrites =
597                     {{1009, "mount",
598                       UserPackageStats::IoStatsView{{0, int64Multiplier(16'000)},
599                                                     {0, int64Multiplier(100)}}},
600                      {1002001, "com.google.android.car.kitchensink",
601                       UserPackageStats::IoStatsView{{0, int64Multiplier(6'700)},
602                                                     {0, int64Multiplier(200)}}},
603                      {1012345, "1012345",
604                       UserPackageStats::IoStatsView{{int64Multiplier(300), int64Multiplier(5'600)},
605                                                     {int64Multiplier(600), int64Multiplier(300)}}}},
606             .topNIoBlocked =
607                     {{1002001, "com.google.android.car.kitchensink",
608                       UserPackageStats::ProcSingleStatsView{3,
609                                                             {{"CTS", 2}, {"KitchenSinkApp", 1}}}},
610                      {1012345, "1012345",
611                       UserPackageStats::ProcSingleStatsView{2, {{"MapsApp", 2}}}},
612                      {1009, "mount", UserPackageStats::ProcSingleStatsView{1, {{"disk I/O", 1}}}}},
613             .topNMajorFaults =
614                     {{1012345, "1012345",
615                       UserPackageStats::ProcSingleStatsView{uint64Multiplier(50'900),
616                                                             {{"MapsApp",
617                                                               uint64Multiplier(50'900)}}}},
618                      {1002001, "com.google.android.car.kitchensink",
619                       UserPackageStats::ProcSingleStatsView{uint64Multiplier(22'445),
620                                                             {{"KitchenSinkApp",
621                                                               uint64Multiplier(12'345)},
622                                                              {"CTS", uint64Multiplier(10'100)}}}},
623                      {1009, "mount",
624                       UserPackageStats::ProcSingleStatsView{uint64Multiplier(11'000),
625                                                             {{"disk I/O",
626                                                               uint64Multiplier(11'000)}}}}},
627             .topNMemStats =
628                     isSmapsRollupSupported ? topNMemStatsRankedByPss : topNMemStatsRankedByRss,
629             .totalIoStats = {{int64Multiplier(1'000), int64Multiplier(21'600)},
630                              {int64Multiplier(300), int64Multiplier(28'300)},
631                              {int64Multiplier(600), int64Multiplier(600)}},
632             .taskCountByUid = {{1009, 1}, {1002001, 5}, {1012345, 4}},
633             .totalCpuTimeMillis = int64Multiplier(48'376),
634             .totalCpuCycles = 64'000,
635             .totalMajorFaults = uint64Multiplier(84'345),
636             .totalRssKb = 5010,
637             .totalPssKb = 4145,
638             .majorFaultsPercentChange = 0.0,
639     };
640     applyFeatureFilter(&userPackageSummaryStats);
641     return std::make_tuple(uidStats, userPackageSummaryStats);
642 }
643 
sampleProcStat(auto int64Multiplier,auto uint64Multiplier,auto uint32Multiplier)644 std::tuple<ProcStatInfo, SystemSummaryStats> sampleProcStat(auto int64Multiplier,
645                                                             auto uint64Multiplier,
646                                                             auto uint32Multiplier) {
647     ProcStatInfo procStatInfo{/*stats=*/{int64Multiplier(2'900), int64Multiplier(7'900),
648                                          int64Multiplier(4'900), int64Multiplier(8'900),
649                                          /*ioWaitTimeMillis=*/int64Multiplier(5'900),
650                                          int64Multiplier(6'966), int64Multiplier(7'980), 0, 0,
651                                          int64Multiplier(2'930)},
652                               /*ctxtSwitches=*/uint64Multiplier(500),
653                               /*runnableCnt=*/uint32Multiplier(100),
654                               /*ioBlockedCnt=*/uint32Multiplier(57)};
655     SystemSummaryStats systemSummaryStats{/*cpuIoWaitTimeMillis=*/int64Multiplier(5'900),
656                                           /*cpuIdleTimeMillis=*/int64Multiplier(8'900),
657                                           /*totalCpuTimeMillis=*/int64Multiplier(48'376),
658                                           /*totalCpuCycles=*/64'000,
659                                           /*contextSwitchesCount=*/uint64Multiplier(500),
660                                           /*ioBlockedProcessCount=*/uint32Multiplier(57),
661                                           /*totalProcessCount=*/uint32Multiplier(157)};
662     return std::make_tuple(procStatInfo, systemSummaryStats);
663 }
664 
samplePressureLevels(int advanceUptimeSec=1)665 std::tuple<PressureLevelTransitions, PressureLevelDurations> samplePressureLevels(
666         int advanceUptimeSec = 1) {
667     PressureLevelTransitions pressureLevelTransitions{
668             PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_NONE, 100 * advanceUptimeSec},
669             PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_HIGH, 200 * advanceUptimeSec},
670             PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_HIGH, 100 * advanceUptimeSec},
671             PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_LOW, 200 * advanceUptimeSec},
672             PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_MEDIUM,
673                                       100 * advanceUptimeSec},
674             PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_LOW, 200 * advanceUptimeSec},
675             PressureLevelDurationPair{PressureMonitor::PRESSURE_LEVEL_MEDIUM,
676                                       100 * advanceUptimeSec},
677     };
678     PressureLevelDurations pressureLevelDurations{
679             {PressureMonitor::PRESSURE_LEVEL_NONE, 100ms * advanceUptimeSec},
680             {PressureMonitor::PRESSURE_LEVEL_LOW, 400ms * advanceUptimeSec},
681             {PressureMonitor::PRESSURE_LEVEL_MEDIUM, 200ms * advanceUptimeSec},
682             {PressureMonitor::PRESSURE_LEVEL_HIGH, 300ms * advanceUptimeSec},
683     };
684     return std::make_tuple(pressureLevelTransitions, pressureLevelDurations);
685 }
686 
getResourceStatsForSampledStats(auto int32Multiplier,auto int64Multiplier,time_point_millis nowMillis,int64_t elapsedRealtimeSinceBootMillis)687 ResourceStats getResourceStatsForSampledStats(auto int32Multiplier, auto int64Multiplier,
688                                               time_point_millis nowMillis,
689                                               int64_t elapsedRealtimeSinceBootMillis) {
690     // clang-format off
691     return {
692         .resourceUsageStats = std::make_optional<ResourceUsageStats>({
693             .startTimeEpochMillis = nowMillis.time_since_epoch().count(),
694             // Set durationInMillis to zero since this field is set by WatchdogPerfService.
695             .durationInMillis = 0,
696             .systemSummaryUsageStats = {
697                 .cpuNonIdleCycles = 64'000,
698                 .cpuNonIdleTimeMillis = int32Multiplier(39'476),
699                 .cpuIdleTimeMillis = int32Multiplier(8'900),
700                 .contextSwitchesCount = int32Multiplier(500),
701                 .ioBlockedProcessCount = int32Multiplier(57),
702                 .totalProcessCount = int32Multiplier(157),
703                 .totalMajorPageFaults = int32Multiplier(84'345),
704                 .totalIoReads = {
705                     .foregroundBytes = int32Multiplier(1'000),
706                     .backgroundBytes = int32Multiplier(21'600),
707                     .garageModeBytes = 0,
708                 },
709                 .totalIoWrites = {
710                     .foregroundBytes = int32Multiplier(300),
711                     .backgroundBytes = int32Multiplier(28'300),
712                     .garageModeBytes = 0,
713                 },
714             },
715             .uidResourceUsageStats = {
716                 {
717                     .packageIdentifier = {
718                         .name = "mount",
719                         .uid = 1009,
720                     },
721                     .uidUptimeMillis = elapsedRealtimeSinceBootMillis - 234,
722                     .cpuUsageStats = {
723                         .cpuTimeMillis = int64Multiplier(50),
724                         .cpuCycles = 4'000,
725                         .cpuTimePercentage = (50. / 48'376.) * 100.0,
726                     },
727                     .processCpuUsageStats = {
728                         {
729                             .pid = 100,
730                             .name = "disk I/O",
731                             .cpuTimeMillis = int64Multiplier(50),
732                             .cpuCycles = 4'000,
733                         },
734                     },
735                     .ioUsageStats = {
736                         .writtenBytes = {
737                             .foregroundBytes = 0,
738                             .backgroundBytes = int32Multiplier(16'000),
739                             .garageModeBytes = 0,
740                         },
741                         .readBytes = {
742                             .foregroundBytes = 0,
743                             .backgroundBytes = int32Multiplier(14'000),
744                             .garageModeBytes = 0,
745                         },
746                     },
747                 },
748                 {
749                     .packageIdentifier = {
750                         .name = "com.google.android.car.kitchensink",
751                         .uid = 1002001,
752                     },
753                     .uidUptimeMillis = elapsedRealtimeSinceBootMillis - 467,
754                     .cpuUsageStats = {
755                         .cpuTimeMillis = int64Multiplier(60),
756                         .cpuCycles = 10'000,
757                         .cpuTimePercentage = (60. / 48'376.) * 100.0,
758                     },
759                     .processCpuUsageStats = {
760                         {
761                             .pid = 1001,
762                             .name = "CTS",
763                             .cpuTimeMillis = int64Multiplier(30),
764                             .cpuCycles = 5'000,
765                         },
766                         {
767                             .pid = 1000,
768                             .name = "KitchenSinkApp",
769                             .cpuTimeMillis = int64Multiplier(25),
770                             .cpuCycles = 4'000,
771                         },
772                     },
773                     .ioUsageStats = {
774                         .writtenBytes = {
775                             .foregroundBytes = 0,
776                             .backgroundBytes = int32Multiplier(6'700),
777                             .garageModeBytes = 0,
778                         },
779                         .readBytes = {
780                             .foregroundBytes = 0,
781                             .backgroundBytes = int32Multiplier(3'400),
782                             .garageModeBytes = 0,
783                         },
784                     },
785                 },
786                 {
787                     .packageIdentifier = {
788                         .name = "1012345",
789                         .uid = 1012345,
790                     },
791                     .uidUptimeMillis = elapsedRealtimeSinceBootMillis - 6789,
792                     .cpuUsageStats = {
793                         .cpuTimeMillis = int64Multiplier(100),
794                         .cpuCycles = 50'000,
795                         .cpuTimePercentage = (100. / 48'376.) * 100.0,
796                     },
797                     .processCpuUsageStats = {
798                         {
799                             .pid = 2345,
800                             .name = "MapsApp",
801                             .cpuTimeMillis = int64Multiplier(100),
802                             .cpuCycles = 50'000,
803                         },
804                     },
805                     .ioUsageStats = {
806                         .writtenBytes = {
807                             .foregroundBytes = int32Multiplier(300),
808                             .backgroundBytes = int32Multiplier(5'600),
809                             .garageModeBytes = 0,
810                         },
811                         .readBytes = {
812                             .foregroundBytes = int32Multiplier(1'000),
813                             .backgroundBytes = int32Multiplier(4'200),
814                             .garageModeBytes = 0,
815                         },
816                     },
817                 },
818                 {
819                     .packageIdentifier = {
820                         .name = "com.google.radio",
821                         .uid = 1015678,
822                     },
823                     .uidUptimeMillis = elapsedRealtimeSinceBootMillis - 10789,
824                     .cpuUsageStats = {
825                         .cpuTimeMillis = 0,
826                         .cpuCycles = 0,
827                         .cpuTimePercentage = 0,
828                     },
829                     .ioUsageStats = {
830                         .writtenBytes = {
831                             .foregroundBytes = 0,
832                             .backgroundBytes = 0,
833                             .garageModeBytes = 0,
834                         },
835                         .readBytes = {
836                             .foregroundBytes = 0,
837                             .backgroundBytes = 0,
838                             .garageModeBytes = 0,
839                         },
840                     },
841                 },
842             },
843         }),
844     };
845     // clang-format on
846 }
847 
848 struct StatsInfo {
849     std::vector<UidStats> uidStats = {};
850     UserPackageSummaryStats userPackageSummaryStats = {};
851     ProcStatInfo procStatInfo = {};
852     SystemSummaryStats systemSummaryStats = {};
853     ResourceStats resourceStats = {};
854 };
855 
856 MATCHER_P(UserPackageInfoProtoEq, expected, "") {
857     return ExplainMatchResult(AllOf(Property("user_id", &UserPackageInfo::user_id,
858                                              static_cast<int>(multiuser_get_user_id(expected.uid))),
859                                     Property("package_name", &UserPackageInfo::package_name,
860                                              expected.genericPackageName)),
861                               arg, result_listener);
862 }
863 
864 MATCHER_P(CpuStatsProtoEq, expected, "") {
865     return ExplainMatchResult(AllOf(Property("cpu_time_millis",
866                                              &PackageCpuStats_CpuStats::cpu_time_millis,
867                                              expected.cpuTimeMillis),
868                                     Property("cpu_cycles", &PackageCpuStats_CpuStats::cpu_cycles,
869                                              expected.cpuCycles)),
870                               arg, result_listener);
871 }
872 
873 MATCHER_P(ProcessCpuStatsProtoEq, expected, "") {
874     return ExplainMatchResult(AllOf(Property("command", &PackageCpuStats_ProcessCpuStats::command,
875                                              expected.comm),
876                                     Property("cpu_stats",
877                                              &PackageCpuStats_ProcessCpuStats::cpu_stats,
878                                              CpuStatsProtoEq(expected))),
879                               arg, result_listener);
880 }
881 
882 MATCHER_P(PackageCpuStatsProtoEq, expected, "") {
883     const auto& procCpuStatsView =
884             std::get_if<UserPackageStats::ProcCpuStatsView>(&expected.statsView);
885     std::vector<Matcher<const PackageCpuStats_ProcessCpuStats&>> processCpuStatsMatchers;
886     for (const auto& expectedProcessCpuValue : procCpuStatsView->topNProcesses) {
887         processCpuStatsMatchers.push_back(ProcessCpuStatsProtoEq(expectedProcessCpuValue));
888     }
889     return ExplainMatchResult(AllOf(Property("user_package_info",
890                                              &PackageCpuStats::user_package_info,
891                                              UserPackageInfoProtoEq(expected)),
892                                     Property("cpu_stats", &PackageCpuStats::cpu_stats,
893                                              CpuStatsProtoEq(*procCpuStatsView)),
894                                     Property("process_cpu_stats",
895                                              &PackageCpuStats::process_cpu_stats,
896                                              ElementsAreArray(processCpuStatsMatchers))),
897                               arg, result_listener);
898 }
899 
900 MATCHER_P4(StorageIoStatsProtoEq, fgBytes, fgFsync, bgBytes, byFsync, "") {
901     return ExplainMatchResult(AllOf(Property("fg_bytes", &StorageIoStats::fg_bytes, fgBytes),
902                                     Property("fg_fsync", &StorageIoStats::fg_fsync, fgFsync),
903                                     Property("bg_bytes", &StorageIoStats::bg_bytes, bgBytes),
904                                     Property("bg_fsync", &StorageIoStats::bg_fsync, byFsync)),
905                               arg, result_listener);
906 }
907 
908 MATCHER_P(PackageStorageIoStatsProtoEq, expected, "") {
909     const auto& ioStatsView = std::get_if<UserPackageStats::IoStatsView>(&expected.statsView);
910     return ExplainMatchResult(AllOf(Property("user_package_info",
911                                              &PackageStorageIoStats::user_package_info,
912                                              UserPackageInfoProtoEq(expected)),
913                                     Property("storage_io_stats",
914                                              &PackageStorageIoStats::storage_io_stats,
915                                              StorageIoStatsProtoEq(ioStatsView->bytes[FOREGROUND],
916                                                                    ioStatsView->fsync[FOREGROUND],
917                                                                    ioStatsView->bytes[BACKGROUND],
918                                                                    ioStatsView
919                                                                            ->fsync[BACKGROUND]))),
920                               arg, result_listener);
921 }
922 
923 MATCHER_P(ProcessTaskStateStatsProtoEq, expected, "") {
924     return ExplainMatchResult(AllOf(Property("command",
925                                              &PackageTaskStateStats_ProcessTaskStateStats::command,
926                                              expected.comm),
927                                     Property("io_blocked_task_count",
928                                              &PackageTaskStateStats_ProcessTaskStateStats::
929                                                      io_blocked_task_count,
930                                              expected.value)),
931                               arg, result_listener);
932 }
933 
934 MATCHER_P2(PackageTaskStateStatsProtoEq, expected, taskCountByUid, "") {
935     const auto& procSingleStatsView =
936             std::get_if<UserPackageStats::ProcSingleStatsView>(&expected.statsView);
937     std::vector<Matcher<const PackageTaskStateStats_ProcessTaskStateStats&>>
938             processTaskStateStatsMatchers;
939     for (const auto& expectedProcessValue : procSingleStatsView->topNProcesses) {
940         processTaskStateStatsMatchers.push_back(ProcessTaskStateStatsProtoEq(expectedProcessValue));
941     }
942     return ExplainMatchResult(AllOf(Property("user_package_info",
943                                              &PackageTaskStateStats::user_package_info,
944                                              UserPackageInfoProtoEq(expected)),
945                                     Property("io_blocked_task_count",
946                                              &PackageTaskStateStats::io_blocked_task_count,
947                                              procSingleStatsView->value),
948                                     Property("total_task_count",
949                                              &PackageTaskStateStats::total_task_count,
950                                              taskCountByUid.at(expected.uid)),
951                                     Property("process_task_state_stats",
952                                              &PackageTaskStateStats::process_task_state_stats,
953                                              ElementsAreArray(processTaskStateStatsMatchers))),
954                               arg, result_listener);
955 }
956 
957 MATCHER_P(PackageMajorPageFaultsProtoEq, expected, "") {
958     const auto& procSingleStatsView =
959             std::get_if<UserPackageStats::ProcSingleStatsView>(&expected.statsView);
960     return ExplainMatchResult(AllOf(Property("user_package_info",
961                                              &PackageMajorPageFaults::user_package_info,
962                                              UserPackageInfoProtoEq(expected)),
963                                     Property("major_page_faults_count",
964                                              &PackageMajorPageFaults::major_page_faults_count,
965                                              procSingleStatsView->value)),
966                               arg, result_listener);
967 }
968 
969 MATCHER_P(DateProtoEq, expected, "") {
970     return ExplainMatchResult(AllOf(Property("year", &Date::year, expected.tm_year + 1900),
971                                     Property("month", &Date::month, expected.tm_mon),
972                                     Property("day", &Date::day, expected.tm_mday)),
973                               arg, result_listener);
974 }
975 
976 MATCHER_P2(TimeOfDayProtoEq, expected, nowTimeMs, "") {
977     return ExplainMatchResult(AllOf(Property("hours", &TimeOfDay::hours, expected.tm_hour),
978                                     Property("minutes", &TimeOfDay::minutes, expected.tm_min),
979                                     Property("seconds", &TimeOfDay::seconds, expected.tm_sec),
980                                     Property("millis", &TimeOfDay::millis, nowTimeMs.count())),
981                               arg, result_listener);
982 }
983 
984 MATCHER_P2(SystemWideStatsProtoEq, userPackageSummaryStats, systemSummaryStats, "") {
985     return ExplainMatchResult(AllOf(Property("io_wait_time_millis",
986                                              &SystemWideStats::io_wait_time_millis,
987                                              systemSummaryStats.cpuIoWaitTimeMillis),
988                                     Property("idle_cpu_time_millis",
989                                              &SystemWideStats::idle_cpu_time_millis,
990                                              systemSummaryStats.cpuIdleTimeMillis),
991                                     Property("total_cpu_time_millis",
992                                              &SystemWideStats::total_cpu_time_millis,
993                                              systemSummaryStats.totalCpuTimeMillis),
994                                     Property("total_cpu_cycles", &SystemWideStats::total_cpu_cycles,
995                                              systemSummaryStats.totalCpuCycles),
996                                     Property("total_context_switches",
997                                              &SystemWideStats::total_context_switches,
998                                              systemSummaryStats.contextSwitchesCount),
999                                     Property("total_io_blocked_processes",
1000                                              &SystemWideStats::total_io_blocked_processes,
1001                                              systemSummaryStats.ioBlockedProcessCount),
1002                                     Property("total_major_page_faults",
1003                                              &SystemWideStats::total_major_page_faults,
1004                                              userPackageSummaryStats.totalMajorFaults),
1005                                     Property("total_storage_io_stats",
1006                                              &SystemWideStats::total_storage_io_stats,
1007                                              StorageIoStatsProtoEq(userPackageSummaryStats
1008                                                                            .totalIoStats
1009                                                                                    [WRITE_BYTES]
1010                                                                                    [FOREGROUND],
1011                                                                    userPackageSummaryStats
1012                                                                            .totalIoStats
1013                                                                                    [FSYNC_COUNT]
1014                                                                                    [FOREGROUND],
1015                                                                    userPackageSummaryStats
1016                                                                            .totalIoStats
1017                                                                                    [WRITE_BYTES]
1018                                                                                    [BACKGROUND],
1019                                                                    userPackageSummaryStats
1020                                                                            .totalIoStats
1021                                                                                    [FSYNC_COUNT]
1022                                                                                    [BACKGROUND]))),
1023                               arg, result_listener);
1024 }
1025 
1026 MATCHER_P3(StatsRecordProtoEq, userPackageSummaryStats, systemSummaryStats, nowMs, "") {
1027     struct tm timeinfo;
1028     memset(&timeinfo, 0, sizeof(timeinfo));
1029     auto dateTime = std::chrono::system_clock::to_time_t(nowMs);
1030     auto nowTimeMs = std::chrono::duration_cast<std::chrono::milliseconds>(
1031             nowMs - std::chrono::system_clock::from_time_t(dateTime));
1032     localtime_r(&dateTime, &timeinfo);
1033 
1034     std::vector<Matcher<const PackageCpuStats&>> packageCpuStatsMatchers;
1035     for (const auto& expectedProcCpuStatsView : userPackageSummaryStats.topNCpuTimes) {
1036         packageCpuStatsMatchers.push_back(PackageCpuStatsProtoEq(expectedProcCpuStatsView));
1037     }
1038     std::vector<Matcher<const PackageStorageIoStats&>> packageStorageReadIoStatsMatchers;
1039     for (const auto& expectedPackageStorageReadIoStat : userPackageSummaryStats.topNIoReads) {
1040         packageStorageReadIoStatsMatchers.push_back(
1041                 PackageStorageIoStatsProtoEq(expectedPackageStorageReadIoStat));
1042     }
1043     std::vector<Matcher<const PackageStorageIoStats&>> packageStorageWriteIoStatsMatchers;
1044     for (const auto& expectedPackageStorageWriteIoStat : userPackageSummaryStats.topNIoWrites) {
1045         packageStorageWriteIoStatsMatchers.push_back(
1046                 PackageStorageIoStatsProtoEq(expectedPackageStorageWriteIoStat));
1047     }
1048     std::vector<Matcher<const PackageTaskStateStats&>> packageTaskStateStatsMatchers;
1049     for (const auto& expectedPackageTaskStateStat : userPackageSummaryStats.topNIoBlocked) {
1050         packageTaskStateStatsMatchers.push_back(
1051                 PackageTaskStateStatsProtoEq(expectedPackageTaskStateStat,
1052                                              userPackageSummaryStats.taskCountByUid));
1053     }
1054     std::vector<Matcher<const PackageMajorPageFaults&>> packageMajorPageFaultsMatchers;
1055     for (const auto& expectedPackageMajorPageFault : userPackageSummaryStats.topNMajorFaults) {
1056         packageMajorPageFaultsMatchers.push_back(
1057                 PackageMajorPageFaultsProtoEq(expectedPackageMajorPageFault));
1058     }
1059     return ExplainMatchResult(AllOf(Property("date", &StatsRecord::date, DateProtoEq(timeinfo)),
1060                                     Property("time", &StatsRecord::time,
1061                                              TimeOfDayProtoEq(timeinfo, nowTimeMs)),
1062                                     Property("system_wide_stats", &StatsRecord::system_wide_stats,
1063                                              SystemWideStatsProtoEq(userPackageSummaryStats,
1064                                                                     systemSummaryStats)),
1065                                     Property("package_cpu_stats", &StatsRecord::package_cpu_stats,
1066                                              ElementsAreArray(packageCpuStatsMatchers)),
1067                                     Property("package_storage_io_read_stats",
1068                                              &StatsRecord::package_storage_io_read_stats,
1069                                              ElementsAreArray(packageStorageReadIoStatsMatchers)),
1070                                     Property("package_storage_io_read_stats",
1071                                              &StatsRecord::package_storage_io_write_stats,
1072                                              ElementsAreArray(packageStorageWriteIoStatsMatchers)),
1073                                     Property("package_task_state_stats",
1074                                              &StatsRecord::package_task_state_stats,
1075                                              ElementsAreArray(packageTaskStateStatsMatchers)),
1076                                     Property("package_major_page_faults",
1077                                              &StatsRecord::package_major_page_faults,
1078                                              ElementsAreArray(packageMajorPageFaultsMatchers))),
1079                               arg, result_listener);
1080 }
1081 
toString(util::ProtoOutputStream * proto)1082 std::string toString(util::ProtoOutputStream* proto) {
1083     std::string content;
1084     content.reserve(proto->size());
1085     sp<ProtoReader> reader = proto->data();
1086     while (reader->hasNext()) {
1087         content.push_back(reader->next());
1088     }
1089     return content;
1090 }
1091 
toString(const std::vector<UserSwitchCollectionInfo> & infos)1092 std::string toString(const std::vector<UserSwitchCollectionInfo>& infos) {
1093     std::string buffer;
1094     StringAppendF(&buffer, "{");
1095     for (const auto& info : infos) {
1096         StringAppendF(&buffer, "%s\n", info.toString().c_str());
1097     }
1098     StringAppendF(&buffer, "}");
1099     return buffer;
1100 }
1101 
1102 }  // namespace
1103 
1104 namespace internal {
1105 
1106 // TODO(b/289396065): Refactor class such that variable fields are initialized directly in the
1107 // constructor and remove the setter methods.
1108 class PerformanceProfilerPeer final : public RefBase {
1109 public:
PerformanceProfilerPeer(sp<PerformanceProfiler> collector)1110     explicit PerformanceProfilerPeer(sp<PerformanceProfiler> collector) : mCollector(collector) {}
1111 
1112     PerformanceProfilerPeer() = delete;
~PerformanceProfilerPeer()1113     ~PerformanceProfilerPeer() {
1114         mCollector->terminate();
1115         mCollector.clear();
1116     }
1117 
init()1118     Result<void> init() { return mCollector->init(); }
1119 
setTopNStatsPerCategory(int value)1120     void setTopNStatsPerCategory(int value) { mCollector->mTopNStatsPerCategory = value; }
1121 
setTopNStatsPerSubcategory(int value)1122     void setTopNStatsPerSubcategory(int value) { mCollector->mTopNStatsPerSubcategory = value; }
1123 
setMaxUserSwitchEvents(int value)1124     void setMaxUserSwitchEvents(int value) { mCollector->mMaxUserSwitchEvents = value; }
1125 
setSystemEventDataCacheDuration(std::chrono::seconds value)1126     void setSystemEventDataCacheDuration(std::chrono::seconds value) {
1127         mCollector->mSystemEventDataCacheDurationSec = value;
1128     }
1129 
setPeriodicCollectionBufferSize(size_t bufferSize)1130     void setPeriodicCollectionBufferSize(size_t bufferSize) {
1131         mCollector->mPeriodicCollection.maxCacheSize = bufferSize;
1132     }
1133 
setSendResourceUsageStatsEnabled(bool enable)1134     void setSendResourceUsageStatsEnabled(bool enable) {
1135         mCollector->mDoSendResourceUsageStats = enable;
1136     }
1137 
setSmapsRollupSupportedEnabled(bool enable)1138     void setSmapsRollupSupportedEnabled(bool enable) {
1139         mCollector->mIsSmapsRollupSupported = enable;
1140     }
1141 
getBoottimeCollectionInfo()1142     const CollectionInfo& getBoottimeCollectionInfo() {
1143         Mutex::Autolock lock(mCollector->mMutex);
1144         return mCollector->mBoottimeCollection;
1145     }
1146 
getPeriodicCollectionInfo()1147     const CollectionInfo& getPeriodicCollectionInfo() {
1148         Mutex::Autolock lock(mCollector->mMutex);
1149         return mCollector->mPeriodicCollection;
1150     }
1151 
getUserSwitchCollectionInfos()1152     const std::vector<UserSwitchCollectionInfo>& getUserSwitchCollectionInfos() {
1153         Mutex::Autolock lock(mCollector->mMutex);
1154         return mCollector->mUserSwitchCollections;
1155     }
1156 
getWakeUpCollectionInfo()1157     const CollectionInfo& getWakeUpCollectionInfo() {
1158         Mutex::Autolock lock(mCollector->mMutex);
1159         return mCollector->mWakeUpCollection;
1160     }
1161 
getCustomCollectionInfo()1162     const CollectionInfo& getCustomCollectionInfo() {
1163         Mutex::Autolock lock(mCollector->mMutex);
1164         return mCollector->mCustomCollection;
1165     }
1166 
1167 private:
1168     sp<PerformanceProfiler> mCollector;
1169 };
1170 
1171 }  // namespace internal
1172 
1173 class PerformanceProfilerTest : public Test {
1174 protected:
SetUp()1175     void SetUp() override {
1176         mPeriodicCollectionBufferSize =
1177                 static_cast<size_t>(sysprop::periodicCollectionBufferSize().value_or(
1178                         kDefaultPeriodicCollectionBufferSize));
1179         mElapsedRealtimeSinceBootMillis = kTestElapsedRealtimeSinceBootMillis;
1180         mNowMillis = kTestNowMillis;
1181         mMockUidStatsCollector = sp<MockUidStatsCollector>::make();
1182         mMockPressureMonitor = sp<MockPressureMonitor>::make();
1183         mMockProcStatCollector = sp<MockProcStatCollector>::make();
1184         mCollector = sp<PerformanceProfiler>::
1185                 make(mMockPressureMonitor,
1186                      std::bind(&PerformanceProfilerTest::getTestElapsedRealtimeSinceBootMs, this));
1187         mCollectorPeer = sp<internal::PerformanceProfilerPeer>::make(mCollector);
1188 
1189         EXPECT_CALL(*mMockPressureMonitor, registerPressureChangeCallback(Eq(mCollector)))
1190                 .Times(car_watchdog_memory_profiling() ? 1 : 0);
1191 
1192         ASSERT_RESULT_OK(mCollectorPeer->init());
1193 
1194         mCollectorPeer->setTopNStatsPerCategory(kTestTopNStatsPerCategory);
1195         mCollectorPeer->setTopNStatsPerSubcategory(kTestTopNStatsPerSubcategory);
1196         mCollectorPeer->setMaxUserSwitchEvents(kTestMaxUserSwitchEvents);
1197         mCollectorPeer->setSystemEventDataCacheDuration(kTestSystemEventDataCacheDurationSec);
1198         mCollectorPeer->setSendResourceUsageStatsEnabled(true);
1199         mCollectorPeer->setSmapsRollupSupportedEnabled(true);
1200         mCollectorPeer->setPeriodicCollectionBufferSize(kTestPeriodicCollectionBufferSize);
1201     }
1202 
TearDown()1203     void TearDown() override {
1204         mMockUidStatsCollector.clear();
1205         mMockProcStatCollector.clear();
1206 
1207         EXPECT_CALL(*mMockPressureMonitor, unregisterPressureChangeCallback(Eq(mCollector)))
1208                 .Times(car_watchdog_memory_profiling() ? 1 : 0);
1209 
1210         mCollector.clear();
1211         mCollectorPeer.clear();
1212     }
1213 
getTestElapsedRealtimeSinceBootMs()1214     int64_t getTestElapsedRealtimeSinceBootMs() { return mElapsedRealtimeSinceBootMillis; }
1215 
1216 protected:
checkDumpContents(int wantedEmptyCollectionInstances)1217     void checkDumpContents(int wantedEmptyCollectionInstances) {
1218         TemporaryFile dump;
1219         ASSERT_RESULT_OK(mCollector->onDump(dump.fd));
1220 
1221         checkDumpFd(wantedEmptyCollectionInstances, dump.fd);
1222     }
1223 
checkCustomDumpContents()1224     void checkCustomDumpContents() {
1225         TemporaryFile dump;
1226         ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(dump.fd));
1227 
1228         checkDumpFd(/*wantedEmptyCollectionInstances=*/0, dump.fd);
1229     }
1230 
injectPressureLevelTransitions(int advanceUptimeSec)1231     PressureLevelDurations injectPressureLevelTransitions(int advanceUptimeSec) {
1232         if (!car_watchdog_memory_profiling()) {
1233             mElapsedRealtimeSinceBootMillis += advanceUptimeSec * 1000;
1234             return PressureLevelDurations{};
1235         }
1236         auto [pressureLevelTransitions, pressureLevelDurations] =
1237                 samplePressureLevels(advanceUptimeSec);
1238         for (const auto transition : pressureLevelTransitions) {
1239             mElapsedRealtimeSinceBootMillis += transition.second;
1240             mCollector->onPressureChanged(transition.first);
1241         }
1242         return pressureLevelDurations;
1243     }
1244 
1245     // Direct use of this method in tests is not recommended because further setup (such as calling
1246     // injectPressureLevelTransitions, constructing CollectionInfo struct, advancing time, and
1247     // setting up EXPECT_CALL) is required before testing a collection. Please consider using one of
1248     // the PerformanceProfilerTest::setup* methods instead. If none of them work for a new use case,
1249     // either update the existing PerformanceProfilerTest::setup* methods or add a new
1250     // PerformanceProfilerTest::setup* method.
getSampleStatsInfo(int multiplier=1,bool isSmapsRollupSupported=kTestIsSmapsRollupSupported)1251     StatsInfo getSampleStatsInfo(int multiplier = 1,
1252                                  bool isSmapsRollupSupported = kTestIsSmapsRollupSupported) {
1253         const auto int64Multiplier = [&](int64_t bytes) -> int64_t {
1254             return static_cast<int64_t>(bytes * multiplier);
1255         };
1256         const auto uint64Multiplier = [&](uint64_t count) -> uint64_t {
1257             return static_cast<uint64_t>(count * multiplier);
1258         };
1259         const auto int32Multiplier = [&](int32_t bytes) -> int32_t {
1260             return static_cast<int32_t>(bytes * multiplier);
1261         };
1262         const auto uint32Multiplier = [&](uint32_t bytes) -> uint32_t {
1263             return static_cast<uint32_t>(bytes * multiplier);
1264         };
1265 
1266         auto [uidStats, userPackageSummaryStats] =
1267                 sampleUidStats(int64Multiplier, uint64Multiplier, isSmapsRollupSupported);
1268 
1269         applyFeatureFilter(&userPackageSummaryStats);
1270 
1271         auto [procStatInfo, systemSummaryStats] =
1272                 sampleProcStat(int64Multiplier, uint64Multiplier, uint32Multiplier);
1273 
1274         ResourceStats resourceStats =
1275                 getResourceStatsForSampledStats(int32Multiplier, int64Multiplier, mNowMillis,
1276                                                 mElapsedRealtimeSinceBootMillis);
1277 
1278         StatsInfo statsInfo(uidStats, userPackageSummaryStats, procStatInfo, systemSummaryStats,
1279                             resourceStats);
1280         return statsInfo;
1281     }
1282 
advanceTime(int durationMillis)1283     void advanceTime(int durationMillis) {
1284         mNowMillis += std::chrono::milliseconds(durationMillis);
1285     }
1286 
setupFirstCollection(size_t maxCollectionCacheSize=std::numeric_limits<std::size_t>::max (),bool isSmapsRollupSupported=kTestIsSmapsRollupSupported)1287     std::tuple<CollectionInfo, ResourceStats> setupFirstCollection(
1288             size_t maxCollectionCacheSize = std::numeric_limits<std::size_t>::max(),
1289             bool isSmapsRollupSupported = kTestIsSmapsRollupSupported) {
1290         // Trigger pressure level transitions to test the pressure level accounting done by the
1291         // implementation.
1292         auto pressureLevelDurations = injectPressureLevelTransitions(/*advanceUptimeSec=*/1);
1293         auto statsInfo = getSampleStatsInfo(/*multiplier=*/1, isSmapsRollupSupported);
1294 
1295         EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(statsInfo.uidStats));
1296         EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(statsInfo.procStatInfo));
1297 
1298         auto expectedCollectionInfo =
1299                 CollectionInfo{.maxCacheSize = maxCollectionCacheSize,
1300                                .records = {{
1301                                        .collectionTimeMillis = mNowMillis,
1302                                        .systemSummaryStats = statsInfo.systemSummaryStats,
1303                                        .userPackageSummaryStats = statsInfo.userPackageSummaryStats,
1304                                        .memoryPressureLevelDurations = pressureLevelDurations,
1305                                }}};
1306         auto expectedResourceStats = statsInfo.resourceStats;
1307         return std::make_tuple(expectedCollectionInfo, expectedResourceStats);
1308     }
1309 
setupNextCollection(CollectionInfo * prevCollectionInfo,ResourceStats * outResourceStats,int multiplier=1)1310     void setupNextCollection(CollectionInfo* prevCollectionInfo, ResourceStats* outResourceStats,
1311                              int multiplier = 1) {
1312         advanceTime(/*durationMillis=*/1000);
1313         // Trigger pressure level transitions to test the pressure level accounting done by the
1314         // implementation.
1315         auto pressureLevelDurations = injectPressureLevelTransitions(/*advanceUptimeSec=*/1);
1316         auto statsInfo = getSampleStatsInfo(multiplier, kTestIsSmapsRollupSupported);
1317 
1318         EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(statsInfo.uidStats));
1319         EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(statsInfo.procStatInfo));
1320 
1321         auto& prevRecord = prevCollectionInfo->records.back();
1322         statsInfo.userPackageSummaryStats.majorFaultsPercentChange =
1323                 (static_cast<double>(statsInfo.userPackageSummaryStats.totalMajorFaults -
1324                                      prevRecord.userPackageSummaryStats.totalMajorFaults) /
1325                  static_cast<double>(prevRecord.userPackageSummaryStats.totalMajorFaults)) *
1326                 100.0;
1327 
1328         prevCollectionInfo->records.push_back(PerfStatsRecord{
1329                 .collectionTimeMillis = mNowMillis,
1330                 .systemSummaryStats = statsInfo.systemSummaryStats,
1331                 .userPackageSummaryStats = statsInfo.userPackageSummaryStats,
1332                 .memoryPressureLevelDurations = pressureLevelDurations,
1333         });
1334         *outResourceStats = statsInfo.resourceStats;
1335     }
1336 
setupUserSwitchCollection(userid_t fromUserId,userid_t toUserId)1337     UserSwitchCollectionInfo setupUserSwitchCollection(userid_t fromUserId, userid_t toUserId) {
1338         auto [collectionInfo, _] = setupFirstCollection();
1339         return UserSwitchCollectionInfo{
1340                 collectionInfo,
1341                 .from = fromUserId,
1342                 .to = toUserId,
1343         };
1344     }
1345 
1346     // Use this method only in tests where the returned CollectionInfo / UserSwitchCollectionInfo
1347     // is not verified.
setupMultipleCollections()1348     void setupMultipleCollections() {
1349         auto statsInfo = getSampleStatsInfo();
1350 
1351         EXPECT_CALL(*mMockUidStatsCollector, deltaStats())
1352                 .WillRepeatedly(Return(statsInfo.uidStats));
1353         EXPECT_CALL(*mMockProcStatCollector, deltaStats())
1354                 .WillRepeatedly(Return(statsInfo.procStatInfo));
1355     }
1356 
getNowMillis()1357     time_point_millis getNowMillis() { return mNowMillis; }
1358 
1359 private:
checkDumpFd(int wantedEmptyCollectionInstances,int fd)1360     void checkDumpFd(int wantedEmptyCollectionInstances, int fd) {
1361         lseek(fd, 0, SEEK_SET);
1362         std::string dumpContents;
1363         ASSERT_TRUE(ReadFdToString(fd, &dumpContents));
1364         ASSERT_FALSE(dumpContents.empty());
1365 
1366         ASSERT_EQ(countOccurrences(dumpContents, kEmptyCollectionMessage),
1367                   wantedEmptyCollectionInstances)
1368                 << "Dump contents: " << dumpContents;
1369     }
1370 
1371 protected:
1372     size_t mPeriodicCollectionBufferSize;
1373     sp<MockUidStatsCollector> mMockUidStatsCollector;
1374     sp<MockPressureMonitor> mMockPressureMonitor;
1375     sp<MockProcStatCollector> mMockProcStatCollector;
1376     sp<PerformanceProfiler> mCollector;
1377     sp<internal::PerformanceProfilerPeer> mCollectorPeer;
1378 
1379 private:
1380     int64_t mElapsedRealtimeSinceBootMillis;
1381     time_point_millis mNowMillis;
1382 };
1383 
TEST_F(PerformanceProfilerTest,TestOnBoottimeCollection)1384 TEST_F(PerformanceProfilerTest, TestOnBoottimeCollection) {
1385     auto [expectedCollectionInfo, expectedResourceStats] = setupFirstCollection();
1386 
1387     ResourceStats actualResourceStats = {};
1388     ASSERT_RESULT_OK(mCollector->onBoottimeCollection(getNowMillis(), mMockUidStatsCollector,
1389                                                       mMockProcStatCollector,
1390                                                       &actualResourceStats));
1391 
1392     const auto actualCollectionInfo = mCollectorPeer->getBoottimeCollectionInfo();
1393 
1394     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1395             << "Boottime collection info doesn't match.\nExpected:\n"
1396             << expectedCollectionInfo.toString() << "\nActual:\n"
1397             << actualCollectionInfo.toString();
1398 
1399     ASSERT_EQ(actualResourceStats, expectedResourceStats)
1400             << "Expected: " << expectedResourceStats.toString()
1401             << "\nActual: " << actualResourceStats.toString();
1402 
1403     ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1404             << "Periodic, wake-up and user-switch collections shouldn't be reported";
1405 }
1406 
TEST_F(PerformanceProfilerTest,TestOnWakeUpCollection)1407 TEST_F(PerformanceProfilerTest, TestOnWakeUpCollection) {
1408     auto [expectedCollectionInfo, expectedResourceStats] = setupFirstCollection();
1409 
1410     ASSERT_RESULT_OK(mCollector->onWakeUpCollection(getNowMillis(), mMockUidStatsCollector,
1411                                                     mMockProcStatCollector));
1412 
1413     const auto actualCollectionInfo = mCollectorPeer->getWakeUpCollectionInfo();
1414 
1415     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1416             << "Wake-up collection info doesn't match.\nExpected:\n"
1417             << expectedCollectionInfo.toString() << "\nActual:\n"
1418             << actualCollectionInfo.toString();
1419 
1420     ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1421             << "Boot-time, periodic, and user-switch collections shouldn't be reported";
1422 }
1423 
TEST_F(PerformanceProfilerTest,TestOnSystemStartup)1424 TEST_F(PerformanceProfilerTest, TestOnSystemStartup) {
1425     setupMultipleCollections();
1426 
1427     ResourceStats resourceStats = {};
1428     ASSERT_RESULT_OK(mCollector->onBoottimeCollection(getNowMillis(), mMockUidStatsCollector,
1429                                                       mMockProcStatCollector, &resourceStats));
1430     ASSERT_RESULT_OK(mCollector->onWakeUpCollection(getNowMillis(), mMockUidStatsCollector,
1431                                                     mMockProcStatCollector));
1432 
1433     auto actualBoottimeCollection = mCollectorPeer->getBoottimeCollectionInfo();
1434     auto actualWakeUpCollection = mCollectorPeer->getWakeUpCollectionInfo();
1435 
1436     EXPECT_THAT(actualBoottimeCollection.records.size(), 1)
1437             << "Boot-time collection records is empty.";
1438     EXPECT_THAT(actualWakeUpCollection.records.size(), 1) << "Wake-up collection records is empty.";
1439 
1440     ASSERT_RESULT_OK(mCollector->onSystemStartup());
1441 
1442     actualBoottimeCollection = mCollectorPeer->getBoottimeCollectionInfo();
1443     actualWakeUpCollection = mCollectorPeer->getWakeUpCollectionInfo();
1444 
1445     EXPECT_THAT(actualBoottimeCollection.records.size(), 0)
1446             << "Boot-time collection records is not empty.";
1447     EXPECT_THAT(actualWakeUpCollection.records.size(), 0)
1448             << "Wake-up collection records is not empty.";
1449 }
1450 
TEST_F(PerformanceProfilerTest,TestOnUserSwitchCollection)1451 TEST_F(PerformanceProfilerTest, TestOnUserSwitchCollection) {
1452     std::vector<UserSwitchCollectionInfo> expected;
1453     expected.push_back(setupUserSwitchCollection(kTestBaseUserId, kTestBaseUserId + 1));
1454 
1455     ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), kTestBaseUserId,
1456                                                         kTestBaseUserId + 1, mMockUidStatsCollector,
1457                                                         mMockProcStatCollector));
1458 
1459     auto actual = mCollectorPeer->getUserSwitchCollectionInfos();
1460 
1461     EXPECT_THAT(actual, UserSwitchCollectionsEq(expected))
1462             << "User switch collection infos doesn't match.\nExpected:\n"
1463             << toString(expected) << "\nActual:\n"
1464             << toString(actual);
1465 
1466     // Continuation of the previous user switch collection
1467     std::vector<UidStats> nextUidStats = {
1468             {.packageInfo = constructPackageInfo("mount", 1009),
1469              .cpuTimeMillis = 0,  // No TopNCpuTimes will be registered
1470              .ioStats = {/*fgRdBytes=*/0,
1471                          /*bgRdBytes=*/5'000,
1472                          /*fgWrBytes=*/0,
1473                          /*bgWrBytes=*/3'000,
1474                          /*fgFsync=*/0, /*bgFsync=*/50},
1475              .procStats = {.cpuTimeMillis = 50,
1476                            .cpuCycles = 3'500,
1477                            .totalMajorFaults = 6'000,
1478                            .totalTasksCount = 1,
1479                            .ioBlockedTasksCount = 2,
1480                            .processStatsByPid = {{/*pid=*/100,
1481                                                   {/*comm=*/"disk I/O", /*startTime=*/234,
1482                                                    /*cpuTimeMillis=*/50,
1483                                                    /*totalCpuCycle=*/3'500,
1484                                                    /*totalMajorFaults=*/6'000,
1485                                                    /*totalTasksCount=*/1,
1486                                                    /*ioBlockedTasksCount=*/2,
1487                                                    /*cpuCyclesByTid=*/{{100, 3'500}}}}}}}};
1488 
1489     UserPackageSummaryStats nextUserPackageSummaryStats = {
1490             .topNIoReads = {{1009, "mount", UserPackageStats::IoStatsView{{0, 5'000}, {0, 50}}}},
1491             .topNIoWrites = {{1009, "mount", UserPackageStats::IoStatsView{{0, 3'000}, {0, 50}}}},
1492             .topNIoBlocked = {{1009, "mount",
1493                                UserPackageStats::ProcSingleStatsView{2, {{"disk I/O", 2}}}}},
1494             .topNMajorFaults = {{1009, "mount",
1495                                  UserPackageStats::ProcSingleStatsView{6'000,
1496                                                                        {{"disk I/O", 6'000}}}}},
1497             .totalIoStats = {{0, 5'000}, {0, 3'000}, {0, 50}},
1498             .taskCountByUid = {{1009, 1}},
1499             .totalCpuTimeMillis = 48'376,
1500             .totalCpuCycles = 3'500,
1501             .totalMajorFaults = 6'000,
1502             .majorFaultsPercentChange = (6'000.0 - 84'345.0) / 84'345.0 * 100.0,
1503     };
1504 
1505     // TODO(b/336835345): Revisit this test and update the below logic to use setupNextCollection
1506     //  instead.
1507     auto nextPressureLevelDurations = injectPressureLevelTransitions(/*advanceUptimeSec=*/2);
1508     advanceTime(/*durationMillis=*/2000);
1509 
1510     const auto statsInfo = getSampleStatsInfo();
1511     ProcStatInfo nextProcStatInfo = statsInfo.procStatInfo;
1512     SystemSummaryStats nextSystemSummaryStats = statsInfo.systemSummaryStats;
1513 
1514     nextProcStatInfo.contextSwitchesCount = 300;
1515     nextSystemSummaryStats.totalCpuCycles = 3'500;
1516     nextSystemSummaryStats.contextSwitchesCount = 300;
1517 
1518     EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillOnce(Return(nextUidStats));
1519     EXPECT_CALL(*mMockProcStatCollector, deltaStats()).WillOnce(Return(nextProcStatInfo));
1520 
1521     ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), kTestBaseUserId,
1522                                                         kTestBaseUserId + 1, mMockUidStatsCollector,
1523                                                         mMockProcStatCollector));
1524 
1525     actual = mCollectorPeer->getUserSwitchCollectionInfos();
1526 
1527     expected[0].records.push_back(
1528             PerfStatsRecord{.collectionTimeMillis = getNowMillis(),
1529                             .systemSummaryStats = nextSystemSummaryStats,
1530                             .userPackageSummaryStats = nextUserPackageSummaryStats,
1531                             .memoryPressureLevelDurations = nextPressureLevelDurations});
1532 
1533     EXPECT_THAT(actual, UserSwitchCollectionsEq(expected))
1534             << "User switch collection info after continuation doesn't match.\nExpected:\n"
1535             << toString(expected) << "\nActual:\n"
1536             << toString(actual);
1537 
1538     ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1539             << "Boot-time, wake-up and periodic collections shouldn't be reported";
1540 }
1541 
TEST_F(PerformanceProfilerTest,TestUserSwitchCollectionsMaxCacheSize)1542 TEST_F(PerformanceProfilerTest, TestUserSwitchCollectionsMaxCacheSize) {
1543     std::vector<UserSwitchCollectionInfo> expected;
1544     userid_t userIdToTriggerEviction = kTestBaseUserId + kTestMaxUserSwitchEvents;
1545 
1546     for (userid_t userId = kTestBaseUserId; userId < userIdToTriggerEviction; ++userId) {
1547         expected.push_back(setupUserSwitchCollection(userId, userId + 1));
1548         ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), userId, userId + 1,
1549                                                             mMockUidStatsCollector,
1550                                                             mMockProcStatCollector));
1551     }
1552 
1553     auto actual = mCollectorPeer->getUserSwitchCollectionInfos();
1554 
1555     EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents);
1556 
1557     EXPECT_THAT(actual, UserSwitchCollectionsEq(expected))
1558             << "User switch collection infos don't match before crossing limit.\nExpected:\n"
1559             << toString(expected) << "\nActual:\n"
1560             << toString(actual);
1561 
1562     // Add new user switch event with max cache size. The oldest user switch event should be dropped
1563     // and the new one added to the cache.
1564     expected.push_back(
1565             setupUserSwitchCollection(userIdToTriggerEviction, userIdToTriggerEviction + 1));
1566     expected.erase(expected.begin());
1567 
1568     ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), userIdToTriggerEviction,
1569                                                         userIdToTriggerEviction + 1,
1570                                                         mMockUidStatsCollector,
1571                                                         mMockProcStatCollector));
1572 
1573     actual = mCollectorPeer->getUserSwitchCollectionInfos();
1574 
1575     EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents);
1576 
1577     EXPECT_THAT(actual, UserSwitchCollectionsEq(expected))
1578             << "User switch collection infos don't match after crossing limit.\nExpected:\n"
1579             << toString(expected) << "\nActual:\n"
1580             << toString(actual);
1581 }
1582 
TEST_F(PerformanceProfilerTest,TestOnPeriodicCollection)1583 TEST_F(PerformanceProfilerTest, TestOnPeriodicCollection) {
1584     const auto [expectedCollectionInfo, expectedResourceStats] =
1585             setupFirstCollection(kTestPeriodicCollectionBufferSize);
1586 
1587     ResourceStats actualResourceStats = {};
1588     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1589                                                       mMockUidStatsCollector,
1590                                                       mMockProcStatCollector,
1591                                                       &actualResourceStats));
1592 
1593     const auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1594 
1595     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1596             << "Periodic collection info doesn't match.\nExpected:\n"
1597             << expectedCollectionInfo.toString() << "\nActual:\n"
1598             << actualCollectionInfo.toString();
1599 
1600     ASSERT_EQ(actualResourceStats, expectedResourceStats)
1601             << "Expected: " << expectedResourceStats.toString()
1602             << "\nActual: " << actualResourceStats.toString();
1603 
1604     ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1605             << "Boot-time, wake-up and user-switch collections shouldn't be reported";
1606 }
1607 
TEST_F(PerformanceProfilerTest,TestOnPeriodicCollectionWithSendingUsageStatsDisabled)1608 TEST_F(PerformanceProfilerTest, TestOnPeriodicCollectionWithSendingUsageStatsDisabled) {
1609     mCollectorPeer->setSendResourceUsageStatsEnabled(false);
1610 
1611     auto [expectedCollectionInfo, _] = setupFirstCollection(kTestPeriodicCollectionBufferSize);
1612 
1613     ResourceStats actualResourceStats = {};
1614     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1615                                                       mMockUidStatsCollector,
1616                                                       mMockProcStatCollector,
1617                                                       &actualResourceStats));
1618 
1619     const auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1620     const ResourceStats expectedResourceStats = {};
1621 
1622     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1623             << "Periodic collection info doesn't match.\nExpected:\n"
1624             << expectedCollectionInfo.toString() << "\nActual:\n"
1625             << actualCollectionInfo.toString();
1626 
1627     ASSERT_EQ(actualResourceStats, expectedResourceStats)
1628             << "Expected: " << expectedResourceStats.toString()
1629             << "\nActual: " << actualResourceStats.toString();
1630 
1631     ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1632             << "Boot-time, wake-up and user-switch collections shouldn't be reported";
1633 }
1634 
TEST_F(PerformanceProfilerTest,TestOnCustomCollectionWithoutPackageFilter)1635 TEST_F(PerformanceProfilerTest, TestOnCustomCollectionWithoutPackageFilter) {
1636     auto [expectedCollectionInfo, expectedResourceStats] = setupFirstCollection();
1637 
1638     ResourceStats actualResourceStats = {};
1639     ASSERT_RESULT_OK(mCollector->onCustomCollection(getNowMillis(), SystemState::NORMAL_MODE, {},
1640                                                     mMockUidStatsCollector, mMockProcStatCollector,
1641                                                     &actualResourceStats));
1642 
1643     const auto actualCollectionInfo = mCollectorPeer->getCustomCollectionInfo();
1644 
1645     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1646             << "Custom collection info doesn't match.\nExpected:\n"
1647             << expectedCollectionInfo.toString() << "\nActual:\n"
1648             << actualCollectionInfo.toString();
1649 
1650     ASSERT_EQ(actualResourceStats, expectedResourceStats)
1651             << "Expected: " << expectedResourceStats.toString()
1652             << "\nActual: " << actualResourceStats.toString();
1653 
1654     ASSERT_NO_FATAL_FAILURE(checkCustomDumpContents()) << "Custom collection should be reported";
1655 
1656     TemporaryFile customDump;
1657     ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(customDump.fd));
1658 
1659     // Should clear the cache.
1660     ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(-1));
1661 
1662     expectedCollectionInfo.records.clear();
1663     const CollectionInfo& emptyCollectionInfo = mCollectorPeer->getCustomCollectionInfo();
1664     EXPECT_THAT(emptyCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1665             << "Custom collection should be cleared.";
1666 }
1667 
TEST_F(PerformanceProfilerTest,TestOnCustomCollectionWithPackageFilter)1668 TEST_F(PerformanceProfilerTest, TestOnCustomCollectionWithPackageFilter) {
1669     // Filter by package name should ignore this limit with package filter.
1670     mCollectorPeer->setTopNStatsPerCategory(1);
1671 
1672     auto [expectedCollectionInfo, expectedResourceStats] = setupFirstCollection();
1673 
1674     ResourceStats actualResourceStats = {};
1675     ASSERT_RESULT_OK(mCollector->onCustomCollection(getNowMillis(), SystemState::NORMAL_MODE,
1676                                                     {"mount", "com.google.android.car.kitchensink"},
1677                                                     mMockUidStatsCollector, mMockProcStatCollector,
1678                                                     &actualResourceStats));
1679     const auto actualCollectionInfo = mCollectorPeer->getCustomCollectionInfo();
1680 
1681     UserPackageSummaryStats userPackageSummaryStats{
1682             .topNCpuTimes = {{1009, "mount",
1683                               UserPackageStats::ProcCpuStatsView{50,
1684                                                                  4'000,
1685                                                                  {{100, "disk I/O", 50, 4'000}}}},
1686                              {1002001, "com.google.android.car.kitchensink",
1687                               UserPackageStats::ProcCpuStatsView{60,
1688                                                                  10'000,
1689                                                                  {{1001, "CTS", 30, 5'000},
1690                                                                   {1000, "KitchenSinkApp", 25,
1691                                                                    4'000}}}}},
1692             .topNIoReads = {{1009, "mount", UserPackageStats::IoStatsView{{0, 14'000}, {0, 100}}},
1693                             {1002001, "com.google.android.car.kitchensink",
1694                              UserPackageStats::IoStatsView{{0, 3'400}, {0, 200}}}},
1695             .topNIoWrites = {{1009, "mount", UserPackageStats::IoStatsView{{0, 16'000}, {0, 100}}},
1696                              {1002001, "com.google.android.car.kitchensink",
1697                               UserPackageStats::IoStatsView{{0, 6'700}, {0, 200}}}},
1698             .topNIoBlocked =
1699                     {{1009, "mount", UserPackageStats::ProcSingleStatsView{1, {{"disk I/O", 1}}}},
1700                      {1002001, "com.google.android.car.kitchensink",
1701                       UserPackageStats::ProcSingleStatsView{3,
1702                                                             {{"CTS", 2}, {"KitchenSinkApp", 1}}}}},
1703             .topNMajorFaults = {{1009, "mount",
1704                                  UserPackageStats::ProcSingleStatsView{11'000,
1705                                                                        {{"disk I/O", 11'000}}}},
1706                                 {1002001, "com.google.android.car.kitchensink",
1707                                  UserPackageStats::ProcSingleStatsView{22'445,
1708                                                                        {{"KitchenSinkApp", 12'345},
1709                                                                         {"CTS", 10'100}}}}},
1710             .topNMemStats =
1711                     {{1009, "mount",
1712                       UserPackageStats::UidMemoryStats{{/*rssKb=*/2010, /*pssKb=*/1635,
1713                                                         /*ussKb=*/1286, /*swapPssKb=*/600},
1714                                                        kTestIsSmapsRollupSupported,
1715                                                        {{"disk I/O",
1716                                                          {/*rssKb=*/2010, /*pssKb=*/1635,
1717                                                           /*ussKb=*/1286, /*swapPssKb=*/600}}}}},
1718                      {1002001, "com.google.android.car.kitchensink",
1719                       UserPackageStats::UidMemoryStats{{/*rssKb=*/2000, /*pssKb=*/1645,
1720                                                         /*ussKb=*/1286, /*swapPssKb=*/600},
1721                                                        kTestIsSmapsRollupSupported,
1722                                                        {{"KitchenSinkApp",
1723                                                          {/*rssKb=*/1000, /*pssKb=*/875,
1724                                                           /*ussKb=*/630, /*swapPssKb=*/400}},
1725                                                         {"CTS",
1726                                                          {/*rssKb=*/1000, /*pssKb=*/770,
1727                                                           /*ussKb=*/656, /*swapPssKb=*/200}}}}}},
1728             .totalIoStats = {{1000, 21'600}, {300, 28'300}, {600, 600}},
1729             .taskCountByUid = {{1009, 1}, {1002001, 5}},
1730             .totalCpuTimeMillis = 48'376,
1731             .totalCpuCycles = 64'000,
1732             .totalMajorFaults = 84'345,
1733             .totalRssKb = 5010,
1734             .totalPssKb = 4145,
1735             .majorFaultsPercentChange = 0.0,
1736     };
1737     applyFeatureFilter(&userPackageSummaryStats);
1738     expectedCollectionInfo.records[0].userPackageSummaryStats = userPackageSummaryStats;
1739 
1740     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1741             << "Custom collection info doesn't match.\nExpected:\n"
1742             << expectedCollectionInfo.toString() << "\nActual:\n"
1743             << actualCollectionInfo.toString();
1744 
1745     ASSERT_EQ(actualResourceStats, expectedResourceStats)
1746             << "Expected: " << expectedResourceStats.toString()
1747             << "\nActual: " << actualResourceStats.toString();
1748 
1749     ASSERT_NO_FATAL_FAILURE(checkCustomDumpContents()) << "Custom collection should be reported";
1750 
1751     TemporaryFile customDump;
1752     ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(customDump.fd));
1753 
1754     // Should clear the cache.
1755     ASSERT_RESULT_OK(mCollector->onCustomCollectionDump(-1));
1756 
1757     expectedCollectionInfo.records.clear();
1758     const CollectionInfo& emptyCollectionInfo = mCollectorPeer->getCustomCollectionInfo();
1759     EXPECT_THAT(emptyCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1760             << "Custom collection should be cleared.";
1761 }
1762 
TEST_F(PerformanceProfilerTest,TestOnPeriodicCollectionWithTrimmingStatsAfterTopN)1763 TEST_F(PerformanceProfilerTest, TestOnPeriodicCollectionWithTrimmingStatsAfterTopN) {
1764     mCollectorPeer->setTopNStatsPerCategory(1);
1765     mCollectorPeer->setTopNStatsPerSubcategory(1);
1766 
1767     auto [expectedCollectionInfo, expectedResourceStats] =
1768             setupFirstCollection(kTestPeriodicCollectionBufferSize);
1769 
1770     // Top N stats per category/sub-category is set to 1, so remove entries in the
1771     // expected value to match this.
1772     ASSERT_FALSE(expectedResourceStats.resourceUsageStats->uidResourceUsageStats.empty());
1773     UidResourceUsageStats& kitchenSinkStats =
1774             expectedResourceStats.resourceUsageStats->uidResourceUsageStats.at(1);
1775     ASSERT_FALSE(kitchenSinkStats.processCpuUsageStats.empty());
1776     kitchenSinkStats.processCpuUsageStats.pop_back();
1777 
1778     ResourceStats actualResourceStats = {};
1779     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1780                                                       mMockUidStatsCollector,
1781                                                       mMockProcStatCollector,
1782                                                       &actualResourceStats));
1783 
1784     const auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1785 
1786     UserPackageSummaryStats userPackageSummaryStats{
1787             .topNCpuTimes = {{1012345, "1012345",
1788                               UserPackageStats::ProcCpuStatsView{100,
1789                                                                  50'000,
1790                                                                  {{2345, "MapsApp", 100,
1791                                                                    50'000}}}}},
1792             .topNIoReads = {{1009, "mount", UserPackageStats::IoStatsView{{0, 14'000}, {0, 100}}}},
1793             .topNIoWrites = {{1009, "mount", UserPackageStats::IoStatsView{{0, 16'000}, {0, 100}}}},
1794             .topNIoBlocked = {{1002001, "com.google.android.car.kitchensink",
1795                                UserPackageStats::ProcSingleStatsView{3, {{"CTS", 2}}}}},
1796             .topNMajorFaults = {{1012345, "1012345",
1797                                  UserPackageStats::ProcSingleStatsView{50'900,
1798                                                                        {{"MapsApp", 50'900}}}}},
1799             .topNMemStats = {{1002001, "com.google.android.car.kitchensink",
1800                               UserPackageStats::UidMemoryStats{{/*rssKb=*/2000, /*pssKb=*/1645,
1801                                                                 /*ussKb=*/1286, /*swapPssKb=*/600},
1802                                                                kTestIsSmapsRollupSupported,
1803                                                                {{"KitchenSinkApp",
1804                                                                  {/*rssKb=*/1000, /*pssKb=*/875,
1805                                                                   /*ussKb=*/630,
1806                                                                   /*swapPssKb=*/400}}}}}},
1807             .totalIoStats = {{1000, 21'600}, {300, 28'300}, {600, 600}},
1808             .taskCountByUid = {{1009, 1}, {1002001, 5}, {1012345, 4}},
1809             .totalCpuTimeMillis = 48'376,
1810             .totalCpuCycles = 64'000,
1811             .totalMajorFaults = 84'345,
1812             .totalRssKb = 5010,
1813             .totalPssKb = 4145,
1814             .majorFaultsPercentChange = 0.0,
1815     };
1816     applyFeatureFilter(&userPackageSummaryStats);
1817     expectedCollectionInfo.records[0].userPackageSummaryStats = userPackageSummaryStats;
1818 
1819     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1820             << "Periodic collection info doesn't match.\nExpected:\n"
1821             << expectedCollectionInfo.toString() << "\nActual:\n"
1822             << actualCollectionInfo.toString();
1823 
1824     ASSERT_EQ(actualResourceStats, expectedResourceStats)
1825             << "Expected: " << expectedResourceStats.toString()
1826             << "\nActual: " << actualResourceStats.toString();
1827 
1828     ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1829             << "Boot-time, wake-up and user-switch collections shouldn't be reported";
1830 }
1831 
TEST_F(PerformanceProfilerTest,TestConsecutiveOnPeriodicCollection)1832 TEST_F(PerformanceProfilerTest, TestConsecutiveOnPeriodicCollection) {
1833     auto [expectedCollectionInfo, expectedResourceStats] =
1834             setupFirstCollection(kTestPeriodicCollectionBufferSize);
1835 
1836     ResourceStats actualResourceStats = {};
1837     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1838                                                       mMockUidStatsCollector,
1839                                                       mMockProcStatCollector,
1840                                                       &actualResourceStats));
1841 
1842     for (size_t i = 1; i < kTestPeriodicCollectionBufferSize; i++) {
1843         setupNextCollection(&expectedCollectionInfo, &expectedResourceStats, /*multiplier=*/2);
1844 
1845         ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1846                                                           mMockUidStatsCollector,
1847                                                           mMockProcStatCollector,
1848                                                           &actualResourceStats));
1849 
1850         ASSERT_EQ(actualResourceStats, expectedResourceStats)
1851                 << "Resource stats don't match for collection " << i
1852                 << "\nExpected: " << expectedResourceStats.toString()
1853                 << "\nActual: " << actualResourceStats.toString();
1854     }
1855 
1856     auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1857 
1858     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1859             << "Periodic collection info doesn't match.\nExpected:\n"
1860             << expectedCollectionInfo.toString() << "\nActual:\n"
1861             << actualCollectionInfo.toString();
1862 
1863     // Collection beyond kTestPeriodicCollectionBufferSize should evict the first collection data.
1864     setupNextCollection(&expectedCollectionInfo, &expectedResourceStats, /*multiplier=*/2);
1865     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1866                                                       mMockUidStatsCollector,
1867                                                       mMockProcStatCollector,
1868                                                       &actualResourceStats));
1869 
1870     expectedCollectionInfo.records.erase(expectedCollectionInfo.records.begin());
1871     actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
1872 
1873     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
1874             << "Periodic collection info doesn't match after exceeding cache limit.\nExpected:\n"
1875             << expectedCollectionInfo.toString() << "\nActual:\n"
1876             << actualCollectionInfo.toString();
1877 
1878     ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
1879             << "Boot-time, wake-up and user-switch collection shouldn't be reported";
1880 }
1881 
TEST_F(PerformanceProfilerTest,TestBoottimeCollectionCacheEvictionAfterTimeout)1882 TEST_F(PerformanceProfilerTest, TestBoottimeCollectionCacheEvictionAfterTimeout) {
1883     setupMultipleCollections();
1884 
1885     ResourceStats actualResourceStats = {};
1886     ASSERT_RESULT_OK(mCollector->onBoottimeCollection(getNowMillis(), mMockUidStatsCollector,
1887                                                       mMockProcStatCollector,
1888                                                       &actualResourceStats));
1889 
1890     auto actualCollectionInfo = mCollectorPeer->getBoottimeCollectionInfo();
1891 
1892     EXPECT_THAT(actualCollectionInfo.records.size(), 1)
1893             << "Boot-time collection info missing after collection";
1894 
1895     advanceTime(/*durationMillis=*/kTestSystemEventDataCacheDurationSec.count() * 1000);
1896 
1897     // Call |onPeriodicCollection| 1 hour past the last boot-time collection event.
1898     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1899                                                       mMockUidStatsCollector,
1900                                                       mMockProcStatCollector,
1901                                                       &actualResourceStats));
1902 
1903     actualCollectionInfo = mCollectorPeer->getBoottimeCollectionInfo();
1904 
1905     EXPECT_THAT(actualCollectionInfo.records.empty(), true)
1906             << "Boot-time collection info records are not empty after cache eviction period";
1907 }
1908 
TEST_F(PerformanceProfilerTest,TestWakeUpCollectionCacheEvictionAfterTimeout)1909 TEST_F(PerformanceProfilerTest, TestWakeUpCollectionCacheEvictionAfterTimeout) {
1910     setupMultipleCollections();
1911 
1912     ASSERT_RESULT_OK(mCollector->onWakeUpCollection(getNowMillis(), mMockUidStatsCollector,
1913                                                     mMockProcStatCollector));
1914 
1915     auto actualCollectionInfo = mCollectorPeer->getWakeUpCollectionInfo();
1916 
1917     EXPECT_THAT(actualCollectionInfo.records.size(), 1)
1918             << "Wake-up collection info missing after collection";
1919 
1920     advanceTime(/*durationMillis=*/kTestSystemEventDataCacheDurationSec.count() * 1000);
1921     ResourceStats actualResourceStats = {};
1922 
1923     // Call |onPeriodicCollection| 1 hour past the last wake-up collection event.
1924     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1925                                                       mMockUidStatsCollector,
1926                                                       mMockProcStatCollector,
1927                                                       &actualResourceStats));
1928 
1929     actualCollectionInfo = mCollectorPeer->getWakeUpCollectionInfo();
1930 
1931     EXPECT_THAT(actualCollectionInfo.records.empty(), true)
1932             << "Wake-up collection info records are not empty after cache eviction period";
1933 }
1934 
TEST_F(PerformanceProfilerTest,TestUserSwitchCollectionCacheEvictionAfterTimeout)1935 TEST_F(PerformanceProfilerTest, TestUserSwitchCollectionCacheEvictionAfterTimeout) {
1936     userid_t userIdToTriggerEviction = kTestBaseUserId + kTestMaxUserSwitchEvents;
1937     for (userid_t userId = kTestBaseUserId; userId < userIdToTriggerEviction; ++userId) {
1938         ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), userId, userId + 1,
1939                                                             mMockUidStatsCollector,
1940                                                             mMockProcStatCollector));
1941         advanceTime(/*advanceUptimeMillis=*/kTestSystemEventDataCacheDurationSec.count() * 1000);
1942     }
1943 
1944     const auto& actual = mCollectorPeer->getUserSwitchCollectionInfos();
1945 
1946     EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents);
1947 
1948     ResourceStats resourceStats = {};
1949     for (int i = 1; i <= kTestMaxUserSwitchEvents; ++i) {
1950         ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1951                                                           mMockUidStatsCollector,
1952                                                           mMockProcStatCollector, &resourceStats));
1953 
1954         const auto& actual = mCollectorPeer->getUserSwitchCollectionInfos();
1955 
1956         EXPECT_THAT(actual.size(), kTestMaxUserSwitchEvents - i)
1957                 << "Expired user switch collection infos are still retained after " << i
1958                 << "iterations";
1959 
1960         advanceTime(/*durationMillis=*/kTestSystemEventDataCacheDurationSec.count() * 1000);
1961     }
1962 }
1963 
TEST_F(PerformanceProfilerTest,TestOnDumpProto)1964 TEST_F(PerformanceProfilerTest, TestOnDumpProto) {
1965     auto statsInfo = getSampleStatsInfo();
1966 
1967     EXPECT_CALL(*mMockUidStatsCollector, deltaStats()).WillRepeatedly(Return(statsInfo.uidStats));
1968     EXPECT_CALL(*mMockProcStatCollector, deltaStats())
1969             .WillRepeatedly(Return(statsInfo.procStatInfo));
1970 
1971     DataProcessorInterface::CollectionIntervals collectionIntervals =
1972             {.mBoottimeIntervalMillis = std::chrono::milliseconds(1),
1973              .mPeriodicIntervalMillis = std::chrono::milliseconds(10),
1974              .mUserSwitchIntervalMillis = std::chrono::milliseconds(100),
1975              .mWakeUpIntervalMillis = std::chrono::milliseconds(1000),
1976              .mCustomIntervalMillis = std::chrono::milliseconds(10000)};
1977 
1978     ResourceStats actualResourceStats = {};
1979 
1980     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
1981                                                       mMockUidStatsCollector,
1982                                                       mMockProcStatCollector,
1983                                                       &actualResourceStats));
1984 
1985     ASSERT_RESULT_OK(mCollector->onBoottimeCollection(getNowMillis(), mMockUidStatsCollector,
1986                                                       mMockProcStatCollector,
1987                                                       &actualResourceStats));
1988 
1989     ASSERT_RESULT_OK(mCollector->onWakeUpCollection(getNowMillis(), mMockUidStatsCollector,
1990                                                     mMockProcStatCollector));
1991 
1992     ASSERT_RESULT_OK(mCollector->onCustomCollection(getNowMillis(), SystemState::NORMAL_MODE, {},
1993                                                     mMockUidStatsCollector, mMockProcStatCollector,
1994                                                     &actualResourceStats));
1995 
1996     ASSERT_RESULT_OK(mCollector->onUserSwitchCollection(getNowMillis(), kTestBaseUserId,
1997                                                         kTestBaseUserId + 1, mMockUidStatsCollector,
1998                                                         mMockProcStatCollector));
1999 
2000     util::ProtoOutputStream proto;
2001     mCollector->onDumpProto(collectionIntervals, proto);
2002 
2003     PerformanceProfilerDump performanceProfilerDump;
2004     ASSERT_TRUE(performanceProfilerDump.ParseFromString(toString(&proto)));
2005 
2006     PerformanceStats performanceStats = performanceProfilerDump.performance_stats();
2007     auto bootTimeStats = performanceStats.boot_time_stats();
2008     EXPECT_EQ(bootTimeStats.collection_interval_millis(), 1);
2009     for (auto& record : bootTimeStats.records()) {
2010         EXPECT_THAT(record,
2011                     StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2012                                        statsInfo.systemSummaryStats, getNowMillis()));
2013     }
2014 
2015     for (const auto& userSwitchStat : performanceStats.user_switch_stats()) {
2016         EXPECT_EQ(userSwitchStat.to_user_id(), kTestBaseUserId + 1);
2017         EXPECT_EQ(userSwitchStat.from_user_id(), kTestBaseUserId);
2018         auto userSwitchCollection = userSwitchStat.user_switch_collection();
2019         EXPECT_EQ(userSwitchCollection.collection_interval_millis(), 100);
2020         for (const auto& record : userSwitchCollection.records()) {
2021             EXPECT_THAT(record,
2022                         StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2023                                            statsInfo.systemSummaryStats, getNowMillis()));
2024         }
2025     }
2026 
2027     auto wakeUpStats = performanceStats.wake_up_stats();
2028     EXPECT_EQ(wakeUpStats.collection_interval_millis(), 1000);
2029     for (auto& record : wakeUpStats.records()) {
2030         EXPECT_THAT(record,
2031                     StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2032                                        statsInfo.systemSummaryStats, getNowMillis()));
2033     }
2034 
2035     auto lastNMinutesStats = performanceStats.last_n_minutes_stats();
2036     EXPECT_EQ(lastNMinutesStats.collection_interval_millis(), 10);
2037     for (auto& record : lastNMinutesStats.records()) {
2038         EXPECT_THAT(record,
2039                     StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2040                                        statsInfo.systemSummaryStats, getNowMillis()));
2041     }
2042 
2043     auto customCollectionStats = performanceStats.custom_collection_stats();
2044     EXPECT_EQ(customCollectionStats.collection_interval_millis(), 10000);
2045     for (auto& record : customCollectionStats.records()) {
2046         EXPECT_THAT(record,
2047                     StatsRecordProtoEq(statsInfo.userPackageSummaryStats,
2048                                        statsInfo.systemSummaryStats, getNowMillis()));
2049     }
2050 }
2051 
TEST_F(PerformanceProfilerTest,TestOnPeriodicCollectionWithSmapsRollupSupportInverted)2052 TEST_F(PerformanceProfilerTest, TestOnPeriodicCollectionWithSmapsRollupSupportInverted) {
2053     mCollectorPeer->setSmapsRollupSupportedEnabled(!kTestIsSmapsRollupSupported);
2054     auto [expectedCollectionInfo, expectedResourceStats] =
2055             setupFirstCollection(kTestPeriodicCollectionBufferSize, !kTestIsSmapsRollupSupported);
2056 
2057     ResourceStats actualResourceStats = {};
2058     ASSERT_RESULT_OK(mCollector->onPeriodicCollection(getNowMillis(), SystemState::NORMAL_MODE,
2059                                                       mMockUidStatsCollector,
2060                                                       mMockProcStatCollector,
2061                                                       &actualResourceStats));
2062 
2063     const auto actualCollectionInfo = mCollectorPeer->getPeriodicCollectionInfo();
2064 
2065     EXPECT_THAT(actualCollectionInfo, CollectionInfoEq(expectedCollectionInfo))
2066             << "When smaps rollup is not supported, periodic collection info doesn't match."
2067             << "\nExpected:\n"
2068             << expectedCollectionInfo.toString() << "\nActual:\n"
2069             << actualCollectionInfo.toString();
2070 
2071     ASSERT_EQ(actualResourceStats, expectedResourceStats)
2072             << "Expected: " << expectedResourceStats.toString()
2073             << "\nActual: " << actualResourceStats.toString();
2074 
2075     ASSERT_NO_FATAL_FAILURE(checkDumpContents(/*wantedEmptyCollectionInstances=*/3))
2076             << "Boot-time, wake-up and user-switch collections shouldn't be reported";
2077 }
2078 
2079 }  // namespace watchdog
2080 }  // namespace automotive
2081 }  // namespace android
2082