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