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