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 "ProcPidDir.h"
18 #include "UidProcStatsCollector.h"
19 #include "UidProcStatsCollectorTestUtils.h"
20
21 #include <android-base/file.h>
22 #include <android-base/stringprintf.h>
23 #include <gmock/gmock.h>
24
25 #include <inttypes.h>
26
27 #include <algorithm>
28 #include <string>
29
30 namespace android {
31 namespace automotive {
32 namespace watchdog {
33
34 using ::android::automotive::watchdog::testing::populateProcPidDir;
35 using ::android::base::StringAppendF;
36 using ::android::base::StringPrintf;
37 using ::testing::UnorderedPointwise;
38
39 namespace {
40
41 MATCHER(UidProcStatsByUidEq, "") {
42 const auto& actual = std::get<0>(arg);
43 const auto& expected = std::get<1>(arg);
44 return actual.first == expected.first &&
45 ExplainMatchResult(UidProcStatsEq(expected.second), actual.second, result_listener);
46 }
47
pidStatusStr(pid_t pid,uid_t uid)48 std::string pidStatusStr(pid_t pid, uid_t uid) {
49 return StringPrintf("Pid:\t%" PRIu32 "\nTgid:\t%" PRIu32 "\nUid:\t%" PRIu32 "\n", pid, pid,
50 uid);
51 }
52
toString(const std::unordered_map<uid_t,UidProcStats> & uidProcStatsByUid)53 std::string toString(const std::unordered_map<uid_t, UidProcStats>& uidProcStatsByUid) {
54 std::string buffer;
55 StringAppendF(&buffer, "Number of UIDs: %" PRIi32 "\n",
56 static_cast<int>(uidProcStatsByUid.size()));
57 for (const auto& [uid, stats] : uidProcStatsByUid) {
58 StringAppendF(&buffer, "{UID: %d, %s}", uid, stats.toString().c_str());
59 }
60 return buffer;
61 }
62
ticksToMillis(int32_t clockTicks)63 int64_t ticksToMillis(int32_t clockTicks) {
64 return (clockTicks * 1000) / sysconf(_SC_CLK_TCK);
65 }
66
67 } // namespace
68
TEST(UidProcStatsCollectorTest,TestValidStatFiles)69 TEST(UidProcStatsCollectorTest, TestValidStatFiles) {
70 std::unordered_map<pid_t, std::vector<pid_t>> pidToTids = {
71 {1, {1, 453}},
72 {1000, {1000, 1100}},
73 };
74
75 std::unordered_map<pid_t, std::string> perProcessStat = {
76 {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 6 4 0 0 0 0 2 0 19\n"},
77 {1000, "1000 (system_server) D 1 0 0 0 0 0 0 0 600 0 8000 4000 0 0 0 0 2 0 13400\n"},
78 };
79
80 std::unordered_map<pid_t, std::string> perProcessStatus = {
81 {1, pidStatusStr(1, 0)},
82 {1000, pidStatusStr(1000, 10001234)},
83 };
84
85 std::unordered_map<pid_t, std::string> perThreadStat = {
86 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 3 2 0 0 0 0 2 0 19\n"},
87 {453, "453 (init) D 0 0 0 0 0 0 0 0 20 0 3 2 0 0 0 0 2 0 275\n"},
88 {1000, "1000 (system_server) D 1 0 0 0 0 0 0 0 250 0 4000 2000 0 0 0 0 2 0 13400\n"},
89 {1100, "1100 (system_server) D 1 0 0 0 0 0 0 0 350 0 4000 2000 0 0 0 0 2 0 13900\n"},
90 };
91
92 std::unordered_map<uid_t, UidProcStats> expected =
93 {{0,
94 UidProcStats{.cpuTimeMillis = ticksToMillis(10),
95 .totalMajorFaults = 220,
96 .totalTasksCount = 2,
97 .ioBlockedTasksCount = 1,
98 .processStatsByPid = {{1,
99 {"init", ticksToMillis(19), ticksToMillis(10),
100 220, 2, 1}}}}},
101 {10001234,
102 UidProcStats{.cpuTimeMillis = ticksToMillis(12'000),
103 .totalMajorFaults = 600,
104 .totalTasksCount = 2,
105 .ioBlockedTasksCount = 2,
106 .processStatsByPid = {{1000,
107 {"system_server", ticksToMillis(13'400),
108 ticksToMillis(12'000), 600, 2, 2}}}}}};
109
110 TemporaryDir firstSnapshot;
111 ASSERT_RESULT_OK(populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat,
112 perProcessStatus, perThreadStat));
113
114 UidProcStatsCollector collector(firstSnapshot.path);
115 collector.init();
116
117 ASSERT_TRUE(collector.enabled())
118 << "Files under the path `" << firstSnapshot.path << "` are inaccessible";
119 ASSERT_RESULT_OK(collector.collect());
120
121 auto actual = collector.deltaStats();
122
123 EXPECT_THAT(actual, UnorderedPointwise(UidProcStatsByUidEq(), expected))
124 << "First snapshot doesn't match.\nExpected:\n"
125 << toString(expected) << "\nActual:\n"
126 << toString(actual);
127
128 pidToTids = {
129 {1, {1, 453}}, {1000, {1000, 1400}}, // TID 1100 terminated and 1400 instantiated.
130 };
131
132 perProcessStat = {
133 {1, "1 (init) S 0 0 0 0 0 0 0 0 920 0 10 10 0 0 0 0 2 0 19\n"},
134 {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 1550 0 10000 8000 0 0 0 0 2 0 13400\n"},
135 };
136
137 perThreadStat = {
138 {1, "1 (init) S 0 0 0 0 0 0 0 0 600 0 5 5 0 0 0 0 2 0 19\n"},
139 {453, "453 (init) S 0 0 0 0 0 0 0 0 320 0 5 5 0 0 0 0 2 0 275\n"},
140 {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 5000 2000 0 0 0 0 2 0 13400\n"},
141 // TID 1100 hits +400 major page faults before terminating. This is counted against
142 // PID 1000's perProcessStat.
143 {1400, "1400 (system_server) S 1 0 0 0 0 0 0 0 200 0 5000 2000 0 0 0 0 2 0 8977476\n"},
144 };
145
146 expected = {{0,
147 {.cpuTimeMillis = ticksToMillis(10),
148 .totalMajorFaults = 700,
149 .totalTasksCount = 2,
150 .ioBlockedTasksCount = 0,
151 .processStatsByPid =
152 {{1, {"init", ticksToMillis(19), ticksToMillis(10), 700, 2, 0}}}}},
153 {10001234,
154 {.cpuTimeMillis = ticksToMillis(6'000),
155 .totalMajorFaults = 950,
156 .totalTasksCount = 2,
157 .ioBlockedTasksCount = 0,
158 .processStatsByPid = {{1000,
159 {"system_server", ticksToMillis(13'400),
160 ticksToMillis(6'000), 950, 2, 0}}}}}};
161
162 TemporaryDir secondSnapshot;
163 ASSERT_RESULT_OK(populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat,
164 perProcessStatus, perThreadStat));
165
166 collector.mPath = secondSnapshot.path;
167
168 ASSERT_TRUE(collector.enabled())
169 << "Files under the path `" << secondSnapshot.path << "` are inaccessible";
170 ASSERT_RESULT_OK(collector.collect());
171
172 actual = collector.deltaStats();
173 EXPECT_THAT(actual, UnorderedPointwise(UidProcStatsByUidEq(), expected))
174 << "Second snapshot doesn't match.\nExpected:\n"
175 << toString(expected) << "\nActual:\n"
176 << toString(actual);
177 }
178
TEST(UidProcStatsCollectorTest,TestHandlesProcessTerminationBetweenScanningAndParsing)179 TEST(UidProcStatsCollectorTest, TestHandlesProcessTerminationBetweenScanningAndParsing) {
180 std::unordered_map<pid_t, std::vector<pid_t>> pidToTids = {
181 {1, {1}},
182 {100, {100}}, // Process terminates after scanning PID directory.
183 {1000, {1000}}, // Process terminates after reading stat file.
184 {2000, {2000}}, // Process terminates after scanning task directory.
185 {3000, {3000, 3300}}, // TID 3300 terminates after scanning task directory.
186 };
187
188 std::unordered_map<pid_t, std::string> perProcessStat = {
189 {1, "1 (init) S 0 0 0 0 0 0 0 0 220 0 10 10 0 0 0 0 1 0 19\n"},
190 // Process 100 terminated.
191 {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 600 0 20 20 0 0 0 0 1 0 1000\n"},
192 {2000, "2000 (logd) R 1 0 0 0 0 0 0 0 1200 0 30 30 0 0 0 0 1 0 4567\n"},
193 {3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 10300 0 40 40 0 0 0 0 2 0 67890\n"},
194 };
195
196 std::unordered_map<pid_t, std::string> perProcessStatus = {
197 {1, pidStatusStr(1, 0)},
198 // Process 1000 terminated.
199 {2000, pidStatusStr(2000, 10001234)},
200 {3000, pidStatusStr(3000, 10001234)},
201 };
202
203 std::unordered_map<pid_t, std::string> perThreadStat = {
204 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 1 0 19\n"},
205 // Process 2000 terminated.
206 {3000, "3000 (disk I/O) R 1 0 0 0 0 0 0 0 2400 0 30 30 0 0 0 0 2 0 67890\n"},
207 // TID 3300 terminated.
208 };
209
210 std::unordered_map<uid_t, UidProcStats> expected =
211 {{0,
212 UidProcStats{.cpuTimeMillis = ticksToMillis(20),
213 .totalMajorFaults = 220,
214 .totalTasksCount = 1,
215 .ioBlockedTasksCount = 0,
216 .processStatsByPid = {{1,
217 {"init", ticksToMillis(19), ticksToMillis(20),
218 220, 1, 0}}}}},
219 {10001234,
220 UidProcStats{.cpuTimeMillis = ticksToMillis(140),
221 .totalMajorFaults = 11500,
222 .totalTasksCount = 2,
223 .ioBlockedTasksCount = 0,
224 .processStatsByPid = {{2000,
225 {"logd", ticksToMillis(4567), ticksToMillis(60),
226 1200, 1, 0}},
227 {3000,
228 {"disk I/O", ticksToMillis(67890),
229 ticksToMillis(80), 10'300, 1, 0}}}}}};
230
231 TemporaryDir procDir;
232 ASSERT_RESULT_OK(populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
233 perThreadStat));
234
235 UidProcStatsCollector collector(procDir.path);
236 collector.init();
237
238 ASSERT_TRUE(collector.enabled())
239 << "Files under the path `" << procDir.path << "` are inaccessible";
240 ASSERT_RESULT_OK(collector.collect());
241
242 auto actual = collector.deltaStats();
243 EXPECT_THAT(actual, UnorderedPointwise(UidProcStatsByUidEq(), expected))
244 << "Proc pid contents doesn't match.\nExpected:\n"
245 << toString(expected) << "\nActual:\n"
246 << toString(actual);
247 }
248
TEST(UidProcStatsCollectorTest,TestHandlesPidTidReuse)249 TEST(UidProcStatsCollectorTest, TestHandlesPidTidReuse) {
250 std::unordered_map<pid_t, std::vector<pid_t>> pidToTids = {
251 {1, {1, 367, 453, 589}},
252 {1000, {1000}},
253 {2345, {2345}},
254 };
255
256 std::unordered_map<pid_t, std::string> perProcessStat = {
257 {1, "1 (init) S 0 0 0 0 0 0 0 0 1200 0 40 40 0 0 0 0 4 0 19\n"},
258 {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 10 10 0 0 0 0 1 0 1000\n"},
259 {2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 10 10 0 0 0 0 1 0 456\n"},
260 };
261
262 std::unordered_map<pid_t, std::string> perProcessStatus = {
263 {1, pidStatusStr(1, 0)},
264 {1000, pidStatusStr(1000, 10001234)},
265 {2345, pidStatusStr(2345, 10001234)},
266 };
267
268 std::unordered_map<pid_t, std::string> perThreadStat = {
269 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 4 0 19\n"},
270 {367, "367 (init) S 0 0 0 0 0 0 0 0 400 0 10 10 0 0 0 0 4 0 100\n"},
271 {453, "453 (init) S 0 0 0 0 0 0 0 0 100 0 10 10 0 0 0 0 4 0 275\n"},
272 {589, "589 (init) D 0 0 0 0 0 0 0 0 500 0 10 10 0 0 0 0 4 0 600\n"},
273 {1000, "1000 (system_server) R 1 0 0 0 0 0 0 0 250 0 10 10 0 0 0 0 1 0 1000\n"},
274 {2345, "2345 (logd) R 1 0 0 0 0 0 0 0 54354 0 10 10 0 0 0 0 1 0 456\n"},
275 };
276
277 std::unordered_map<uid_t, UidProcStats> expected =
278 {{0,
279 UidProcStats{.cpuTimeMillis = ticksToMillis(80),
280 .totalMajorFaults = 1200,
281 .totalTasksCount = 4,
282 .ioBlockedTasksCount = 1,
283 .processStatsByPid = {{1,
284 {"init", ticksToMillis(19), ticksToMillis(80),
285 1200, 4, 1}}}}},
286 {10001234,
287 UidProcStats{.cpuTimeMillis = ticksToMillis(40),
288 .totalMajorFaults = 54'604,
289 .totalTasksCount = 2,
290 .ioBlockedTasksCount = 0,
291 .processStatsByPid = {{1000,
292 {"system_server", ticksToMillis(1000),
293 ticksToMillis(20), 250, 1, 0}},
294 {2345,
295 {"logd", ticksToMillis(456), ticksToMillis(20),
296 54'354, 1, 0}}}}}};
297
298 TemporaryDir firstSnapshot;
299 ASSERT_RESULT_OK(populateProcPidDir(firstSnapshot.path, pidToTids, perProcessStat,
300 perProcessStatus, perThreadStat));
301
302 UidProcStatsCollector collector(firstSnapshot.path);
303 collector.init();
304
305 ASSERT_TRUE(collector.enabled())
306 << "Files under the path `" << firstSnapshot.path << "` are inaccessible";
307 ASSERT_RESULT_OK(collector.collect());
308
309 auto actual = collector.deltaStats();
310
311 EXPECT_THAT(actual, UnorderedPointwise(UidProcStatsByUidEq(), expected))
312 << "First snapshot doesn't match.\nExpected:\n"
313 << toString(expected) << "\nActual:\n"
314 << toString(actual);
315
316 pidToTids = {
317 {1, {1, 589}}, // TID 589 reused by the same process.
318 {367, {367, 2000}}, // TID 367 reused as a PID. PID 2000 reused as a TID.
319 // PID 1000 reused as a new PID. TID 453 reused by a different PID.
320 {1000, {1000, 453}},
321 };
322
323 perProcessStat = {
324 {1, "1 (init) S 0 0 0 0 0 0 0 0 1800 0 60 60 0 0 0 0 2 0 19\n"},
325 {367, "367 (system_server) R 1 0 0 0 0 0 0 0 100 0 30 30 0 0 0 0 2 0 3450\n"},
326 {1000, "1000 (logd) R 1 0 0 0 0 0 0 0 2000 0 20 20 0 0 0 0 2 0 4650\n"},
327 };
328
329 perProcessStatus = {
330 {1, pidStatusStr(1, 0)},
331 {367, pidStatusStr(367, 10001234)},
332 {1000, pidStatusStr(1000, 10001234)},
333 };
334
335 perThreadStat = {
336 {1, "1 (init) S 0 0 0 0 0 0 0 0 500 0 20 20 0 0 0 0 2 0 19\n"},
337 {589, "589 (init) S 0 0 0 0 0 0 0 0 300 0 10 10 0 0 0 0 2 0 2345\n"},
338 {367, "367 (system_server) R 1 0 0 0 0 0 0 0 50 0 15 15 0 0 0 0 2 0 3450\n"},
339 {2000, "2000 (system_server) R 1 0 0 0 0 0 0 0 50 0 15 15 0 0 0 0 2 0 3670\n"},
340 {1000, "1000 (logd) R 1 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 2 0 4650\n"},
341 {453, "453 (logd) D 1 0 0 0 0 0 0 0 1800 0 10 10 0 0 0 0 2 0 4770\n"},
342 };
343
344 expected = {{0,
345 UidProcStats{.cpuTimeMillis = ticksToMillis(40),
346 .totalMajorFaults = 600,
347 .totalTasksCount = 2,
348 .ioBlockedTasksCount = 0,
349 .processStatsByPid = {{1,
350 {"init", ticksToMillis(19), ticksToMillis(40),
351 600, 2, 0}}}}},
352 {10001234,
353 UidProcStats{.cpuTimeMillis = ticksToMillis(100),
354 .totalMajorFaults = 2100,
355 .totalTasksCount = 4,
356 .ioBlockedTasksCount = 1,
357 .processStatsByPid = {{367,
358 {"system_server", ticksToMillis(3450),
359 ticksToMillis(60), 100, 2, 0}},
360 {1000,
361 {"logd", ticksToMillis(4650),
362 ticksToMillis(40), 2000, 2, 1}}}}}};
363
364 TemporaryDir secondSnapshot;
365 ASSERT_RESULT_OK(populateProcPidDir(secondSnapshot.path, pidToTids, perProcessStat,
366 perProcessStatus, perThreadStat));
367
368 collector.mPath = secondSnapshot.path;
369
370 ASSERT_TRUE(collector.enabled())
371 << "Files under the path `" << secondSnapshot.path << "` are inaccessible";
372 ASSERT_RESULT_OK(collector.collect());
373
374 actual = collector.deltaStats();
375
376 EXPECT_THAT(actual, UnorderedPointwise(UidProcStatsByUidEq(), expected))
377 << "Second snapshot doesn't match.\nExpected:\n"
378 << toString(expected) << "\nActual:\n"
379 << toString(actual);
380 }
381
TEST(UidProcStatsCollectorTest,TestErrorOnCorruptedProcessStatFile)382 TEST(UidProcStatsCollectorTest, TestErrorOnCorruptedProcessStatFile) {
383 std::unordered_map<pid_t, std::vector<pid_t>> pidToTids = {
384 {1, {1}},
385 };
386
387 std::unordered_map<pid_t, std::string> perProcessStat = {
388 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 CORRUPTED DATA\n"},
389 };
390
391 std::unordered_map<pid_t, std::string> perProcessStatus = {
392 {1, pidStatusStr(1, 0)},
393 };
394
395 std::unordered_map<pid_t, std::string> perThreadStat = {
396 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 19\n"},
397 };
398
399 TemporaryDir procDir;
400 ASSERT_RESULT_OK(populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
401 perThreadStat));
402
403 UidProcStatsCollector collector(procDir.path);
404 collector.init();
405
406 ASSERT_TRUE(collector.enabled())
407 << "Files under the path `" << procDir.path << "` are inaccessible";
408 ASSERT_FALSE(collector.collect().ok()) << "No error returned for invalid process stat file";
409 }
410
TEST(UidProcStatsCollectorTest,TestErrorOnCorruptedProcessStatusFile)411 TEST(UidProcStatsCollectorTest, TestErrorOnCorruptedProcessStatusFile) {
412 std::unordered_map<pid_t, std::vector<pid_t>> pidToTids = {
413 {1, {1}},
414 };
415
416 std::unordered_map<pid_t, std::string> perProcessStat = {
417 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 19\n"},
418 };
419
420 std::unordered_map<pid_t, std::string> perProcessStatus = {
421 {1, "Pid:\t1\nTgid:\t1\nCORRUPTED DATA\n"},
422 };
423
424 std::unordered_map<pid_t, std::string> perThreadStat = {
425 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 1 0 19\n"},
426 };
427
428 TemporaryDir procDir;
429 ASSERT_RESULT_OK(populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
430 perThreadStat));
431
432 UidProcStatsCollector collector(procDir.path);
433 collector.init();
434
435 ASSERT_TRUE(collector.enabled())
436 << "Files under the path `" << procDir.path << "` are inaccessible";
437 ASSERT_FALSE(collector.collect().ok()) << "No error returned for invalid process status file";
438 }
439
TEST(UidProcStatsCollectorTest,TestErrorOnCorruptedThreadStatFile)440 TEST(UidProcStatsCollectorTest, TestErrorOnCorruptedThreadStatFile) {
441 std::unordered_map<pid_t, std::vector<pid_t>> pidToTids = {
442 {1, {1, 234}},
443 };
444
445 std::unordered_map<pid_t, std::string> perProcessStat = {
446 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 678\n"},
447 };
448
449 std::unordered_map<pid_t, std::string> perProcessStatus = {
450 {1, pidStatusStr(1, 0)},
451 };
452
453 std::unordered_map<pid_t, std::string> perThreadStat = {
454 {1, "1 (init) S 0 0 0 0 0 0 0 0 200 0 0 0 0 0 0 0 2 0 678\n"},
455 {234, "234 (init) D 0 0 0 0 0 0 0 0 200 0 0 0 CORRUPTED DATA\n"},
456 };
457
458 TemporaryDir procDir;
459 ASSERT_RESULT_OK(populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
460 perThreadStat));
461
462 UidProcStatsCollector collector(procDir.path);
463 collector.init();
464
465 ASSERT_TRUE(collector.enabled())
466 << "Files under the path `" << procDir.path << "` are inaccessible";
467 ASSERT_FALSE(collector.collect().ok()) << "No error returned for invalid thread stat file";
468 }
469
TEST(UidProcStatsCollectorTest,TestHandlesSpaceInCommName)470 TEST(UidProcStatsCollectorTest, TestHandlesSpaceInCommName) {
471 std::unordered_map<pid_t, std::vector<pid_t>> pidToTids = {
472 {1, {1}},
473 };
474
475 std::unordered_map<pid_t, std::string> perProcessStat = {
476 {1,
477 "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 1 0 19\n"},
478 };
479
480 std::unordered_map<pid_t, std::string> perProcessStatus = {
481 {1, pidStatusStr(1, 0)},
482 };
483
484 std::unordered_map<pid_t, std::string> perThreadStat = {
485 {1,
486 "1 (random process name with space) S 0 0 0 0 0 0 0 0 200 0 10 10 0 0 0 0 1 0 19\n"},
487 };
488
489 std::unordered_map<uid_t, UidProcStats> expected = {
490 {0,
491 UidProcStats{.cpuTimeMillis = ticksToMillis(20),
492 .totalMajorFaults = 200,
493 .totalTasksCount = 1,
494 .ioBlockedTasksCount = 0,
495 .processStatsByPid = {
496 {1,
497 {"random process name with space", ticksToMillis(19),
498 ticksToMillis(20), 200, 1, 0}}}}}};
499
500 TemporaryDir procDir;
501 ASSERT_RESULT_OK(populateProcPidDir(procDir.path, pidToTids, perProcessStat, perProcessStatus,
502 perThreadStat));
503
504 UidProcStatsCollector collector(procDir.path);
505 collector.init();
506
507 ASSERT_TRUE(collector.enabled())
508 << "Files under the path `" << procDir.path << "` are inaccessible";
509 ASSERT_RESULT_OK(collector.collect());
510
511 auto actual = collector.deltaStats();
512
513 EXPECT_THAT(actual, UnorderedPointwise(UidProcStatsByUidEq(), expected))
514 << "Proc pid contents doesn't match.\nExpected:\n"
515 << toString(expected) << "\nActual:\n"
516 << toString(actual);
517 }
518
TEST(UidProcStatsCollectorTest,TestUidProcStatsCollectorContentsFromDevice)519 TEST(UidProcStatsCollectorTest, TestUidProcStatsCollectorContentsFromDevice) {
520 UidProcStatsCollector collector;
521 collector.init();
522
523 ASSERT_TRUE(collector.enabled()) << "/proc/[pid]/.* files are inaccessible";
524 ASSERT_RESULT_OK(collector.collect());
525
526 const auto& processStats = collector.deltaStats();
527
528 // The below check should pass because there should be at least one process.
529 EXPECT_GT(processStats.size(), static_cast<size_t>(0));
530 }
531
532 } // namespace watchdog
533 } // namespace automotive
534 } // namespace android
535