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 #include "StatsLogProcessor.h"
17 #include "config/ConfigKey.h"
18 #include "guardrail/StatsdStats.h"
19 #include "logd/LogEvent.h"
20 #include "hash.h"
21 #include "statslog_statsdtest.h"
22 #include "statsd_test_util.h"
23
24 #include <android/util/ProtoOutputStream.h>
25 #include <gtest/gtest.h>
26
27 #include <stdio.h>
28
29 using namespace android;
30
31 namespace android {
32 namespace os {
33 namespace statsd {
34
35 using android::util::ProtoOutputStream;
36 using android::util::ProtoReader;
37
38 #ifdef __ANDROID__
39 const string kApp1 = "app1.sharing.1";
40 const string kApp2 = "app2.sharing.1";
41
TEST(UidMapTest,TestIsolatedUID)42 TEST(UidMapTest, TestIsolatedUID) {
43 sp<UidMap> m = new UidMap();
44 sp<StatsPullerManager> pullerManager = new StatsPullerManager();
45 sp<AlarmMonitor> anomalyAlarmMonitor;
46 sp<AlarmMonitor> subscriberAlarmMonitor;
47 // Construct the processor with a no-op sendBroadcast function that does nothing.
48 StatsLogProcessor p(
49 m, pullerManager, anomalyAlarmMonitor, subscriberAlarmMonitor, 0,
50 [](const ConfigKey& key) { return true; },
51 [](const int&, const vector<int64_t>&) { return true; });
52
53 std::unique_ptr<LogEvent> addEvent = CreateIsolatedUidChangedEvent(
54 1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 1 /*is_create*/);
55 EXPECT_EQ(101, m->getHostUidOrSelf(101));
56 p.OnLogEvent(addEvent.get());
57 EXPECT_EQ(100, m->getHostUidOrSelf(101));
58
59 std::unique_ptr<LogEvent> removeEvent = CreateIsolatedUidChangedEvent(
60 1 /*timestamp*/, 100 /*hostUid*/, 101 /*isolatedUid*/, 0 /*is_create*/);
61 p.OnLogEvent(removeEvent.get());
62 EXPECT_EQ(101, m->getHostUidOrSelf(101));
63 }
64
TEST(UidMapTest,TestMatching)65 TEST(UidMapTest, TestMatching) {
66 UidMap m;
67 const vector<int32_t> uids{1000, 1000};
68 const vector<int64_t> versions{4, 5};
69 const vector<String16> versionStrings{String16("v1"), String16("v1")};
70 const vector<String16> apps{String16(kApp1.c_str()), String16(kApp2.c_str())};
71 const vector<String16> installers{String16(""), String16("")};
72 const vector<vector<uint8_t>> certificateHashes{{}, {}};
73
74 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
75 certificateHashes);
76 EXPECT_TRUE(m.hasApp(1000, kApp1));
77 EXPECT_TRUE(m.hasApp(1000, kApp2));
78 EXPECT_FALSE(m.hasApp(1000, "not.app"));
79
80 std::set<string> name_set = m.getAppNamesFromUid(1000u, true /* returnNormalized */);
81 ASSERT_EQ(name_set.size(), 2u);
82 EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
83 EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
84
85 name_set = m.getAppNamesFromUid(12345, true /* returnNormalized */);
86 EXPECT_TRUE(name_set.empty());
87 }
88
TEST(UidMapTest,TestAddAndRemove)89 TEST(UidMapTest, TestAddAndRemove) {
90 UidMap m;
91 const vector<int32_t> uids{1000, 1000};
92 const vector<int64_t> versions{4, 5};
93 const vector<String16> versionStrings{String16("v1"), String16("v1")};
94 const vector<String16> apps{String16(kApp1.c_str()), String16(kApp2.c_str())};
95 const vector<String16> installers{String16(""), String16("")};
96 const vector<vector<uint8_t>> certificateHashes{{}, {}};
97
98 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
99 certificateHashes);
100
101 std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
102 ASSERT_EQ(name_set.size(), 2u);
103 EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
104 EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
105
106 // Update the app1 version.
107 m.updateApp(2, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16(""),
108 /* certificateHash */ {});
109 EXPECT_EQ(40, m.getAppVersion(1000, kApp1));
110
111 name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
112 ASSERT_EQ(name_set.size(), 2u);
113 EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
114 EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
115
116 m.removeApp(3, String16(kApp1.c_str()), 1000);
117 EXPECT_FALSE(m.hasApp(1000, kApp1));
118 EXPECT_TRUE(m.hasApp(1000, kApp2));
119 name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
120 ASSERT_EQ(name_set.size(), 1u);
121 EXPECT_TRUE(name_set.find(kApp1) == name_set.end());
122 EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
123
124 // Remove app2.
125 m.removeApp(4, String16(kApp2.c_str()), 1000);
126 EXPECT_FALSE(m.hasApp(1000, kApp1));
127 EXPECT_FALSE(m.hasApp(1000, kApp2));
128 name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
129 EXPECT_TRUE(name_set.empty());
130 }
131
TEST(UidMapTest,TestUpdateApp)132 TEST(UidMapTest, TestUpdateApp) {
133 UidMap m;
134 m.updateMap(1, {1000, 1000}, {4, 5}, {String16("v4"), String16("v5")},
135 {String16(kApp1.c_str()), String16(kApp2.c_str())}, {String16(""), String16("")},
136 /* certificateHash */ {{}, {}});
137 std::set<string> name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
138 ASSERT_EQ(name_set.size(), 2u);
139 EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
140 EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
141
142 // Adds a new name for uid 1000.
143 m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40, String16("v40"), String16(""),
144 /* certificateHash */ {});
145 name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */);
146 ASSERT_EQ(name_set.size(), 3u);
147 EXPECT_TRUE(name_set.find(kApp1) != name_set.end());
148 EXPECT_TRUE(name_set.find(kApp2) != name_set.end());
149 EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end());
150 EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
151
152 // This name is also reused by another uid 2000.
153 m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1, String16("v1"), String16(""),
154 /* certificateHash */ {});
155 name_set = m.getAppNamesFromUid(2000, true /* returnNormalized */);
156 ASSERT_EQ(name_set.size(), 1u);
157 EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end());
158 EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end());
159 }
160
protoOutputStreamToUidMapping(ProtoOutputStream * proto,UidMapping * results)161 static void protoOutputStreamToUidMapping(ProtoOutputStream* proto, UidMapping* results) {
162 vector<uint8_t> bytes;
163 bytes.resize(proto->size());
164 size_t pos = 0;
165 sp<ProtoReader> reader = proto->data();
166 while (reader->readBuffer() != NULL) {
167 size_t toRead = reader->currentToRead();
168 std::memcpy(&((bytes)[pos]), reader->readBuffer(), toRead);
169 pos += toRead;
170 reader->move(toRead);
171 }
172 results->ParseFromArray(bytes.data(), bytes.size());
173 }
174
175 // Test that uid map returns at least one snapshot even if we already obtained
176 // this snapshot from a previous call to getData.
TEST(UidMapTest,TestOutputIncludesAtLeastOneSnapshot)177 TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot) {
178 UidMap m;
179 // Initialize single config key.
180 ConfigKey config1(1, StringToId("config1"));
181 m.OnConfigUpdated(config1);
182 const vector<int32_t> uids{1000};
183 const vector<int64_t> versions{5};
184 const vector<String16> versionStrings{String16("v1")};
185 const vector<String16> apps{String16(kApp2.c_str())};
186 const vector<String16> installers{String16("")};
187 const vector<vector<uint8_t>> certificateHashes{{}};
188
189 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
190 certificateHashes);
191
192 // Set the last timestamp for this config key to be newer.
193 m.mLastUpdatePerConfigKey[config1] = 2;
194
195 ProtoOutputStream proto;
196 m.appendUidMap(/* timestamp */ 3, config1, /* includeVersionStrings */ true,
197 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
198 /* str_set */ nullptr, &proto);
199
200 // Check there's still a uidmap attached this one.
201 UidMapping results;
202 protoOutputStreamToUidMapping(&proto, &results);
203 ASSERT_EQ(1, results.snapshots_size());
204 EXPECT_EQ("v1", results.snapshots(0).package_info(0).version_string());
205 }
206
TEST(UidMapTest,TestRemovedAppRetained)207 TEST(UidMapTest, TestRemovedAppRetained) {
208 UidMap m;
209 // Initialize single config key.
210 ConfigKey config1(1, StringToId("config1"));
211 m.OnConfigUpdated(config1);
212 const vector<int32_t> uids{1000};
213 const vector<int64_t> versions{5};
214 const vector<String16> versionStrings{String16("v5")};
215 const vector<String16> apps{String16(kApp2.c_str())};
216 const vector<String16> installers{String16("")};
217 const vector<vector<uint8_t>> certificateHashes{{}};
218
219 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
220 certificateHashes);
221 m.removeApp(2, String16(kApp2.c_str()), 1000);
222
223 ProtoOutputStream proto;
224 m.appendUidMap(/* timestamp */ 3, config1, /* includeVersionStrings */ true,
225 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
226 /* str_set */ nullptr, &proto);
227
228 // Snapshot should still contain this item as deleted.
229 UidMapping results;
230 protoOutputStreamToUidMapping(&proto, &results);
231 ASSERT_EQ(1, results.snapshots(0).package_info_size());
232 EXPECT_EQ(true, results.snapshots(0).package_info(0).deleted());
233 }
234
TEST(UidMapTest,TestRemovedAppOverGuardrail)235 TEST(UidMapTest, TestRemovedAppOverGuardrail) {
236 UidMap m;
237 // Initialize single config key.
238 ConfigKey config1(1, StringToId("config1"));
239 m.OnConfigUpdated(config1);
240 vector<int32_t> uids;
241 vector<int64_t> versions;
242 vector<String16> versionStrings;
243 vector<String16> installers;
244 vector<String16> apps;
245 vector<vector<uint8_t>> certificateHashes;
246 const int maxDeletedApps = StatsdStats::kMaxDeletedAppsInUidMap;
247 for (int j = 0; j < maxDeletedApps + 10; j++) {
248 uids.push_back(j);
249 apps.push_back(String16(kApp1.c_str()));
250 versions.push_back(j);
251 versionStrings.push_back(String16("v"));
252 installers.push_back(String16(""));
253 certificateHashes.push_back({});
254 }
255 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
256 certificateHashes);
257
258 // First, verify that we have the expected number of items.
259 UidMapping results;
260 ProtoOutputStream proto;
261 m.appendUidMap(/* timestamp */ 3, config1, /* includeVersionStrings */ true,
262 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
263 /* str_set */ nullptr, &proto);
264 protoOutputStreamToUidMapping(&proto, &results);
265 ASSERT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size());
266
267 // Now remove all the apps.
268 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
269 certificateHashes);
270 for (int j = 0; j < maxDeletedApps + 10; j++) {
271 m.removeApp(4, String16(kApp1.c_str()), j);
272 }
273
274 proto.clear();
275 m.appendUidMap(/* timestamp */ 5, config1, /* includeVersionStrings */ true,
276 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
277 /* str_set */ nullptr, &proto);
278 // Snapshot drops the first nine items.
279 protoOutputStreamToUidMapping(&proto, &results);
280 ASSERT_EQ(maxDeletedApps, results.snapshots(0).package_info_size());
281 }
282
TEST(UidMapTest,TestClearingOutput)283 TEST(UidMapTest, TestClearingOutput) {
284 UidMap m;
285
286 ConfigKey config1(1, StringToId("config1"));
287 ConfigKey config2(1, StringToId("config2"));
288
289 m.OnConfigUpdated(config1);
290
291 const vector<int32_t> uids{1000, 1000};
292 const vector<int64_t> versions{4, 5};
293 const vector<String16> versionStrings{String16("v4"), String16("v5")};
294 const vector<String16> apps{String16(kApp1.c_str()), String16(kApp2.c_str())};
295 const vector<String16> installers{String16(""), String16("")};
296 const vector<vector<uint8_t>> certificateHashes{{}, {}};
297 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
298 certificateHashes);
299
300 ProtoOutputStream proto;
301 m.appendUidMap(/* timestamp */ 2, config1, /* includeVersionStrings */ true,
302 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
303 /* str_set */ nullptr, &proto);
304 UidMapping results;
305 protoOutputStreamToUidMapping(&proto, &results);
306 ASSERT_EQ(1, results.snapshots_size());
307
308 // We have to keep at least one snapshot in memory at all times.
309 proto.clear();
310 m.appendUidMap(/* timestamp */ 2, config1, /* includeVersionStrings */ true,
311 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
312 /* str_set */ nullptr, &proto);
313 protoOutputStreamToUidMapping(&proto, &results);
314 ASSERT_EQ(1, results.snapshots_size());
315
316 // Now add another configuration.
317 m.OnConfigUpdated(config2);
318 m.updateApp(5, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16(""),
319 /* certificateHash */ {});
320 ASSERT_EQ(1U, m.mChanges.size());
321 proto.clear();
322 m.appendUidMap(/* timestamp */ 6, config1, /* includeVersionStrings */ true,
323 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
324 /* str_set */ nullptr, &proto);
325 protoOutputStreamToUidMapping(&proto, &results);
326 ASSERT_EQ(1, results.snapshots_size());
327 ASSERT_EQ(1, results.changes_size());
328 ASSERT_EQ(1U, m.mChanges.size());
329
330 // Add another delta update.
331 m.updateApp(7, String16(kApp2.c_str()), 1001, 41, String16("v41"), String16(""),
332 /* certificateHash */ {});
333 ASSERT_EQ(2U, m.mChanges.size());
334
335 // We still can't remove anything.
336 proto.clear();
337 m.appendUidMap(/* timestamp */ 8, config1, /* includeVersionStrings */ true,
338 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
339 /* str_set */ nullptr, &proto);
340 protoOutputStreamToUidMapping(&proto, &results);
341 ASSERT_EQ(1, results.snapshots_size());
342 ASSERT_EQ(1, results.changes_size());
343 ASSERT_EQ(2U, m.mChanges.size());
344
345 proto.clear();
346 m.appendUidMap(/* timestamp */ 9, config2, /* includeVersionStrings */ true,
347 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
348 /* str_set */ nullptr, &proto);
349 protoOutputStreamToUidMapping(&proto, &results);
350 ASSERT_EQ(1, results.snapshots_size());
351 ASSERT_EQ(2, results.changes_size());
352 // At this point both should be cleared.
353 ASSERT_EQ(0U, m.mChanges.size());
354 }
355
TEST(UidMapTest,TestMemoryComputed)356 TEST(UidMapTest, TestMemoryComputed) {
357 UidMap m;
358
359 ConfigKey config1(1, StringToId("config1"));
360 m.OnConfigUpdated(config1);
361
362 size_t startBytes = m.mBytesUsed;
363 const vector<int32_t> uids{1000};
364 const vector<int64_t> versions{1};
365 const vector<String16> versionStrings{String16("v1")};
366 const vector<String16> apps{String16(kApp1.c_str())};
367 const vector<String16> installers{String16("")};
368 const vector<vector<uint8_t>> certificateHashes{{}};
369 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
370 certificateHashes);
371
372 m.updateApp(3, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16(""),
373 /* certificateHash */ {});
374
375 ProtoOutputStream proto;
376 vector<uint8_t> bytes;
377 m.appendUidMap(/* timestamp */ 2, config1, /* includeVersionStrings */ true,
378 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
379 /* str_set */ nullptr, &proto);
380 size_t prevBytes = m.mBytesUsed;
381
382 m.appendUidMap(/* timestamp */ 4, config1, /* includeVersionStrings */ true,
383 /* includeInstaller */ true, /* truncatedCertificateHashSize */ 0,
384 /* str_set */ nullptr, &proto);
385 EXPECT_TRUE(m.mBytesUsed < prevBytes);
386 }
387
TEST(UidMapTest,TestMemoryGuardrail)388 TEST(UidMapTest, TestMemoryGuardrail) {
389 UidMap m;
390 string buf;
391
392 ConfigKey config1(1, StringToId("config1"));
393 m.OnConfigUpdated(config1);
394
395 size_t startBytes = m.mBytesUsed;
396 vector<int32_t> uids;
397 vector<int64_t> versions;
398 vector<String16> versionStrings;
399 vector<String16> installers;
400 vector<String16> apps;
401 vector<vector<uint8_t>> certificateHashes;
402 for (int i = 0; i < 100; i++) {
403 uids.push_back(1);
404 buf = "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY." + to_string(i);
405 apps.push_back(String16(buf.c_str()));
406 versions.push_back(1);
407 versionStrings.push_back(String16("v1"));
408 installers.push_back(String16(""));
409 certificateHashes.push_back({});
410 }
411 m.updateMap(1 /* timestamp */, uids, versions, versionStrings, apps, installers,
412 certificateHashes);
413
414 m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2,
415 String16("v2"), String16(""), /* certificateHash */ {});
416 ASSERT_EQ(1U, m.mChanges.size());
417
418 // Now force deletion by limiting the memory to hold one delta change.
419 m.maxBytesOverride = 120; // Since the app string alone requires >45 characters.
420 m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4,
421 String16("v4"), String16(""), /* certificateHash */ {});
422 ASSERT_EQ(1U, m.mChanges.size());
423 }
424
425 #else
426 GTEST_LOG_(INFO) << "This test does nothing.\n";
427 #endif
428
429 } // namespace statsd
430 } // namespace os
431 } // namespace android
432