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