1 // Copyright (C) 2017 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "packages/UidMap.h"
16
17 #include <android/util/ProtoOutputStream.h>
18 #include <gtest/gtest.h>
19 #include <private/android_filesystem_config.h>
20 #include <src/uid_data.pb.h>
21 #include <stdio.h>
22
23 #include "StatsLogProcessor.h"
24 #include "StatsService.h"
25 #include "config/ConfigKey.h"
26 #include "gtest_matchers.h"
27 #include "guardrail/StatsdStats.h"
28 #include "hash.h"
29 #include "logd/LogEvent.h"
30 #include "statsd_test_util.h"
31 #include "statslog_statsdtest.h"
32
33 using namespace android;
34
35 namespace android {
36 namespace os {
37 namespace statsd {
38
39 using android::util::ProtoOutputStream;
40 using android::util::ProtoReader;
41 using ::ndk::SharedRefBase;
42 using Change = UidMapping_Change;
43
44 #ifdef __ANDROID__
45
46 namespace {
47 const string kApp1 = "app1.sharing.1";
48 const string kApp2 = "app2.sharing.1";
49 const string kApp3 = "app3";
50
51 const vector<int32_t> kUids{1000, 1000, 1500};
52 const vector<int64_t> kVersions{4, 5, 6};
53 const vector<string> kVersionStrings{"v1", "v1", "v2"};
54 const vector<string> kApps{kApp1, kApp2, kApp3};
55 const vector<string> kInstallers{"", "", "com.android.vending"};
56 const vector<vector<uint8_t>> kCertificateHashes{{'a', 'z'}, {'b', 'c'}, {'d', 'e'}};
57 const vector<uint8_t> kDeleted(3, false);
58
createUidData(const vector<int32_t> & uids,const vector<int64_t> & versions,const vector<string> & versionStrings,const vector<string> & apps,const vector<string> & installers,const vector<vector<uint8_t>> & certificateHashes)59 UidData createUidData(const vector<int32_t>& uids, const vector<int64_t>& versions,
60 const vector<string>& versionStrings, const vector<string>& apps,
61 const vector<string>& installers,
62 const vector<vector<uint8_t>>& certificateHashes) {
63 // Populate UidData from app data.
64 UidData uidData;
65 for (size_t i = 0; i < uids.size(); i++) {
66 ApplicationInfo* appInfo = uidData.add_app_info();
67 appInfo->set_uid(uids[i]);
68 appInfo->set_version(versions[i]);
69 appInfo->set_version_string(versionStrings[i]);
70 appInfo->set_package_name(apps[i]);
71 appInfo->set_installer(installers[i]);
72 appInfo->set_certificate_hash(certificateHashes[i].data(), certificateHashes[i].size());
73 }
74 return uidData;
75 }
76
sendPackagesToStatsd(shared_ptr<StatsService> service,const vector<int32_t> & uids,const vector<int64_t> & versions,const vector<string> & versionStrings,const vector<string> & apps,const vector<string> & installers,const vector<vector<uint8_t>> & certificateHashes)77 void sendPackagesToStatsd(shared_ptr<StatsService> service, const vector<int32_t>& uids,
78 const vector<int64_t>& versions, const vector<string>& versionStrings,
79 const vector<string>& apps, const vector<string>& installers,
80 const vector<vector<uint8_t>>& certificateHashes) {
81 // Create file descriptor from serialized UidData.
82 // Create a file that lives in memory.
83 ScopedFileDescriptor scopedFd(memfd_create("doesn't matter", MFD_CLOEXEC));
84 const int fd = scopedFd.get();
85 int f = fcntl(fd, F_GETFD); // Read the file descriptor flags.
86 ASSERT_NE(-1, f); // Ensure there was no error while reading file descriptor flags.
87 ASSERT_TRUE(f & FD_CLOEXEC);
88
89 UidData uidData =
90 createUidData(uids, versions, versionStrings, apps, installers, certificateHashes);
91 ASSERT_TRUE(uidData.SerializeToFileDescriptor(fd));
92 ASSERT_EQ(0, lseek(fd, 0, SEEK_SET));
93
94 // Send file descriptor containing app data to statsd.
95 service->informAllUidData(scopedFd);
96 }
97
98 // Returns a vector of the same length as values param. Each i-th element in the returned vector is
99 // the index at which values[i] appears in the list denoted by the begin and end iterators.
100 template <typename Iterator, typename ValueType>
computeIndices(const Iterator begin,const Iterator end,const vector<ValueType> & values)101 vector<uint32_t> computeIndices(const Iterator begin, const Iterator end,
102 const vector<ValueType>& values) {
103 vector<uint32_t> indices;
104 for (const ValueType& value : values) {
105 Iterator it = find(begin, end, value);
106 indices.emplace_back(distance(begin, it));
107 }
108 return indices;
109 }
110
111 class UidMapTestAppendUidMapBase : public Test {
112 protected:
113 const ConfigKey cfgKey;
114 const sp<UidMap> uidMap;
115
UidMapTestAppendUidMapBase()116 UidMapTestAppendUidMapBase() : cfgKey(1, StringToId("config1")), uidMap(new UidMap()) {
117 }
118 };
119
120 } // anonymous namespace
121
TEST(UidMapTest,TestIsolatedUID)122 TEST(UidMapTest, TestIsolatedUID) {
123 sp<UidMap> m = new UidMap();
124 sp<StatsPullerManager> pullerManager = new StatsPullerManager();
125 sp<AlarmMonitor> anomalyAlarmMonitor;
126 sp<AlarmMonitor> subscriberAlarmMonitor;
127 // Construct the processor with a no-op sendBroadcast function that does nothing.
128 StatsLogProcessor p(
129 m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
130 [](const ConfigKey& key) { return true; },
131 [](const int&, const vector<int64_t>&) { return true; },
132 [](const ConfigKey&, const string&, const vector<int64_t>&) {},
133 std::make_shared<LogEventFilter>());
134
135 std::unique_ptr<LogEvent> addEvent = CreateIsolatedUidChangedEvent(
136 1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 1 /*is_create*/);
137 EXPECT_EQ(101, m->getHostUidOrSelf(101));
138 p.OnLogEvent(addEvent.get());
139 EXPECT_EQ(100, m->getHostUidOrSelf(101));
140
141 std::unique_ptr<LogEvent> removeEvent = CreateIsolatedUidChangedEvent(
142 1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 0 /*is_create*/);
143 p.OnLogEvent(removeEvent.get());
144 EXPECT_EQ(101, m->getHostUidOrSelf(101));
145 }
146
TEST(UidMapTest,TestUpdateMap)147 TEST(UidMapTest, TestUpdateMap) {
148 const sp<UidMap> uidMap = new UidMap();
149 const shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(
150 uidMap, /* queue */ nullptr, std::make_shared<LogEventFilter>());
151 sendPackagesToStatsd(service, kUids, kVersions, kVersionStrings, kApps, kInstallers,
152 kCertificateHashes);
153
154 EXPECT_TRUE(uidMap->hasApp(1000, kApp1));
155 EXPECT_TRUE(uidMap->hasApp(1000, kApp2));
156 EXPECT_TRUE(uidMap->hasApp(1500, kApp3));
157 EXPECT_FALSE(uidMap->hasApp(1000, "not.app"));
158
159 std::set<string> name_set = uidMap->getAppNamesFromUid(1000u, true /* returnNormalized */);
160 EXPECT_THAT(name_set, UnorderedElementsAre(kApp1, kApp2));
161
162 name_set = uidMap->getAppNamesFromUid(1500u, true /* returnNormalized */);
163 EXPECT_THAT(name_set, UnorderedElementsAre(kApp3));
164
165 name_set = uidMap->getAppNamesFromUid(12345, true /* returnNormalized */);
166 EXPECT_THAT(name_set, IsEmpty());
167
168 vector<PackageInfo> expectedPackageInfos =
169 buildPackageInfos(kApps, kUids, kVersions, kVersionStrings, kInstallers,
170 kCertificateHashes, kDeleted, /* installerIndices */ {},
171 /* hashStrings */ false);
172
173 PackageInfoSnapshot packageInfoSnapshot = getPackageInfoSnapshot(uidMap);
174
175 EXPECT_THAT(packageInfoSnapshot.package_info(),
176 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
177 }
178
TEST(UidMapTest,TestUpdateMapMultiple)179 TEST(UidMapTest, TestUpdateMapMultiple) {
180 const sp<UidMap> uidMap = new UidMap();
181 const shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(
182 uidMap, /* queue */ nullptr, std::make_shared<LogEventFilter>());
183 sendPackagesToStatsd(service, kUids, kVersions, kVersionStrings, kApps, kInstallers,
184 kCertificateHashes);
185
186 // Remove kApp3, and add NewApp
187 vector<int32_t> uids(kUids);
188 uids.back() = 2000;
189 vector<string> apps(kApps);
190 apps.back() = "NewApp";
191 vector<string> installers(kInstallers);
192 installers.back() = "NewInstaller";
193
194 sendPackagesToStatsd(service, uids, kVersions, kVersionStrings, apps, installers,
195 kCertificateHashes);
196
197 EXPECT_TRUE(uidMap->hasApp(1000, kApp1));
198 EXPECT_TRUE(uidMap->hasApp(1000, kApp2));
199 EXPECT_TRUE(uidMap->hasApp(2000, "NewApp"));
200 EXPECT_FALSE(uidMap->hasApp(1500, kApp3));
201 EXPECT_FALSE(uidMap->hasApp(1000, "not.app"));
202
203 std::set<string> name_set = uidMap->getAppNamesFromUid(1000u, true /* returnNormalized */);
204 EXPECT_THAT(name_set, UnorderedElementsAre(kApp1, kApp2));
205
206 name_set = uidMap->getAppNamesFromUid(2000, true /* returnNormalized */);
207 EXPECT_THAT(name_set, UnorderedElementsAre("newapp"));
208
209 name_set = uidMap->getAppNamesFromUid(1500, true /* returnNormalized */);
210 EXPECT_THAT(name_set, IsEmpty());
211
212 vector<PackageInfo> expectedPackageInfos =
213 buildPackageInfos(apps, uids, kVersions, kVersionStrings, installers,
214 kCertificateHashes, kDeleted, /* installerIndices */ {},
215 /* hashStrings */ false);
216
217 PackageInfoSnapshot packageInfoSnapshot = getPackageInfoSnapshot(uidMap);
218
219 EXPECT_THAT(packageInfoSnapshot.package_info(),
220 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
221 }
222
TEST(UidMapTest,TestRemoveApp)223 TEST(UidMapTest, TestRemoveApp) {
224 const sp<UidMap> uidMap = new UidMap();
225 const shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(
226 uidMap, /* queue */ nullptr, std::make_shared<LogEventFilter>());
227 sendPackagesToStatsd(service, kUids, kVersions, kVersionStrings, kApps, kInstallers,
228 kCertificateHashes);
229
230 service->informOnePackageRemoved(kApp1, 1000);
231 EXPECT_FALSE(uidMap->hasApp(1000, kApp1));
232 EXPECT_TRUE(uidMap->hasApp(1000, kApp2));
233 EXPECT_TRUE(uidMap->hasApp(1500, kApp3));
234 std::set<string> name_set = uidMap->getAppNamesFromUid(1000, true /* returnNormalized */);
235 EXPECT_THAT(name_set, UnorderedElementsAre(kApp2));
236
237 vector<uint8_t> deleted(kDeleted);
238 deleted[0] = true;
239 vector<PackageInfo> expectedPackageInfos =
240 buildPackageInfos(kApps, kUids, kVersions, kVersionStrings, kInstallers,
241 kCertificateHashes, deleted, /* installerIndices */ {},
242 /* hashStrings */ false);
243 PackageInfoSnapshot packageInfoSnapshot = getPackageInfoSnapshot(uidMap);
244 EXPECT_THAT(packageInfoSnapshot.package_info(),
245 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
246
247 service->informOnePackageRemoved(kApp2, 1000);
248 EXPECT_FALSE(uidMap->hasApp(1000, kApp1));
249 EXPECT_FALSE(uidMap->hasApp(1000, kApp2));
250 EXPECT_TRUE(uidMap->hasApp(1500, kApp3));
251 EXPECT_FALSE(uidMap->hasApp(1000, "not.app"));
252 name_set = uidMap->getAppNamesFromUid(1000, true /* returnNormalized */);
253 EXPECT_THAT(name_set, IsEmpty());
254
255 deleted[1] = true;
256 expectedPackageInfos = buildPackageInfos(kApps, kUids, kVersions, kVersionStrings, kInstallers,
257 kCertificateHashes, deleted, /* installerIndices */ {},
258 /* hashStrings */ false);
259 packageInfoSnapshot = getPackageInfoSnapshot(uidMap);
260 EXPECT_THAT(packageInfoSnapshot.package_info(),
261 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
262
263 service->informOnePackageRemoved(kApp3, 1500);
264 EXPECT_FALSE(uidMap->hasApp(1000, kApp1));
265 EXPECT_FALSE(uidMap->hasApp(1000, kApp2));
266 EXPECT_FALSE(uidMap->hasApp(1500, kApp3));
267 EXPECT_FALSE(uidMap->hasApp(1000, "not.app"));
268 name_set = uidMap->getAppNamesFromUid(1500, true /* returnNormalized */);
269 EXPECT_THAT(name_set, IsEmpty());
270
271 deleted[2] = true;
272 expectedPackageInfos = buildPackageInfos(kApps, kUids, kVersions, kVersionStrings, kInstallers,
273 kCertificateHashes, deleted, /* installerIndices */ {},
274 /* hashStrings */ false);
275 packageInfoSnapshot = getPackageInfoSnapshot(uidMap);
276 EXPECT_THAT(packageInfoSnapshot.package_info(),
277 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
278 }
279
TEST(UidMapTest,TestUpdateApp)280 TEST(UidMapTest, TestUpdateApp) {
281 const sp<UidMap> uidMap = new UidMap();
282 const shared_ptr<StatsService> service = SharedRefBase::make<StatsService>(
283 uidMap, /* queue */ nullptr, std::make_shared<LogEventFilter>());
284 sendPackagesToStatsd(service, kUids, kVersions, kVersionStrings, kApps, kInstallers,
285 kCertificateHashes);
286
287 // Update app1 version.
288 service->informOnePackage(kApps[0].c_str(), kUids[0], /* version */ 40,
289 /* versionString */ "v40", kInstallers[0], kCertificateHashes[0]);
290 EXPECT_THAT(uidMap->getAppVersion(kUids[0], kApps[0]), Eq(40));
291 std::set<string> name_set = uidMap->getAppNamesFromUid(1000, true /* returnNormalized */);
292 EXPECT_THAT(name_set, UnorderedElementsAre(kApp1, kApp2));
293
294 // Add a new name for uid 1000.
295 service->informOnePackage("NeW_aPP1_NAmE", 1000, /* version */ 40,
296 /* versionString */ "v40", /* installer */ "com.android.vending",
297 /* certificateHash */ {'a'});
298 name_set = uidMap->getAppNamesFromUid(1000, true /* returnNormalized */);
299 EXPECT_THAT(name_set, UnorderedElementsAre(kApp1, kApp2, "new_app1_name"));
300
301 // Re-add the same name for another uid 2000
302 service->informOnePackage("NeW_aPP1_NAmE", 2000, /* version */ 1,
303 /* versionString */ "v1", /* installer */ "",
304 /* certificateHash */ {'b'});
305 name_set = uidMap->getAppNamesFromUid(2000, true /* returnNormalized */);
306 EXPECT_THAT(name_set, UnorderedElementsAre("new_app1_name"));
307
308 // Re-add existing package with different installer
309 service->informOnePackage("NeW_aPP1_NAmE", 2000, /* version */ 1,
310 /* versionString */ "v1", /* installer */ "new_installer",
311 /* certificateHash */ {'b'});
312 name_set = uidMap->getAppNamesFromUid(2000, true /* returnNormalized */);
313 EXPECT_THAT(name_set, UnorderedElementsAre("new_app1_name"));
314
315 vector<int32_t> uids = concatenate(kUids, {1000, 2000});
316 vector<int64_t> versions = concatenate(kVersions, {40, 1});
317 versions[0] = 40;
318 vector<string> versionStrings = concatenate(kVersionStrings, {"v40", "v1"});
319 versionStrings[0] = "v40";
320 vector<string> apps = concatenate(kApps, {"NeW_aPP1_NAmE", "NeW_aPP1_NAmE"});
321 vector<string> installers = concatenate(kInstallers, {"com.android.vending", "new_installer"});
322 vector<uint8_t> deleted = concatenate(kDeleted, {false, false});
323 vector<vector<uint8_t>> certHashes = concatenate(kCertificateHashes, {{'a'}, {'b'}});
324 vector<PackageInfo> expectedPackageInfos =
325 buildPackageInfos(apps, uids, versions, versionStrings, installers, certHashes, deleted,
326 /* installerIndices */ {},
327 /* hashStrings */ false);
328
329 PackageInfoSnapshot packageInfoSnapshot = getPackageInfoSnapshot(uidMap);
330 EXPECT_THAT(packageInfoSnapshot.package_info(),
331 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
332 }
333
334 // Test that uid map returns at least one snapshot even if we already obtained
335 // this snapshot from a previous call to getData.
TEST(UidMapTest,TestOutputIncludesAtLeastOneSnapshot)336 TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot) {
337 UidMap m;
338 // Initialize single config key.
339 ConfigKey config1(1, StringToId("config1"));
340 m.OnConfigUpdated(config1);
341
342 UidData uidData;
343 *uidData.add_app_info() = createApplicationInfo(/*uid*/ 1000, /*version*/ 5, "v1", kApp2);
344
345 m.updateMap(1 /* timestamp */, uidData);
346
347 // Set the last timestamp for this config key to be newer.
348 m.mLastUpdatePerConfigKey[config1] = 2;
349
350 ProtoOutputStream proto;
351 m.appendUidMap(/* timestamp */ 3, config1, /* includeVersionStrings */ true,
352 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
353 /* omitSystemUids */ false,
354 /* str_set */ nullptr, &proto);
355
356 // Check there's still a uidmap attached this one.
357 UidMapping results;
358 outputStreamToProto(&proto, &results);
359 ASSERT_EQ(1, results.snapshots_size());
360 EXPECT_EQ("v1", results.snapshots(0).package_info(0).version_string());
361 }
362
TEST(UidMapTest,TestRemovedAppRetained)363 TEST(UidMapTest, TestRemovedAppRetained) {
364 UidMap m;
365 // Initialize single config key.
366 ConfigKey config1(1, StringToId("config1"));
367 m.OnConfigUpdated(config1);
368
369 UidData uidData;
370 *uidData.add_app_info() = createApplicationInfo(/*uid*/ 1000, /*version*/ 5, "v5", kApp2);
371
372 m.updateMap(1 /* timestamp */, uidData);
373 m.removeApp(2, kApp2, 1000);
374
375 ProtoOutputStream proto;
376 m.appendUidMap(/* timestamp */ 3, config1, /* includeVersionStrings */ true,
377 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
378 /* omitSystemUids */ false,
379 /* str_set */ nullptr, &proto);
380
381 // Snapshot should still contain this item as deleted.
382 UidMapping results;
383 outputStreamToProto(&proto, &results);
384 ASSERT_EQ(1, results.snapshots(0).package_info_size());
385 EXPECT_EQ(true, results.snapshots(0).package_info(0).deleted());
386 }
387
TEST(UidMapTest,TestRemovedAppOverGuardrail)388 TEST(UidMapTest, TestRemovedAppOverGuardrail) {
389 UidMap m;
390 // Initialize single config key.
391 ConfigKey config1(1, StringToId("config1"));
392 m.OnConfigUpdated(config1);
393 const int maxDeletedApps = StatsdStats::kMaxDeletedAppsInUidMap;
394
395 UidData uidData;
396 for (int j = 0; j < maxDeletedApps + 10; j++) {
397 *uidData.add_app_info() = createApplicationInfo(/*uid*/ j, /*version*/ j, "v", kApp1);
398 }
399 m.updateMap(1 /* timestamp */, uidData);
400
401 // First, verify that we have the expected number of items.
402 UidMapping results;
403 ProtoOutputStream proto;
404 m.appendUidMap(/* timestamp */ 3, config1, /* includeVersionStrings */ true,
405 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
406 /* omitSystemUids */ false,
407 /* str_set */ nullptr, &proto);
408 outputStreamToProto(&proto, &results);
409 ASSERT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size());
410
411 // Now remove all the apps.
412 m.updateMap(1 /* timestamp */, uidData);
413 for (int j = 0; j < maxDeletedApps + 10; j++) {
414 m.removeApp(4, kApp1, j);
415 }
416
417 proto.clear();
418 m.appendUidMap(/* timestamp */ 5, config1, /* includeVersionStrings */ true,
419 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
420 /* omitSystemUids */ false,
421 /* str_set */ nullptr, &proto);
422 // Snapshot drops the first nine items.
423 outputStreamToProto(&proto, &results);
424 ASSERT_EQ(maxDeletedApps, results.snapshots(0).package_info_size());
425 }
426
TEST(UidMapTest,TestClearingOutput)427 TEST(UidMapTest, TestClearingOutput) {
428 UidMap m;
429
430 ConfigKey config1(1, StringToId("config1"));
431 ConfigKey config2(1, StringToId("config2"));
432
433 m.OnConfigUpdated(config1);
434
435 UidData uidData;
436 *uidData.add_app_info() = createApplicationInfo(/*uid*/ 1000, /*version*/ 4, "v4", kApp1);
437 *uidData.add_app_info() = createApplicationInfo(/*uid*/ 1000, /*version*/ 5, "v5", kApp2);
438 m.updateMap(1 /* timestamp */, uidData);
439
440 ProtoOutputStream proto;
441 m.appendUidMap(/* timestamp */ 2, config1, /* includeVersionStrings */ true,
442 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
443 /* omitSystemUids */ false,
444 /* str_set */ nullptr, &proto);
445 UidMapping results;
446 outputStreamToProto(&proto, &results);
447 ASSERT_EQ(1, results.snapshots_size());
448
449 // We have to keep at least one snapshot in memory at all times.
450 proto.clear();
451 m.appendUidMap(/* timestamp */ 2, config1, /* includeVersionStrings */ true,
452 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
453 /* omitSystemUids */ false,
454 /* str_set */ nullptr, &proto);
455 outputStreamToProto(&proto, &results);
456 ASSERT_EQ(1, results.snapshots_size());
457
458 // Now add another configuration.
459 m.OnConfigUpdated(config2);
460 m.updateApp(5, kApp1, 1000, 40, "v40", "", /* certificateHash */ {});
461 ASSERT_EQ(1U, m.mChanges.size());
462 proto.clear();
463 m.appendUidMap(/* timestamp */ 6, config1, /* includeVersionStrings */ true,
464 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
465 /* omitSystemUids */ false,
466 /* str_set */ nullptr, &proto);
467 outputStreamToProto(&proto, &results);
468 ASSERT_EQ(1, results.snapshots_size());
469 ASSERT_EQ(1, results.changes_size());
470 ASSERT_EQ(1U, m.mChanges.size());
471
472 // Add another delta update.
473 m.updateApp(7, kApp2, 1001, 41, "v41", "", /* certificateHash */ {});
474 ASSERT_EQ(2U, m.mChanges.size());
475
476 // We still can't remove anything.
477 proto.clear();
478 m.appendUidMap(/* timestamp */ 8, config1, /* includeVersionStrings */ true,
479 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
480 /* omitSystemUids */ false,
481 /* str_set */ nullptr, &proto);
482 outputStreamToProto(&proto, &results);
483 ASSERT_EQ(1, results.snapshots_size());
484 ASSERT_EQ(1, results.changes_size());
485 ASSERT_EQ(2U, m.mChanges.size());
486
487 proto.clear();
488 m.appendUidMap(/* timestamp */ 9, config2, /* includeVersionStrings */ true,
489 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
490 /* omitSystemUids */ false,
491 /* str_set */ nullptr, &proto);
492 outputStreamToProto(&proto, &results);
493 ASSERT_EQ(1, results.snapshots_size());
494 ASSERT_EQ(2, results.changes_size());
495 // At this point both should be cleared.
496 ASSERT_EQ(0U, m.mChanges.size());
497 }
498
TEST(UidMapTest,TestMemoryComputed)499 TEST(UidMapTest, TestMemoryComputed) {
500 UidMap m;
501
502 ConfigKey config1(1, StringToId("config1"));
503 m.OnConfigUpdated(config1);
504
505 size_t startBytes = m.mBytesUsed;
506 UidData uidData;
507 *uidData.add_app_info() = createApplicationInfo(/*uid*/ 1000, /*version*/ 1, "v1", kApp1);
508 m.updateMap(1 /* timestamp */, uidData);
509
510 m.updateApp(3, kApp1, 1000, 40, "v40", "", /* certificateHash */ {});
511
512 ProtoOutputStream proto;
513 m.appendUidMap(/* timestamp */ 2, config1, /* includeVersionStrings */ true,
514 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
515 /* omitSystemUids */ false,
516 /* str_set */ nullptr, &proto);
517 size_t prevBytes = m.mBytesUsed;
518
519 m.appendUidMap(/* timestamp */ 4, config1, /* includeVersionStrings */ true,
520 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
521 /* omitSystemUids */ false,
522 /* str_set */ nullptr, &proto);
523 EXPECT_TRUE(m.mBytesUsed < prevBytes);
524 }
525
TEST(UidMapTest,TestMemoryGuardrail)526 TEST(UidMapTest, TestMemoryGuardrail) {
527 UidMap m;
528 string buf;
529
530 ConfigKey config1(1, StringToId("config1"));
531 m.OnConfigUpdated(config1);
532
533 size_t startBytes = m.mBytesUsed;
534 UidData uidData;
535 for (int i = 0; i < 100; i++) {
536 buf = "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY." + to_string(i);
537 *uidData.add_app_info() = createApplicationInfo(/*uid*/ 1, /*version*/ 1, "v1", buf);
538 }
539 m.updateMap(1 /* timestamp */, uidData);
540
541 m.updateApp(3, "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0", 1000, 2, "v2", "",
542 /* certificateHash */ {});
543 ASSERT_EQ(1U, m.mChanges.size());
544
545 // Now force deletion by limiting the memory to hold one delta change.
546 m.maxBytesOverride = 120; // Since the app string alone requires >45 characters.
547 m.updateApp(5, "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0", 1000, 4, "v4", "",
548 /* certificateHash */ {});
549 ASSERT_EQ(1U, m.mChanges.size());
550 }
551
552 namespace {
553 class UidMapTestAppendUidMap : public UidMapTestAppendUidMapBase {
554 protected:
555 const shared_ptr<StatsService> service;
556
557 set<string> installersSet;
558 set<uint64_t> installerHashSet;
559 vector<uint64_t> installerHashes;
560
UidMapTestAppendUidMap()561 UidMapTestAppendUidMap()
562 : UidMapTestAppendUidMapBase(),
563 service(SharedRefBase::make<StatsService>(uidMap, /* queue */ nullptr,
564 std::make_shared<LogEventFilter>())) {
565 }
566
SetUp()567 void SetUp() override {
568 sendPackagesToStatsd(service, kUids, kVersions, kVersionStrings, kApps, kInstallers,
569 kCertificateHashes);
570
571 for (const string& installer : kInstallers) {
572 installersSet.insert(installer);
573 uint64_t installerHash = Hash64(installer);
574 installerHashes.emplace_back(installerHash);
575 installerHashSet.insert(installerHash);
576 }
577 }
578 };
579
TEST_F(UidMapTestAppendUidMap,TestInstallersInReportIncludeInstallerAndHashStrings)580 TEST_F(UidMapTestAppendUidMap, TestInstallersInReportIncludeInstallerAndHashStrings) {
581 ProtoOutputStream proto;
582 set<string> strSet;
583 uidMap->appendUidMap(/* timestamp */ 3, cfgKey, /* includeVersionStrings */ true,
584 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
585 /* omitSystemUids */ false, &strSet, &proto);
586
587 UidMapping results;
588 outputStreamToProto(&proto, &results);
589
590 // Verify hashes for all installers are in the installer_hash list.
591 EXPECT_THAT(results.installer_hash(), UnorderedElementsAreArray(installerHashSet));
592
593 EXPECT_THAT(results.installer_name(), IsEmpty());
594
595 // Verify all installer names are added to the strSet argument.
596 EXPECT_THAT(strSet, IsSupersetOf(installersSet));
597
598 ASSERT_THAT(results.snapshots_size(), Eq(1));
599
600 // Compute installer indices for each package.
601 // Find the location of each installerHash from the input in the results.
602 // installerIndices[i] is the index in results.installer_hash() that matches installerHashes[i].
603 vector<uint32_t> installerIndices = computeIndices(
604 results.installer_hash().begin(), results.installer_hash().end(), installerHashes);
605
606 vector<PackageInfo> expectedPackageInfos =
607 buildPackageInfos(kApps, kUids, kVersions, kVersionStrings, kInstallers,
608 /* certHashes */ {}, kDeleted, installerIndices,
609 /* hashStrings */ true);
610
611 EXPECT_THAT(strSet, IsSupersetOf(kApps));
612
613 EXPECT_THAT(results.snapshots(0).package_info(),
614 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
615 }
616
TEST_F(UidMapTestAppendUidMap,TestInstallersInReportIncludeInstallerAndDontHashStrings)617 TEST_F(UidMapTestAppendUidMap, TestInstallersInReportIncludeInstallerAndDontHashStrings) {
618 ProtoOutputStream proto;
619 uidMap->appendUidMap(/* timestamp */ 3, cfgKey, /* includeVersionStrings */ true,
620 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
621 /* omitSystemUids */ false,
622 /* str_set */ nullptr, &proto);
623
624 UidMapping results;
625 outputStreamToProto(&proto, &results);
626
627 // Verify all installers are in the installer_name list.
628 EXPECT_THAT(results.installer_name(), UnorderedElementsAreArray(installersSet));
629
630 EXPECT_THAT(results.installer_hash(), IsEmpty());
631
632 ASSERT_THAT(results.snapshots_size(), Eq(1));
633
634 vector<uint32_t> installerIndices = computeIndices(results.installer_name().begin(),
635 results.installer_name().end(), kInstallers);
636
637 vector<PackageInfo> expectedPackageInfos =
638 buildPackageInfos(kApps, kUids, kVersions, kVersionStrings, kInstallers,
639 /* certHashes */ {}, kDeleted, installerIndices,
640 /* hashStrings */ false);
641
642 EXPECT_THAT(results.snapshots(0).package_info(),
643 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
644 }
645
646 // Set up parameterized test with set<string>* parameter to control whether strings are hashed
647 // or not in the report. A value of nullptr indicates strings should not be hashed and non-null
648 // values indicates strings are hashed in the report and the original strings are added to this set.
649 class UidMapTestAppendUidMapHashStrings : public UidMapTestAppendUidMap,
650 public WithParamInterface<set<string>*> {
651 public:
652 inline static set<string> strSet;
653
654 protected:
SetUp()655 void SetUp() override {
656 strSet.clear();
657 }
658 };
659
660 INSTANTIATE_TEST_SUITE_P(
661 HashStrings, UidMapTestAppendUidMapHashStrings,
662 Values(nullptr, &(UidMapTestAppendUidMapHashStrings::strSet)),
__anon34be54ab0602(const TestParamInfo<UidMapTestAppendUidMapHashStrings::ParamType>& info) 663 [](const TestParamInfo<UidMapTestAppendUidMapHashStrings::ParamType>& info) {
664 return info.param == nullptr ? "NoHashStrings" : "HashStrings";
665 });
666
TEST_P(UidMapTestAppendUidMapHashStrings,TestNoIncludeInstallersInReport)667 TEST_P(UidMapTestAppendUidMapHashStrings, TestNoIncludeInstallersInReport) {
668 ProtoOutputStream proto;
669 uidMap->appendUidMap(/* timestamp */ 3, cfgKey, /* includeVersionStrings */ true,
670 /* includeInstaller */ false, /* truncatedCertificateHashSize */ 0,
671 /* omitSystemUids */ false,
672 /* str_set */ GetParam(), &proto);
673
674 UidMapping results;
675 outputStreamToProto(&proto, &results);
676
677 // Verify installer lists are empty.
678 EXPECT_THAT(results.installer_name(), IsEmpty());
679 EXPECT_THAT(results.installer_hash(), IsEmpty());
680
681 ASSERT_THAT(results.snapshots_size(), Eq(1));
682
683 // Verify that none of installer, installer_hash, installer_index fields in PackageInfo are
684 // populated.
685 EXPECT_THAT(results.snapshots(0).package_info(),
686 Each(Property(&PackageInfo::has_installer, IsFalse())));
687 EXPECT_THAT(results.snapshots(0).package_info(),
688 Each(Property(&PackageInfo::has_installer_hash, IsFalse())));
689 EXPECT_THAT(results.snapshots(0).package_info(),
690 Each(Property(&PackageInfo::has_installer_index, IsFalse())));
691 }
692
693 // Set up parameterized test for testing with different truncation hash sizes for the certificates.
694 class UidMapTestTruncateCertificateHash : public UidMapTestAppendUidMap,
695 public WithParamInterface<uint8_t> {};
696
697 INSTANTIATE_TEST_SUITE_P(ZeroOneTwoThree, UidMapTestTruncateCertificateHash,
698 Range(uint8_t{0}, uint8_t{4}));
699
TEST_P(UidMapTestTruncateCertificateHash,TestCertificateHashesTruncated)700 TEST_P(UidMapTestTruncateCertificateHash, TestCertificateHashesTruncated) {
701 const uint8_t hashSize = GetParam();
702 ProtoOutputStream proto;
703 uidMap->appendUidMap(/* timestamp */ 3, cfgKey, /* includeVersionStrings */ true,
704 /* includeInstaller */ false, hashSize, /* omitSystemUids */ false,
705 /* str_set */ nullptr, &proto);
706
707 UidMapping results;
708 outputStreamToProto(&proto, &results);
709
710 ASSERT_THAT(results.snapshots_size(), Eq(1));
711
712 vector<vector<uint8_t>> certHashes = kCertificateHashes;
713 for (vector<uint8_t>& certHash : certHashes) {
714 certHash.resize(certHash.size() < hashSize ? certHash.size() : hashSize);
715 }
716 vector<PackageInfo> expectedPackageInfos =
717 buildPackageInfos(kApps, kUids, kVersions, kVersionStrings,
718 /* installers */ {}, certHashes, kDeleted,
719 /* installerIndices*/ {},
720 /* hashStrings */ false);
721
722 EXPECT_THAT(results.snapshots(0).package_info(),
723 UnorderedPointwise(EqPackageInfo(), expectedPackageInfos));
724 }
725
726 class UidMapTestAppendUidMapSystemUids : public UidMapTestAppendUidMapBase {
727 protected:
728 static const uint64_t bucketStartTimeNs = 10000000000; // 0:10
729 uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(TEN_MINUTES) * 1000000LL;
730 StatsdConfig config;
731
SetUp()732 void SetUp() override {
733 UidData uidData =
734 createUidData({AID_LMKD, AID_APP_START + 1, AID_USER_OFFSET + AID_UWB,
735 AID_USER_OFFSET + AID_APP_START + 2, AID_ROOT, AID_APP_START - 1,
736 AID_APP_START} /* uids */,
737 {1, 2, 3, 4, 5, 6, 7} /* versions */,
738 {"v1", "v2", "v3", "v4", "v5", "v6", "v7"} /* versionStrings */,
739 {"LMKD", "app1", "UWB", "app2", "root", "app3", "app4"} /* apps */,
740 vector(7, string("installer")) /* installers */,
741 vector(7, vector<uint8_t>{}) /* certificateHashes */);
742
743 uidMap->updateMap(/* timestamp */ 1, uidData);
744
745 uidMap->updateApp(/* timestamp */ 5, "LMKD", AID_LMKD, /* versionCode */ 10, "v10",
746 /* installer */ "", /* certificateHash */ {});
747 uidMap->updateApp(/* timestamp */ 6, "UWB", AID_USER_OFFSET + AID_UWB, /* versionCode */ 20,
748 "v20", /* installer */ "", /* certificateHash */ {});
749 uidMap->updateApp(/* timestamp */ 7, "root", AID_ROOT, /* versionCode */ 50, "v50",
750 /* installer */ "", /* certificateHash */ {});
751 uidMap->updateApp(/* timestamp */ 8, "app3", AID_APP_START - 1, /* versionCode */ 60, "v60",
752 /* installer */ "", /* certificateHash */ {});
753 uidMap->updateApp(/* timestamp */ 9, "app4", AID_APP_START, /* versionCode */ 70, "v70",
754 /* installer */ "", /* certificateHash */ {});
755
756 *config.add_atom_matcher() =
757 CreateSimpleAtomMatcher("TestAtomMatcher", util::TEST_ATOM_REPORTED);
758 *config.add_event_metric() =
759 createEventMetric("TestAtomReported", config.atom_matcher(0).id(), nullopt);
760 }
761
createStatsLogProcessor(const StatsdConfig & config) const762 inline sp<StatsLogProcessor> createStatsLogProcessor(const StatsdConfig& config) const {
763 return CreateStatsLogProcessor(bucketStartTimeNs, bucketStartTimeNs, config, cfgKey,
764 /* puller */ nullptr, /* puller atomTag */ 0, uidMap);
765 }
766
getUidMapping(const sp<StatsLogProcessor> & processor) const767 UidMapping getUidMapping(const sp<StatsLogProcessor>& processor) const {
768 vector<uint8_t> buffer;
769 processor->onDumpReport(cfgKey, bucketStartTimeNs + bucketSizeNs + 1, false, true, ADB_DUMP,
770 FAST, &buffer);
771 ConfigMetricsReportList reports;
772 reports.ParseFromArray(&buffer[0], buffer.size());
773 return reports.reports(0).uid_map();
774 }
775 };
776
TEST_F(UidMapTestAppendUidMapSystemUids,testHasSystemUids)777 TEST_F(UidMapTestAppendUidMapSystemUids, testHasSystemUids) {
778 sp<StatsLogProcessor> processor = createStatsLogProcessor(config);
779 UidMapping results = getUidMapping(processor);
780
781 ASSERT_EQ(results.snapshots_size(), 1);
782 EXPECT_THAT(results.snapshots(0).package_info(),
783 IsSupersetOf({
784 Property(&PackageInfo::uid, AID_LMKD),
785 Property(&PackageInfo::uid, AID_USER_OFFSET + AID_UWB),
786 Property(&PackageInfo::uid, AID_ROOT),
787 Property(&PackageInfo::uid, AID_APP_START - 1),
788 }));
789
790 EXPECT_THAT(results.changes(), IsSupersetOf({
791 Property(&Change::uid, AID_LMKD),
792 Property(&Change::uid, AID_USER_OFFSET + AID_UWB),
793 Property(&Change::uid, AID_ROOT),
794 Property(&Change::uid, AID_APP_START - 1),
795 }));
796 }
797
TEST_F(UidMapTestAppendUidMapSystemUids,testHasNoSystemUids)798 TEST_F(UidMapTestAppendUidMapSystemUids, testHasNoSystemUids) {
799 config.mutable_statsd_config_options()->set_omit_system_uids_in_uidmap(true);
800 sp<StatsLogProcessor> processor = createStatsLogProcessor(config);
801 UidMapping results = getUidMapping(processor);
802
803 ASSERT_EQ(results.snapshots_size(), 1);
804 EXPECT_THAT(results.snapshots(0).package_info(),
805 Each(Property(&PackageInfo::uid,
806 AllOf(Not(Eq(AID_LMKD)), Not(Eq(AID_USER_OFFSET + AID_UWB)),
807 Not(Eq(AID_ROOT)), Not(Eq(AID_APP_START - 1))))));
808
809 EXPECT_THAT(results.changes(), ElementsAre(Property(&Change::uid, AID_APP_START)));
810 }
811
812 } // anonymous namespace
813 #else
814 GTEST_LOG_(INFO) << "This test does nothing.\n";
815 #endif
816
817 } // namespace statsd
818 } // namespace os
819 } // namespace android
820