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