diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index eb498f5961415..a9819972cfc76 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -370,11 +370,9 @@ void StatsLogProcessor::onConfigMetricsReportLocked(const ConfigKey& key, // This skips the uid map if it's an empty config. if (it->second->getNumMetrics() > 0) { uint64_t uidMapToken = proto->start(FIELD_TYPE_MESSAGE | FIELD_ID_UID_MAP); - if (it->second->hashStringInReport()) { - mUidMap->appendUidMap(dumpTimeStampNs, key, &str_set, proto); - } else { - mUidMap->appendUidMap(dumpTimeStampNs, key, nullptr, proto); - } + mUidMap->appendUidMap( + dumpTimeStampNs, key, it->second->hashStringInReport() ? &str_set : nullptr, + it->second->versionStringsInReport(), it->second->installerInReport(), proto); proto->end(uidMapToken); } diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 27685fc108a06..7fa05be29b9d9 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -787,21 +787,24 @@ status_t StatsService::cmd_print_logs(int out, const Vector& args) { } Status StatsService::informAllUidData(const vector& uid, const vector& version, - const vector& app) { + const vector& version_string, + const vector& app, + const vector& installer) { ENFORCE_UID(AID_SYSTEM); VLOG("StatsService::informAllUidData was called"); - mUidMap->updateMap(getElapsedRealtimeNs(), uid, version, app); + mUidMap->updateMap(getElapsedRealtimeNs(), uid, version, version_string, app, installer); VLOG("StatsService::informAllUidData succeeded"); return Status::ok(); } -Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version) { +Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version, + const String16& version_string, const String16& installer) { ENFORCE_UID(AID_SYSTEM); VLOG("StatsService::informOnePackage was called"); - mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version); + mUidMap->updateApp(getElapsedRealtimeNs(), app, uid, version, version_string, installer); return Status::ok(); } diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 4a5f05fef034c..cd4d601a606fa 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -73,8 +73,10 @@ public: virtual Status informAlarmForSubscriberTriggeringFired(); virtual Status informAllUidData(const vector& uid, const vector& version, - const vector& app); - virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version); + const vector& version_string, + const vector& app, const vector& installer); + virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version, + const String16& version_string, const String16& installer); virtual Status informOnePackageRemoved(const String16& app, int32_t uid); virtual Status informDeviceShutdown(); diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index 4244d5bed23b0..ac34f4760a12b 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -77,6 +77,8 @@ MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, mActivationAtomTrackerToMetricMap, mMetricIndexesWithActivation, mNoReportMetricIds); mHashStringsInReport = config.hash_strings_in_metric_report(); + mVersionStringsInReport = config.version_strings_in_metric_report(); + mInstallerInReport = config.installer_in_metric_report(); if (config.allowed_log_source_size() == 0) { mConfigValid = false; diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index a4672b68f2bc9..a31efbd3c8a68 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -83,6 +83,14 @@ public: return mHashStringsInReport; }; + inline bool versionStringsInReport() const { + return mVersionStringsInReport; + }; + + inline bool installerInReport() const { + return mInstallerInReport; + }; + void refreshTtl(const int64_t currentTimestampNs) { if (mTtlNs > 0) { mTtlEndNs = currentTimestampNs + mTtlNs; @@ -126,6 +134,8 @@ private: bool mConfigValid = false; bool mHashStringsInReport = false; + bool mVersionStringsInReport = false; + bool mInstallerInReport = false; const int64_t mTtlNs; int64_t mTtlEndNs; diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp index 37a00673959c8..59f3f0448e0e8 100644 --- a/cmds/statsd/src/packages/UidMap.cpp +++ b/cmds/statsd/src/packages/UidMap.cpp @@ -49,6 +49,10 @@ const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION = 2; const int FIELD_ID_SNAPSHOT_PACKAGE_UID = 3; const int FIELD_ID_SNAPSHOT_PACKAGE_DELETED = 4; const int FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH = 5; +const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING = 6; +const int FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH = 7; +const int FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER = 8; +const int FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH = 9; const int FIELD_ID_SNAPSHOT_TIMESTAMP = 1; const int FIELD_ID_SNAPSHOT_PACKAGE_INFO = 2; const int FIELD_ID_SNAPSHOTS = 1; @@ -60,6 +64,10 @@ const int FIELD_ID_CHANGE_UID = 4; const int FIELD_ID_CHANGE_NEW_VERSION = 5; const int FIELD_ID_CHANGE_PREV_VERSION = 6; const int FIELD_ID_CHANGE_PACKAGE_HASH = 7; +const int FIELD_ID_CHANGE_NEW_VERSION_STRING = 8; +const int FIELD_ID_CHANGE_PREV_VERSION_STRING = 9; +const int FIELD_ID_CHANGE_NEW_VERSION_STRING_HASH = 10; +const int FIELD_ID_CHANGE_PREV_VERSION_STRING_HASH = 11; UidMap::UidMap() : mBytesUsed(0) {} @@ -104,7 +112,8 @@ int64_t UidMap::getAppVersion(int uid, const string& packageName) const { } void UidMap::updateMap(const int64_t& timestamp, const vector& uid, - const vector& versionCode, const vector& packageName) { + const vector& versionCode, const vector& versionString, + const vector& packageName, const vector& installer) { vector> broadcastList; { lock_guard lock(mMutex); // Exclusively lock for updates. @@ -121,7 +130,9 @@ void UidMap::updateMap(const int64_t& timestamp, const vector& uid, mMap.clear(); for (size_t j = 0; j < uid.size(); j++) { string package = string(String8(packageName[j]).string()); - mMap[std::make_pair(uid[j], package)] = AppData(versionCode[j]); + mMap[std::make_pair(uid[j], package)] = + AppData(versionCode[j], string(String8(versionString[j]).string()), + string(String8(installer[j]).string())); } for (const auto& kv : deletedApps) { @@ -150,23 +161,30 @@ void UidMap::updateMap(const int64_t& timestamp, const vector& uid, } void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid, - const int64_t& versionCode) { + const int64_t& versionCode, const String16& versionString, + const String16& installer) { vector> broadcastList; string appName = string(String8(app_16).string()); { lock_guard lock(mMutex); int32_t prevVersion = 0; + string prevVersionString = ""; + string newVersionString = string(String8(versionString).string()); bool found = false; auto it = mMap.find(std::make_pair(uid, appName)); if (it != mMap.end()) { found = true; prevVersion = it->second.versionCode; + prevVersionString = it->second.versionString; it->second.versionCode = versionCode; + it->second.versionString = newVersionString; + it->second.installer = string(String8(installer).string()); it->second.deleted = false; } if (!found) { // Otherwise, we need to add an app at this uid. - mMap[std::make_pair(uid, appName)] = AppData(versionCode); + mMap[std::make_pair(uid, appName)] = + AppData(versionCode, newVersionString, string(String8(installer).string())); } else { // Only notify the listeners if this is an app upgrade. If this app is being installed // for the first time, then we don't notify the listeners. @@ -174,7 +192,8 @@ void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const i // app after deletion. getListenerListCopyLocked(&broadcastList); } - mChanges.emplace_back(false, timestamp, appName, uid, versionCode, prevVersion); + mChanges.emplace_back(false, timestamp, appName, uid, versionCode, newVersionString, + prevVersion, prevVersionString); mBytesUsed += kBytesChangeRecord; ensureBytesUsedBelowLimit(); StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); @@ -226,10 +245,12 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i lock_guard lock(mMutex); int64_t prevVersion = 0; + string prevVersionString = ""; auto key = std::make_pair(uid, app); auto it = mMap.find(key); if (it != mMap.end() && !it->second.deleted) { prevVersion = it->second.versionCode; + prevVersionString = it->second.versionString; it->second.deleted = true; mDeletedApps.push_back(key); } @@ -240,7 +261,7 @@ void UidMap::removeApp(const int64_t& timestamp, const String16& app_16, const i mMap.erase(oldest); StatsdStats::getInstance().noteUidMapAppDeletionDropped(); } - mChanges.emplace_back(true, timestamp, app, uid, 0, prevVersion); + mChanges.emplace_back(true, timestamp, app, uid, 0, "", prevVersion, prevVersionString); mBytesUsed += kBytesChangeRecord; ensureBytesUsedBelowLimit(); StatsdStats::getInstance().setCurrentUidMapMemory(mBytesUsed); @@ -315,8 +336,9 @@ size_t UidMap::getBytesUsed() const { return mBytesUsed; } -void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, - std::set *str_set, ProtoOutputStream* proto) { +void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set* str_set, + bool includeVersionStrings, bool includeInstaller, + ProtoOutputStream* proto) { lock_guard lock(mMutex); // Lock for updates for (const ChangeRecord& record : mChanges) { @@ -330,8 +352,22 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, str_set->insert(record.package); proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_PACKAGE_HASH, (long long)Hash64(record.package)); + if (includeVersionStrings) { + str_set->insert(record.versionString); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_NEW_VERSION_STRING_HASH, + (long long)Hash64(record.versionString)); + str_set->insert(record.prevVersionString); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_CHANGE_PREV_VERSION_STRING_HASH, + (long long)Hash64(record.prevVersionString)); + } } else { proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PACKAGE, record.package); + if (includeVersionStrings) { + proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_NEW_VERSION_STRING, + record.versionString); + proto->write(FIELD_TYPE_STRING | FIELD_ID_CHANGE_PREV_VERSION_STRING, + record.prevVersionString); + } } proto->write(FIELD_TYPE_INT32 | FIELD_ID_CHANGE_UID, (int)record.uid); @@ -354,8 +390,26 @@ void UidMap::appendUidMap(const int64_t& timestamp, const ConfigKey& key, str_set->insert(kv.first.second); proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_NAME_HASH, (long long)Hash64(kv.first.second)); + if (includeVersionStrings) { + str_set->insert(kv.second.versionString); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING_HASH, + (long long)Hash64(kv.second.versionString)); + } + if (includeInstaller) { + str_set->insert(kv.second.installer); + proto->write(FIELD_TYPE_UINT64 | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER_HASH, + (long long)Hash64(kv.second.installer)); + } } else { proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_NAME, kv.first.second); + if (includeVersionStrings) { + proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_VERSION_STRING, + kv.second.versionString); + } + if (includeInstaller) { + proto->write(FIELD_TYPE_STRING | FIELD_ID_SNAPSHOT_PACKAGE_INSTALLER, + kv.second.installer); + } } proto->write(FIELD_TYPE_INT64 | FIELD_ID_SNAPSHOT_PACKAGE_VERSION, @@ -391,8 +445,9 @@ void UidMap::printUidMap(int out) const { for (const auto& kv : mMap) { if (!kv.second.deleted) { - dprintf(out, "%s, v%" PRId64 " (%i)\n", kv.first.second.c_str(), kv.second.versionCode, - kv.first.first); + dprintf(out, "%s, v%" PRId64 ", %s, %s (%i)\n", kv.first.second.c_str(), + kv.second.versionCode, kv.second.versionString.c_str(), + kv.second.installer.c_str(), kv.first.first); } } } diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h index 4598369f12221..75ff507ef09a4 100644 --- a/cmds/statsd/src/packages/UidMap.h +++ b/cmds/statsd/src/packages/UidMap.h @@ -44,12 +44,16 @@ namespace statsd { struct AppData { int64_t versionCode; + string versionString; + string installer; bool deleted; // Empty constructor needed for unordered map. AppData() { } - AppData(const int64_t v) : versionCode(v), deleted(false){}; + + AppData(const int64_t v, const string& versionString, const string& installer) + : versionCode(v), versionString(versionString), installer(installer), deleted(false){}; }; // When calling appendUidMap, we retrieve all the ChangeRecords since the last @@ -61,15 +65,20 @@ struct ChangeRecord { const int32_t uid; const int64_t version; const int64_t prevVersion; + const string versionString; + const string prevVersionString; ChangeRecord(const bool isDeletion, const int64_t timestampNs, const string& package, - const int32_t uid, const int64_t version, const int64_t prevVersion) + const int32_t uid, const int64_t version, const string versionString, + const int64_t prevVersion, const string prevVersionString) : deletion(isDeletion), timestampNs(timestampNs), package(package), uid(uid), version(version), - prevVersion(prevVersion) { + prevVersion(prevVersion), + versionString(versionString), + prevVersionString(prevVersionString) { } }; @@ -87,10 +96,12 @@ public: * tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j]. */ void updateMap(const int64_t& timestamp, const vector& uid, - const vector& versionCode, const vector& packageName); + const vector& versionCode, const vector& versionString, + const vector& packageName, const vector& installer); void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid, - const int64_t& versionCode); + const int64_t& versionCode, const String16& versionString, + const String16& installer); void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid); // Returns true if the given uid contains the specified app (eg. com.google.android.gms). @@ -127,8 +138,9 @@ public: // Gets all snapshots and changes that have occurred since the last output. // If every config key has received a change or snapshot record, then this // record is deleted. - void appendUidMap(const int64_t& timestamp, const ConfigKey& key, - std::set *str_set, util::ProtoOutputStream* proto); + void appendUidMap(const int64_t& timestamp, const ConfigKey& key, std::set* str_set, + bool includeVersionStrings, bool includeInstaller, + util::ProtoOutputStream* proto); // Forces the output to be cleared. We still generate a snapshot based on the current state. // This results in extra data uploaded but helps us reconstruct the uid mapping on the server diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 5d0f3d1db8c9b..32ee5af9ee218 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -233,6 +233,14 @@ message UidMapping { optional bool deleted = 4; optional uint64 name_hash = 5; + + optional string version_string = 6; + + optional uint64 version_string_hash = 7; + + optional string installer = 8; + + optional uint64 installer_hash = 9; } optional int64 elapsed_timestamp_nanos = 1; @@ -250,6 +258,10 @@ message UidMapping { optional int64 new_version = 5; optional int64 prev_version = 6; optional uint64 app_hash = 7; + optional string new_version_string = 8; + optional string prev_version_string = 9; + optional uint64 new_version_string_hash = 10; + optional uint64 prev_version_string_hash = 11; } repeated Change changes = 2; } diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index aa789c799056e..f955df29aee0a 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -409,6 +409,10 @@ message StatsdConfig { repeated MetricActivation metric_activation = 17; + optional bool version_strings_in_metric_report = 18; + + optional bool installer_in_metric_report = 19; + // Field number 1000 is reserved for later use. reserved 1000; } diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp index 4c6671dcd6632..2b9528f7d1de8 100644 --- a/cmds/statsd/tests/LogEntryMatcher_test.cpp +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -148,8 +148,12 @@ TEST(AtomMatcherTest, TestAttributionMatcher) { uidMap.updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, + {android::String16("v1"), android::String16("v1"), android::String16("v2"), + android::String16("v1"), android::String16("v2")}, {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"), - android::String16("Pkg2"), android::String16("PkG3")} /* package name list */); + android::String16("Pkg2"), android::String16("PkG3")} /* package name list */, + {android::String16(""), android::String16(""), android::String16(""), + android::String16(""), android::String16("")}); EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); attributionMatcher->mutable_matches_tuple()->mutable_field_value_matcher(0) @@ -297,8 +301,12 @@ TEST(AtomMatcherTest, TestNeqAnyStringMatcher) { UidMap uidMap; uidMap.updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, + {android::String16("v1"), android::String16("v1"), android::String16("v2"), + android::String16("v1"), android::String16("v2")}, {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"), - android::String16("Pkg2"), android::String16("PkG3")} /* package name list */); + android::String16("Pkg2"), android::String16("PkG3")} /* package name list */, + {android::String16(""), android::String16(""), android::String16(""), + android::String16(""), android::String16("")}); AttributionNodeInternal attribution_node1; attribution_node1.set_uid(1111); @@ -372,8 +380,12 @@ TEST(AtomMatcherTest, TestEqAnyStringMatcher) { UidMap uidMap; uidMap.updateMap( 1, {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, + {android::String16("v1"), android::String16("v1"), android::String16("v2"), + android::String16("v1"), android::String16("v2")}, {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"), - android::String16("Pkg2"), android::String16("PkG3")} /* package name list */); + android::String16("Pkg2"), android::String16("PkG3")} /* package name list */, + {android::String16(""), android::String16(""), android::String16(""), + android::String16(""), android::String16("")}); AttributionNodeInternal attribution_node1; attribution_node1.set_uid(1067); diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 8864252bcf4bd..355df2986a0b8 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -153,7 +153,8 @@ TEST(StatsLogProcessorTest, TestUidMapHasSnapshot) { // Setup simple config key corresponding to empty config. sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); - m->updateMap(1, {1, 2}, {1, 2}, {String16("p1"), String16("p2")}); + m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")}, + {String16("p1"), String16("p2")}, {String16(""), String16("")}); sp anomalyAlarmMonitor; sp subscriberAlarmMonitor; int broadcastCount = 0; @@ -182,7 +183,8 @@ TEST(StatsLogProcessorTest, TestEmptyConfigHasNoUidMap) { // Setup simple config key corresponding to empty config. sp m = new UidMap(); sp pullerManager = new StatsPullerManager(); - m->updateMap(1, {1, 2}, {1, 2}, {String16("p1"), String16("p2")}); + m->updateMap(1, {1, 2}, {1, 2}, {String16("v1"), String16("v2")}, + {String16("p1"), String16("p2")}, {String16(""), String16("")}); sp anomalyAlarmMonitor; sp subscriberAlarmMonitor; int broadcastCount = 0; diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp index 99082cc647f66..f0d9cf1886616 100644 --- a/cmds/statsd/tests/UidMap_test.cpp +++ b/cmds/statsd/tests/UidMap_test.cpp @@ -71,14 +71,20 @@ TEST(UidMapTest, TestMatching) { vector uids; vector versions; vector apps; + vector versionStrings; + vector installers; uids.push_back(1000); uids.push_back(1000); + versionStrings.push_back(String16("v1")); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); + installers.push_back(String16("")); apps.push_back(String16(kApp1.c_str())); apps.push_back(String16(kApp2.c_str())); versions.push_back(4); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); EXPECT_TRUE(m.hasApp(1000, kApp1)); EXPECT_TRUE(m.hasApp(1000, kApp2)); EXPECT_FALSE(m.hasApp(1000, "not.app")); @@ -97,14 +103,20 @@ TEST(UidMapTest, TestAddAndRemove) { vector uids; vector versions; vector apps; + vector versionStrings; + vector installers; uids.push_back(1000); uids.push_back(1000); + versionStrings.push_back(String16("v1")); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); + installers.push_back(String16("")); apps.push_back(String16(kApp1.c_str())); apps.push_back(String16(kApp2.c_str())); versions.push_back(4); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); std::set name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */); EXPECT_EQ(name_set.size(), 2u); @@ -112,7 +124,7 @@ TEST(UidMapTest, TestAddAndRemove) { EXPECT_TRUE(name_set.find(kApp2) != name_set.end()); // Update the app1 version. - m.updateApp(2, String16(kApp1.c_str()), 1000, 40); + m.updateApp(2, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16("")); EXPECT_EQ(40, m.getAppVersion(1000, kApp1)); name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */); @@ -138,14 +150,15 @@ TEST(UidMapTest, TestAddAndRemove) { TEST(UidMapTest, TestUpdateApp) { UidMap m; - m.updateMap(1, {1000, 1000}, {4, 5}, {String16(kApp1.c_str()), String16(kApp2.c_str())}); + m.updateMap(1, {1000, 1000}, {4, 5}, {String16("v4"), String16("v5")}, + {String16(kApp1.c_str()), String16(kApp2.c_str())}, {String16(""), String16("")}); std::set name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */); EXPECT_EQ(name_set.size(), 2u); EXPECT_TRUE(name_set.find(kApp1) != name_set.end()); EXPECT_TRUE(name_set.find(kApp2) != name_set.end()); // Adds a new name for uid 1000. - m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40); + m.updateApp(2, String16("NeW_aPP1_NAmE"), 1000, 40, String16("v40"), String16("")); name_set = m.getAppNamesFromUid(1000, true /* returnNormalized */); EXPECT_EQ(name_set.size(), 3u); EXPECT_TRUE(name_set.find(kApp1) != name_set.end()); @@ -154,7 +167,7 @@ TEST(UidMapTest, TestUpdateApp) { EXPECT_TRUE(name_set.find("new_app1_name") != name_set.end()); // This name is also reused by another uid 2000. - m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1); + m.updateApp(3, String16("NeW_aPP1_NAmE"), 2000, 1, String16("v1"), String16("")); name_set = m.getAppNamesFromUid(2000, true /* returnNormalized */); EXPECT_EQ(name_set.size(), 1u); EXPECT_TRUE(name_set.find("NeW_aPP1_NAmE") == name_set.end()); @@ -185,21 +198,26 @@ TEST(UidMapTest, TestOutputIncludesAtLeastOneSnapshot) { vector uids; vector versions; vector apps; + vector versionStrings; + vector installers; uids.push_back(1000); apps.push_back(String16(kApp2.c_str())); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); // Set the last timestamp for this config key to be newer. m.mLastUpdatePerConfigKey[config1] = 2; ProtoOutputStream proto; - m.appendUidMap(3, config1, nullptr, &proto); + m.appendUidMap(3, config1, nullptr, true, true, &proto); // Check there's still a uidmap attached this one. UidMapping results; protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); + EXPECT_EQ("v1", results.snapshots(0).package_info(0).version_string()); } TEST(UidMapTest, TestRemovedAppRetained) { @@ -209,15 +227,19 @@ TEST(UidMapTest, TestRemovedAppRetained) { m.OnConfigUpdated(config1); vector uids; vector versions; + vector versionStrings; + vector installers; vector apps; uids.push_back(1000); apps.push_back(String16(kApp2.c_str())); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + versionStrings.push_back(String16("v5")); + installers.push_back(String16("")); + m.updateMap(1, uids, versions, versionStrings, apps, installers); m.removeApp(2, String16(kApp2.c_str()), 1000); ProtoOutputStream proto; - m.appendUidMap(3, config1, nullptr, &proto); + m.appendUidMap(3, config1, nullptr, true, true, &proto); // Snapshot should still contain this item as deleted. UidMapping results; @@ -233,30 +255,34 @@ TEST(UidMapTest, TestRemovedAppOverGuardrail) { m.OnConfigUpdated(config1); vector uids; vector versions; + vector versionStrings; + vector installers; vector apps; const int maxDeletedApps = StatsdStats::kMaxDeletedAppsInUidMap; for (int j = 0; j < maxDeletedApps + 10; j++) { uids.push_back(j); apps.push_back(String16(kApp1.c_str())); versions.push_back(j); + versionStrings.push_back(String16("v")); + installers.push_back(String16("")); } - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); // First, verify that we have the expected number of items. UidMapping results; ProtoOutputStream proto; - m.appendUidMap(3, config1, nullptr, &proto); + m.appendUidMap(3, config1, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(maxDeletedApps + 10, results.snapshots(0).package_info_size()); // Now remove all the apps. - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); for (int j = 0; j < maxDeletedApps + 10; j++) { m.removeApp(4, String16(kApp1.c_str()), j); } proto.clear(); - m.appendUidMap(5, config1, nullptr, &proto); + m.appendUidMap(5, config1, nullptr, true, true, &proto); // Snapshot drops the first nine items. protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(maxDeletedApps, results.snapshots(0).package_info_size()); @@ -272,6 +298,8 @@ TEST(UidMapTest, TestClearingOutput) { vector uids; vector versions; + vector versionStrings; + vector installers; vector apps; uids.push_back(1000); uids.push_back(1000); @@ -279,45 +307,49 @@ TEST(UidMapTest, TestClearingOutput) { apps.push_back(String16(kApp2.c_str())); versions.push_back(4); versions.push_back(5); - m.updateMap(1, uids, versions, apps); + versionStrings.push_back(String16("v4")); + versionStrings.push_back(String16("v5")); + installers.push_back(String16("")); + installers.push_back(String16("")); + m.updateMap(1, uids, versions, versionStrings, apps, installers); ProtoOutputStream proto; - m.appendUidMap(2, config1, nullptr, &proto); + m.appendUidMap(2, config1, nullptr, true, true, &proto); UidMapping results; protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); // We have to keep at least one snapshot in memory at all times. proto.clear(); - m.appendUidMap(2, config1, nullptr, &proto); + m.appendUidMap(2, config1, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); // Now add another configuration. m.OnConfigUpdated(config2); - m.updateApp(5, String16(kApp1.c_str()), 1000, 40); + m.updateApp(5, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16("")); EXPECT_EQ(1U, m.mChanges.size()); proto.clear(); - m.appendUidMap(6, config1, nullptr, &proto); + m.appendUidMap(6, config1, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); EXPECT_EQ(1, results.changes_size()); EXPECT_EQ(1U, m.mChanges.size()); // Add another delta update. - m.updateApp(7, String16(kApp2.c_str()), 1001, 41); + m.updateApp(7, String16(kApp2.c_str()), 1001, 41, String16("v41"), String16("")); EXPECT_EQ(2U, m.mChanges.size()); // We still can't remove anything. proto.clear(); - m.appendUidMap(8, config1, nullptr, &proto); + m.appendUidMap(8, config1, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); EXPECT_EQ(1, results.changes_size()); EXPECT_EQ(2U, m.mChanges.size()); proto.clear(); - m.appendUidMap(9, config2, nullptr, &proto); + m.appendUidMap(9, config2, nullptr, true, true, &proto); protoOutputStreamToUidMapping(&proto, &results); EXPECT_EQ(1, results.snapshots_size()); EXPECT_EQ(2, results.changes_size()); @@ -335,19 +367,23 @@ TEST(UidMapTest, TestMemoryComputed) { vector uids; vector versions; vector apps; + vector versionStrings; + vector installers; uids.push_back(1000); apps.push_back(String16(kApp1.c_str())); versions.push_back(1); - m.updateMap(1, uids, versions, apps); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); + m.updateMap(1, uids, versions, versionStrings, apps, installers); - m.updateApp(3, String16(kApp1.c_str()), 1000, 40); + m.updateApp(3, String16(kApp1.c_str()), 1000, 40, String16("v40"), String16("")); ProtoOutputStream proto; vector bytes; - m.appendUidMap(2, config1, nullptr, &proto); + m.appendUidMap(2, config1, nullptr, true, true, &proto); size_t prevBytes = m.mBytesUsed; - m.appendUidMap(4, config1, nullptr, &proto); + m.appendUidMap(4, config1, nullptr, true, true, &proto); EXPECT_TRUE(m.mBytesUsed < prevBytes); } @@ -361,21 +397,27 @@ TEST(UidMapTest, TestMemoryGuardrail) { size_t startBytes = m.mBytesUsed; vector uids; vector versions; + vector versionStrings; + vector installers; vector apps; for (int i = 0; i < 100; i++) { uids.push_back(1); buf = "EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY." + to_string(i); apps.push_back(String16(buf.c_str())); versions.push_back(1); + versionStrings.push_back(String16("v1")); + installers.push_back(String16("")); } - m.updateMap(1, uids, versions, apps); + m.updateMap(1, uids, versions, versionStrings, apps, installers); - m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2); + m.updateApp(3, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 2, + String16("v2"), String16("")); EXPECT_EQ(1U, m.mChanges.size()); // Now force deletion by limiting the memory to hold one delta change. - m.maxBytesOverride = 80; // Since the app string alone requires >45 characters. - m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4); + m.maxBytesOverride = 120; // Since the app string alone requires >45 characters. + m.updateApp(5, String16("EXTREMELY_LONG_STRING_FOR_APP_TO_WASTE_MEMORY.0"), 1000, 4, + String16("v4"), String16("")); EXPECT_EQ(1U, m.mChanges.size()); } diff --git a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp index 5c47af797eea6..a9841c91ada28 100644 --- a/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/Attribution_e2e_test.cpp @@ -69,8 +69,10 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid) { // Here it assumes that GMS core has two uids. processor->getUidMap()->updateMap( 1, {222, 444, 111, 333}, {1, 1, 2, 2}, + {String16("v1"), String16("v1"), String16("v2"), String16("v2")}, {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"), - String16("APP3")}); + String16("APP3")}, + {String16(""), String16(""), String16(""), String16("")}); // GMS core node is in the middle. std::vector attributions1 = {CreateAttribution(111, "App1"), @@ -215,8 +217,10 @@ TEST(AttributionE2eTest, TestAttributionMatchAndSliceByChain) { // Here it assumes that GMS core has two uids. processor->getUidMap()->updateMap( 1, {222, 444, 111, 333}, {1, 1, 2, 2}, + {String16("v1"), String16("v1"), String16("v2"), String16("v2")}, {String16("com.android.gmscore"), String16("com.android.gmscore"), String16("app1"), - String16("APP3")}); + String16("APP3")}, + {String16(""), String16(""), String16(""), String16("")}); // GMS core node is in the middle. std::vector attributions1 = {CreateAttribution(111, "App1"), diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp index 3cb553fd9a16e..2b0285b374737 100644 --- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp @@ -132,7 +132,8 @@ TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) { service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); // This is a new installation, so there shouldn't be a split (should be same as the without // split case). - service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); // Goes into the second bucket. service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get()); @@ -145,11 +146,13 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) { SendConfig(service, MakeConfig()); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. - service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())}); + service.mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())}, + {String16("")}); // Force the uidmap to update at timestamp 2. service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); - service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(start + 2, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); // Goes into the second bucket. service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 3).get()); @@ -168,7 +171,8 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) { SendConfig(service, MakeConfig()); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. - service.mUidMap->updateMap(start, {1}, {1}, {String16(kApp1.c_str())}); + service.mUidMap->updateMap(start, {1}, {1}, {String16("v1")}, {String16(kApp1.c_str())}, + {String16("")}); // Force the uidmap to update at timestamp 2. service.mProcessor->OnLogEvent(CreateAppCrashEvent(100, start + 1).get()); @@ -189,13 +193,14 @@ TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) { TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) { StatsService service(nullptr); // Partial buckets don't occur when app is first installed. - service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1); + service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeValueMetricConfig(0)); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start); - service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2, + String16("v2"), String16("")); ConfigMetricsReport report = GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true); @@ -206,14 +211,15 @@ TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) { TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) { StatsService service(nullptr); // Partial buckets don't occur when app is first installed. - service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1); + service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */)); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2; service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start); - service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); ConfigMetricsReport report = GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true); @@ -229,13 +235,14 @@ TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) { TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) { StatsService service(nullptr); // Partial buckets don't occur when app is first installed. - service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1); + service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeGaugeMetricConfig(0)); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start); - service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(5 * 60 * NS_PER_SEC + start + 2, String16(kApp1.c_str()), 1, 2, + String16("v2"), String16("")); ConfigMetricsReport report = GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100, true); @@ -246,14 +253,15 @@ TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) { TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) { StatsService service(nullptr); // Partial buckets don't occur when app is first installed. - service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1); + service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16("")); SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */)); int64_t start = getElapsedRealtimeNs(); // This is the start-time the metrics producers are // initialized with. const int64_t endSkipped = 5 * 60 * NS_PER_SEC + start + 2; service.mProcessor->informPullAlarmFired(5 * 60 * NS_PER_SEC + start); - service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2); + service.mUidMap->updateApp(endSkipped, String16(kApp1.c_str()), 1, 2, String16("v2"), + String16("")); ConfigMetricsReport report = GetReports(service.mProcessor, 5 * 60 * NS_PER_SEC + start + 100 * NS_PER_SEC, true); diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index 124f2072933ea..74d434c517814 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -62,12 +62,15 @@ interface IStatsManager { * Inform statsd what the version and package are for each uid. Note that each array should * have the same number of elements, and version[i] and package[i] correspond to uid[i]. */ - oneway void informAllUidData(in int[] uid, in long[] version, in String[] app); + oneway void informAllUidData(in int[] uid, in long[] version, in String[] version_string, + in String[] app, in String[] installer); /** - * Inform statsd what the uid and version are for one app that was updated. + * Inform statsd what the uid, version, version_string, and installer are for one app that was + * updated. */ - oneway void informOnePackage(in String app, in int uid, in long version); + oneway void informOnePackage(in String app, in int uid, in long version, + in String version_string, in String installer); /** * Inform stats that an app was removed. diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 01d02d61cc839..70220d8102afc 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -366,6 +366,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { List uids = new ArrayList<>(); List versions = new ArrayList<>(); List apps = new ArrayList<>(); + List versionStrings = new ArrayList<>(); + List installers = new ArrayList<>(); // Add in all the apps for every user/profile. for (UserInfo profile : users) { @@ -373,14 +375,24 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { pm.getInstalledPackagesAsUser(PackageManager.MATCH_KNOWN_PACKAGES, profile.id); for (int j = 0; j < pi.size(); j++) { if (pi.get(j).applicationInfo != null) { + String installer; + try { + installer = pm.getInstallerPackageName(pi.get(j).packageName); + } catch (IllegalArgumentException e) { + installer = ""; + } + installers.add(installer == null ? "" : installer); uids.add(pi.get(j).applicationInfo.uid); versions.add(pi.get(j).getLongVersionCode()); + versionStrings.add(pi.get(j).versionName); apps.add(pi.get(j).packageName); } } } - sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new - String[apps.size()])); + sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), + versionStrings.toArray(new String[versionStrings.size()]), + apps.toArray(new String[apps.size()]), + installers.toArray(new String[installers.size()])); if (DEBUG) { Slog.d(TAG, "Sent data for " + uids.size() + " apps"); } @@ -422,7 +434,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { int uid = b.getInt(Intent.EXTRA_UID); String app = intent.getData().getSchemeSpecificPart(); PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER); - sStatsd.informOnePackage(app, uid, pi.getLongVersionCode()); + String installer; + try { + installer = pm.getInstallerPackageName(app); + } catch (IllegalArgumentException e) { + installer = ""; + } + sStatsd.informOnePackage(app, uid, pi.getLongVersionCode(), pi.versionName, + installer == null ? "" : installer); } } catch (Exception e) { Slog.w(TAG, "Failed to inform statsd of an app update", e);