1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, versionCode 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 #define DEBUG false // STOPSHIP if true 17 #include "Log.h" 18 19 #include "hash.h" 20 #include "stats_log_util.h" 21 #include "guardrail/StatsdStats.h" 22 #include "packages/UidMap.h" 23 24 #include <android/os/IStatsCompanionService.h> 25 #include <binder/IServiceManager.h> 26 #include <utils/Errors.h> 27 28 #include <inttypes.h> 29 30 using namespace android; 31 32 using android::base::StringPrintf; 33 using android::util::FIELD_COUNT_REPEATED; 34 using android::util::FIELD_TYPE_BOOL; 35 using android::util::FIELD_TYPE_FLOAT; 36 using android::util::FIELD_TYPE_INT32; 37 using android::util::FIELD_TYPE_INT64; 38 using android::util::FIELD_TYPE_UINT64; 39 using android::util::FIELD_TYPE_MESSAGE; 40 using android::util::FIELD_TYPE_STRING; 41 using android::util::ProtoOutputStream; 42 43 namespace android { 44 namespace os { 45 namespace statsd { 46 47 const int FIELD_ID_SNAPSHOT_PACKAGE_NAME = 1; 48 const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION = 2; 49 const int FIELD_ID_SNAPSHOT_PACKAGE_UID = 3; 50 const int FIELD_ID_SNAPSHOT_PACKAGE_DELETED = 4; 51 const int FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH = 5; 52 const int FIELD_ID_SNAPSHOT_TIMESTAMP = 1; 53 const int FIELD_ID_SNAPSHOT_PACKAGE_INFO = 2; 54 const int FIELD_ID_SNAPSHOTS = 1; 55 const int FIELD_ID_CHANGES = 2; 56 const int FIELD_ID_CHANGE_DELETION = 1; 57 const int FIELD_ID_CHANGE_TIMESTAMP = 2; 58 const int FIELD_ID_CHANGE_PACKAGE = 3; 59 const int FIELD_ID_CHANGE_UID = 4; 60 const int FIELD_ID_CHANGE_NEW_VERSION = 5; 61 const int FIELD_ID_CHANGE_PREV_VERSION = 6; 62 const int FIELD_ID_CHANGE_PACKAGE_HASH = 7; 63 64 UidMap::UidMap() : mBytesUsed(0) {} 65 66 UidMap::~UidMap() {} 67 68 bool UidMap::hasApp(int uid, const string& packageName) const { 69 lock_guard<mutex> lock(mMutex); 70 71 auto it = mMap.find(std::make_pair(uid, packageName)); 72 return it != mMap.end() && !it->second.deleted; 73 } 74 75 string UidMap::normalizeAppName(const string& appName) const { 76 string normalizedName = appName; 77 std::transform(normalizedName.begin(), normalizedName.end(), normalizedName.begin(), ::tolower); 78 return normalizedName; 79 } 80 81 std::set<string> UidMap::getAppNamesFromUid(const int32_t& uid, bool returnNormalized) const { 82 lock_guard<mutex> lock(mMutex); 83 return getAppNamesFromUidLocked(uid,returnNormalized); 84 } 85 86 std::set<string> UidMap::getAppNamesFromUidLocked(const int32_t& uid, bool returnNormalized) const { 87 std::set<string> names; 88 for (const auto& kv : mMap) { 89 if (kv.first.first == uid && !kv.second.deleted) { 90 names.insert(returnNormalized ? normalizeAppName(kv.first.second) : kv.first.second); 91 } 92 } 93 return names; 94 } 95 96 int64_t UidMap::getAppVersion(int uid, const string& packageName) const { 97 lock_guard<mutex> lock(mMutex); 98 99 auto it = mMap.find(std::make_pair(uid, packageName)); 100 if (it == mMap.end() || it->second.deleted) { 101 return 0; 102 } 103 return it->second.versionCode; 104 } 105 106 void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid, 107 const vector<int64_t>& versionCode, const vector<String16>& packageName) { 108 vector<wp<PackageInfoListener>> broadcastList; 109 { 110 lock_guard<mutex> lock(mMutex); // Exclusively lock for updates. 111 112 std::unordered_map<std::pair<int, string>, AppData, PairHash> deletedApps; 113 114 // Copy all the deleted apps. 115 for (const auto& kv : mMap) { 116 if (kv.second.deleted) { 117 deletedApps[kv.first] = kv.second; 118 } 119 } 120 121 mMap.clear(); 122 for (size_t j = 0; j < uid.size(); j++) { 123 string package = string(String8(packageName[j]).string()); 124 mMap[std::make_pair(uid[j], package)] = AppData(versionCode[j]); 125 } 126 127 for (const auto& kv : deletedApps) { 128 auto mMapIt = mMap.find(kv.first); 129 if (mMapIt != mMap.end()) { 130 // Insert this deleted app back into the current map. 131 mMap[kv.first] = kv.second; 132 } 133 } 134 135 ensureBytesUsedBelowLimit(); 136 StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); 137 getListenerListCopyLocked(&broadcastList); 138 } 139 // To avoid invoking callback while holding the internal lock. we get a copy of the listener 140 // list and invoke the callback. It's still possible that after we copy the list, a 141 // listener removes itself before we call it. It's then the listener's job to handle it (expect 142 // the callback to be called after listener is removed, and the listener should properly 143 // ignore it). 144 for (auto weakPtr : broadcastList) { 145 auto strongPtr = weakPtr.promote(); 146 if (strongPtr != NULL) { 147 strongPtr->onUidMapReceived(timestamp); 148 } 149 } 150 } 151 152 void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid, 153 const int64_t& versionCode) { 154 vector<wp<PackageInfoListener>> broadcastList; 155 string appName = string(String8(app_16).string()); 156 { 157 lock_guard<mutex> lock(mMutex); 158 int32_t prevVersion = 0; 159 bool found = false; 160 auto it = mMap.find(std::make_pair(uid, appName)); 161 if (it != mMap.end()) { 162 found = true; 163 prevVersion = it->second.versionCode; 164 it->second.versionCode = versionCode; 165 it->second.deleted = false; 166 } 167 if (!found) { 168 // Otherwise, we need to add an app at this uid. 169 mMap[std::make_pair(uid, appName)] = AppData(versionCode); 170 } else { 171 // Only notify the listeners if this is an app upgrade. If this app is being installed 172 // for the first time, then we don't notify the listeners. 173 // It's also OK to split again if we're forming a partial bucket after re-installing an 174 // app after deletion. 175 getListenerListCopyLocked(&broadcastList); 176 } 177 mChanges.emplace_back(false, timestamp, appName, uid, versionCode, prevVersion); 178 mBytesUsed += kBytesChangeRecord; 179 ensureBytesUsedBelowLimit(); 180 StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); 181 StatsdStats::getInstance().setUidMapChanges(mChanges.size()); 182 } 183 184 for (auto weakPtr : broadcastList) { 185 auto strongPtr = weakPtr.promote(); 186 if (strongPtr != NULL) { 187 strongPtr->notifyAppUpgrade(timestamp, appName, uid, versionCode); 188 } 189 } 190 } 191 192 void UidMap::ensureBytesUsedBelowLimit() { 193 size_t limit; 194 if (maxBytesOverride <= 0) { 195 limit = StatsdStats::kMaxBytesUsedUidMap; 196 } else { 197 limit = maxBytesOverride; 198 } 199 while (mBytesUsed > limit) { 200 ALOGI("Bytes used %zu is above limit %zu, need to delete something", mBytesUsed, limit); 201 if (mChanges.size() > 0) { 202 mBytesUsed -= kBytesChangeRecord; 203 mChanges.pop_front(); 204 StatsdStats::getInstance().noteUidMapDropped(1); 205 } 206 } 207 } 208 209 void UidMap::getListenerListCopyLocked(vector<wp<PackageInfoListener>>* output) { 210 for (auto weakIt = mSubscribers.begin(); weakIt != mSubscribers.end();) { 211 auto strongPtr = weakIt->promote(); 212 if (strongPtr != NULL) { 213 output->push_back(*weakIt); 214 weakIt++; 215 } else { 216 weakIt = mSubscribers.erase(weakIt); 217 VLOG("The UidMap listener is gone, remove it now"); 218 } 219 } 220 } 221 222 void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid) { 223 vector<wp<PackageInfoListener>> broadcastList; 224 string app = string(String8(app_16).string()); 225 { 226 lock_guard<mutex> lock(mMutex); 227 228 int64_t prevVersion = 0; 229 auto key = std::make_pair(uid, app); 230 auto it = mMap.find(key); 231 if (it != mMap.end() && !it->second.deleted) { 232 prevVersion = it->second.versionCode; 233 it->second.deleted = true; 234 mDeletedApps.push_back(key); 235 } 236 if (mDeletedApps.size() > StatsdStats::kMaxDeletedAppsInUidMap) { 237 // Delete the oldest one. 238 auto oldest = mDeletedApps.front(); 239 mDeletedApps.pop_front(); 240 mMap.erase(oldest); 241 StatsdStats::getInstance().noteUidMapAppDeletionDropped(); 242 } 243 mChanges.emplace_back(true, timestamp, app, uid, 0, prevVersion); 244 mBytesUsed += kBytesChangeRecord; 245 ensureBytesUsedBelowLimit(); 246 StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); 247 StatsdStats::getInstance().setUidMapChanges(mChanges.size()); 248 getListenerListCopyLocked(&broadcastList); 249 } 250 251 for (auto weakPtr : broadcastList) { 252 auto strongPtr = weakPtr.promote(); 253 if (strongPtr != NULL) { 254 strongPtr->notifyAppRemoved(timestamp, app, uid); 255 } 256 } 257 } 258 259 void UidMap::addListener(wp<PackageInfoListener> producer) { 260 lock_guard<mutex> lock(mMutex); // Lock for updates 261 mSubscribers.insert(producer); 262 } 263 264 void UidMap::removeListener(wp<PackageInfoListener> producer) { 265 lock_guard<mutex> lock(mMutex); // Lock for updates 266 mSubscribers.erase(producer); 267 } 268 269 void UidMap::assignIsolatedUid(int isolatedUid, int parentUid) { 270 lock_guard<mutex> lock(mIsolatedMutex); 271 272 mIsolatedUidMap[isolatedUid] = parentUid; 273 } 274 275 void UidMap::removeIsolatedUid(int isolatedUid, int parentUid) { 276 lock_guard<mutex> lock(mIsolatedMutex); 277 278 auto it = mIsolatedUidMap.find(isolatedUid); 279 if (it != mIsolatedUidMap.end()) { 280 mIsolatedUidMap.erase(it); 281 } 282 } 283 284 int UidMap::getHostUidOrSelf(int uid) const { 285 lock_guard<mutex> lock(mIsolatedMutex); 286 287 auto it = mIsolatedUidMap.find(uid); 288 if (it != mIsolatedUidMap.end()) { 289 return it->second; 290 } 291 return uid; 292 } 293 294 void UidMap::clearOutput() { 295 mChanges.clear(); 296 // Also update the guardrail trackers. 297 StatsdStats::getInstance().setUidMapChanges(0); 298 mBytesUsed = 0; 299 StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); 300 } 301 302 int64_t UidMap::getMinimumTimestampNs() { 303 int64_t m = 0; 304 for (const auto& kv : mLastUpdatePerConfigKey) { 305 if (m == 0) { 306 m = kv.second; 307 } else if (kv.second < m) { 308 m = kv.second; 309 } 310 } 311 return m; 312 } 313 314 size_t UidMap::getBytesUsed() const { 315 return mBytesUsed; 316 } 317 318 void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, 319 std::set<string> *str_set, ProtoOutputStream* proto) { 320 lock_guard<mutex> lock(mMutex); // Lock for updates 321 322 for (const ChangeRecord& record : mChanges) { 323 if (record.timestampNs > mLastUpdatePerConfigKey[key]) { 324 uint64_t changesToken = 325 proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_CHANGES); 326 proto->write(FIELD_TYPE_BOOL | FIELD_ID_CHANGE_DELETION, (bool)record.deletion); 327 proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_TIMESTAMP, 328 (long long)record.timestampNs); 329 if (str_set != nullptr) { 330 str_set->insert(record.package); 331 proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_PACKAGE_HASH, 332 (long long)Hash64(record.package)); 333 } else { 334 proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package); 335 } 336 337 proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid); 338 proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_NEW_VERSION, (long long)record.version); 339 proto->write(FIELD_TYPE_INT64 | FIELD_ID_CHANGE_PREV_VERSION, 340 (long long)record.prevVersion); 341 proto->end(changesToken); 342 } 343 } 344 345 // Write snapshot from current uid map state. 346 uint64_t snapshotsToken = 347 proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_SNAPSHOTS); 348 proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_TIMESTAMP, (long long)timestamp); 349 for (const auto& kv : mMap) { 350 uint64_t token = proto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | 351 FIELD_ID_SNAPSHOT_PACKAGE_INFO); 352 353 if (str_set != nullptr) { 354 str_set->insert(kv.first.second); 355 proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH, 356 (long long)Hash64(kv.first.second)); 357 } else { 358 proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second); 359 } 360 361 proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, 362 (long long)kv.second.versionCode); 363 proto->write(FIELD_TYPE_INT32 | FIELD_ID_SNAPSHOT_PACKAGE_UID, kv.first.first); 364 proto->write(FIELD_TYPE_BOOL | FIELD_ID_SNAPSHOT_PACKAGE_DELETED, kv.second.deleted); 365 proto->end(token); 366 } 367 proto->end(snapshotsToken); 368 369 int64_t prevMin = getMinimumTimestampNs(); 370 mLastUpdatePerConfigKey[key] = timestamp; 371 int64_t newMin = getMinimumTimestampNs(); 372 373 if (newMin > prevMin) { // Delete anything possible now that the minimum has 374 // moved forward. 375 int64_t cutoff_nanos = newMin; 376 for (auto it_changes = mChanges.begin(); it_changes != mChanges.end();) { 377 if (it_changes->timestampNs < cutoff_nanos) { 378 mBytesUsed -= kBytesChangeRecord; 379 it_changes = mChanges.erase(it_changes); 380 } else { 381 ++it_changes; 382 } 383 } 384 } 385 StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); 386 StatsdStats::getInstance().setUidMapChanges(mChanges.size()); 387 } 388 389 void UidMap::printUidMap(FILE* out) const { 390 lock_guard<mutex> lock(mMutex); 391 392 for (const auto& kv : mMap) { 393 if (!kv.second.deleted) { 394 fprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode, 395 kv.first.first); 396 } 397 } 398 } 399 400 void UidMap::OnConfigUpdated(const ConfigKey& key) { 401 mLastUpdatePerConfigKey[key] = -1; 402 } 403 404 void UidMap::OnConfigRemoved(const ConfigKey& key) { 405 mLastUpdatePerConfigKey.erase(key); 406 } 407 408 set<int32_t> UidMap::getAppUid(const string& package) const { 409 lock_guard<mutex> lock(mMutex); 410 411 set<int32_t> results; 412 for (const auto& kv : mMap) { 413 if (kv.first.second == package && !kv.second.deleted) { 414 results.insert(kv.first.first); 415 } 416 } 417 return results; 418 } 419 420 // Note not all the following AIDs are used as uids. Some are used only for gids. 421 // It's ok to leave them in the map, but we won't ever see them in the log's uid field. 422 // App's uid starts from 10000, and will not overlap with the following AIDs. 423 const std::map<string, uint32_t> UidMap::sAidToUidMapping = {{"AID_ROOT", 0}, 424 {"AID_SYSTEM", 1000}, 425 {"AID_RADIO", 1001}, 426 {"AID_BLUETOOTH", 1002}, 427 {"AID_GRAPHICS", 1003}, 428 {"AID_INPUT", 1004}, 429 {"AID_AUDIO", 1005}, 430 {"AID_CAMERA", 1006}, 431 {"AID_LOG", 1007}, 432 {"AID_COMPASS", 1008}, 433 {"AID_MOUNT", 1009}, 434 {"AID_WIFI", 1010}, 435 {"AID_ADB", 1011}, 436 {"AID_INSTALL", 1012}, 437 {"AID_MEDIA", 1013}, 438 {"AID_DHCP", 1014}, 439 {"AID_SDCARD_RW", 1015}, 440 {"AID_VPN", 1016}, 441 {"AID_KEYSTORE", 1017}, 442 {"AID_USB", 1018}, 443 {"AID_DRM", 1019}, 444 {"AID_MDNSR", 1020}, 445 {"AID_GPS", 1021}, 446 // {"AID_UNUSED1", 1022}, 447 {"AID_MEDIA_RW", 1023}, 448 {"AID_MTP", 1024}, 449 // {"AID_UNUSED2", 1025}, 450 {"AID_DRMRPC", 1026}, 451 {"AID_NFC", 1027}, 452 {"AID_SDCARD_R", 1028}, 453 {"AID_CLAT", 1029}, 454 {"AID_LOOP_RADIO", 1030}, 455 {"AID_MEDIA_DRM", 1031}, 456 {"AID_PACKAGE_INFO", 1032}, 457 {"AID_SDCARD_PICS", 1033}, 458 {"AID_SDCARD_AV", 1034}, 459 {"AID_SDCARD_ALL", 1035}, 460 {"AID_LOGD", 1036}, 461 {"AID_SHARED_RELRO", 1037}, 462 {"AID_DBUS", 1038}, 463 {"AID_TLSDATE", 1039}, 464 {"AID_MEDIA_EX", 1040}, 465 {"AID_AUDIOSERVER", 1041}, 466 {"AID_METRICS_COLL", 1042}, 467 {"AID_METRICSD", 1043}, 468 {"AID_WEBSERV", 1044}, 469 {"AID_DEBUGGERD", 1045}, 470 {"AID_MEDIA_CODEC", 1046}, 471 {"AID_CAMERASERVER", 1047}, 472 {"AID_FIREWALL", 1048}, 473 {"AID_TRUNKS", 1049}, 474 {"AID_NVRAM", 1050}, 475 {"AID_DNS", 1051}, 476 {"AID_DNS_TETHER", 1052}, 477 {"AID_WEBVIEW_ZYGOTE", 1053}, 478 {"AID_VEHICLE_NETWORK", 1054}, 479 {"AID_MEDIA_AUDIO", 1055}, 480 {"AID_MEDIA_VIDEO", 1056}, 481 {"AID_MEDIA_IMAGE", 1057}, 482 {"AID_TOMBSTONED", 1058}, 483 {"AID_MEDIA_OBB", 1059}, 484 {"AID_ESE", 1060}, 485 {"AID_OTA_UPDATE", 1061}, 486 {"AID_AUTOMOTIVE_EVS", 1062}, 487 {"AID_LOWPAN", 1063}, 488 {"AID_HSM", 1064}, 489 {"AID_RESERVED_DISK", 1065}, 490 {"AID_STATSD", 1066}, 491 {"AID_INCIDENTD", 1067}, 492 {"AID_SHELL", 2000}, 493 {"AID_CACHE", 2001}, 494 {"AID_DIAG", 2002}}; 495 496 } // namespace statsd 497 } // namespace os 498 } // namespace android 499