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