MediaMetrics: Move package name from uid to service utilities
Allows sharing class with AudioFlinger.
Bug: 129355845
Bug: 138583596
Test: atest mediametrics_tests
Test: adb shell dumpsys media.metrics
Change-Id: I6654dc9456dcd7c93821a8d83dd75d96b658f254
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index 0840f31..20f346c 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -12,6 +12,7 @@
"libbinder",
"liblog",
"libmediametricsservice",
+ "libmediautils",
"libutils",
],
@@ -52,6 +53,7 @@
"libbinder",
"liblog",
"libmediametrics",
+ "libmediautils",
"libprotobuf-cpp-lite",
"libstatslog",
"libutils",
diff --git a/services/mediametrics/MediaMetricsService.cpp b/services/mediametrics/MediaMetricsService.cpp
index bbd13fa..b5bdd6f 100644
--- a/services/mediametrics/MediaMetricsService.cpp
+++ b/services/mediametrics/MediaMetricsService.cpp
@@ -57,6 +57,25 @@
return (timeNs + NANOS_PER_SECOND / 2) / NANOS_PER_SECOND * NANOS_PER_SECOND;
}
+/* static */
+bool MediaMetricsService::useUidForPackage(
+ const std::string& package, const std::string& installer)
+{
+ if (strchr(package.c_str(), '.') == NULL) {
+ return false; // not of form 'com.whatever...'; assume internal and ok
+ } else if (strncmp(package.c_str(), "android.", 8) == 0) {
+ return false; // android.* packages are assumed fine
+ } else if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
+ return false; // from play store
+ } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
+ return false; // some google source
+ } else if (strcmp(installer.c_str(), "preload") == 0) {
+ return false; // preloads
+ } else {
+ return true; // we're not sure where it came from, use uid only.
+ }
+}
+
MediaMetricsService::MediaMetricsService()
: mMaxRecords(kMaxRecords),
mMaxRecordAgeNs(kMaxRecordAgeNs),
@@ -112,14 +131,19 @@
break;
}
- // Overwrite package name and version if the caller was untrusted.
- if (!isTrusted) {
- mUidInfo.setPkgInfo(item, item->getUid(), true, true);
- } else if (item->getPkgName().empty()) {
- // empty, so fill out both parts
- mUidInfo.setPkgInfo(item, item->getUid(), true, true);
- } else {
- // trusted, provided a package, do nothing
+ // Overwrite package name and version if the caller was untrusted or empty
+ if (!isTrusted || item->getPkgName().empty()) {
+ const uid_t uid = item->getUid();
+ mediautils::UidInfo::Info info = mUidInfo.getInfo(uid);
+ if (useUidForPackage(info.package, info.installer)) {
+ // remove uid information of unknown installed packages.
+ // TODO: perhaps this can be done just before uploading to Westworld.
+ item->setPkgName(std::to_string(uid));
+ item->setPkgVersionCode(0);
+ } else {
+ item->setPkgName(info.package);
+ item->setPkgVersionCode(info.versionCode);
+ }
}
ALOGV("%s: given uid %d; sanitized uid: %d sanitized pkg: %s "
@@ -450,150 +474,4 @@
return false;
}
-// How long we hold package info before we re-fetch it
-constexpr nsecs_t PKG_EXPIRATION_NS = 30 * 60 * NANOS_PER_SECOND; // 30 minutes
-
-// give me the package name, perhaps going to find it
-// manages its own mutex operations internally
-void MediaMetricsService::UidInfo::setPkgInfo(
- mediametrics::Item *item, uid_t uid, bool setName, bool setVersion)
-{
- ALOGV("%s: uid=%d", __func__, uid);
-
- if (!setName && !setVersion) {
- return; // setting nothing? strange
- }
-
- const nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
- struct UidToPkgInfo mapping;
- {
- std::lock_guard _l(mUidInfoLock);
- auto it = mPkgMappings.find(uid);
- if (it != mPkgMappings.end()) {
- mapping = it->second;
- ALOGV("%s: uid %d expiration %lld now %lld",
- __func__, uid, (long long)mapping.expiration, (long long)now);
- if (mapping.expiration <= now) {
- // purge the stale entry and fall into re-fetching
- ALOGV("%s: entry for uid %d expired, now %lld",
- __func__, uid, (long long)now);
- mPkgMappings.erase(it);
- mapping.uid = (uid_t)-1; // this is always fully overwritten
- }
- }
- }
-
- // if we did not find it
- if (mapping.uid == (uid_t)(-1)) {
- std::string pkg;
- std::string installer;
- int64_t versionCode = 0;
-
- const struct passwd *pw = getpwuid(uid);
- if (pw) {
- pkg = pw->pw_name;
- }
-
- sp<IServiceManager> sm = defaultServiceManager();
- sp<content::pm::IPackageManagerNative> package_mgr;
- if (sm.get() == nullptr) {
- ALOGE("%s: Cannot find service manager", __func__);
- } else {
- sp<IBinder> binder = sm->getService(String16("package_native"));
- if (binder.get() == nullptr) {
- ALOGE("%s: Cannot find package_native", __func__);
- } else {
- package_mgr = interface_cast<content::pm::IPackageManagerNative>(binder);
- }
- }
-
- if (package_mgr != nullptr) {
- std::vector<int> uids;
- std::vector<std::string> names;
- uids.push_back(uid);
- binder::Status status = package_mgr->getNamesForUids(uids, &names);
- if (!status.isOk()) {
- ALOGE("%s: getNamesForUids failed: %s",
- __func__, status.exceptionMessage().c_str());
- } else {
- if (!names[0].empty()) {
- pkg = names[0].c_str();
- }
- }
- }
-
- // strip any leading "shared:" strings that came back
- if (pkg.compare(0, 7, "shared:") == 0) {
- pkg.erase(0, 7);
- }
- // determine how pkg was installed and the versionCode
- if (pkg.empty()) {
- pkg = std::to_string(uid); // no name for us to manage
- } else if (strchr(pkg.c_str(), '.') == NULL) {
- // not of form 'com.whatever...'; assume internal and ok
- } else if (strncmp(pkg.c_str(), "android.", 8) == 0) {
- // android.* packages are assumed fine
- } else if (package_mgr.get() != nullptr) {
- String16 pkgName16(pkg.c_str());
- binder::Status status = package_mgr->getInstallerForPackage(pkgName16, &installer);
- if (!status.isOk()) {
- ALOGE("%s: getInstallerForPackage failed: %s",
- __func__, status.exceptionMessage().c_str());
- }
-
- // skip if we didn't get an installer
- if (status.isOk()) {
- status = package_mgr->getVersionCodeForPackage(pkgName16, &versionCode);
- if (!status.isOk()) {
- ALOGE("%s: getVersionCodeForPackage failed: %s",
- __func__, status.exceptionMessage().c_str());
- }
- }
-
- ALOGV("%s: package '%s' installed by '%s' versioncode %lld",
- __func__, pkg.c_str(), installer.c_str(), (long long)versionCode);
-
- if (strncmp(installer.c_str(), "com.android.", 12) == 0) {
- // from play store, we keep info
- } else if (strncmp(installer.c_str(), "com.google.", 11) == 0) {
- // some google source, we keep info
- } else if (strcmp(installer.c_str(), "preload") == 0) {
- // preloads, we keep the info
- } else if (installer.c_str()[0] == '\0') {
- // sideload (no installer); report UID only
- pkg = std::to_string(uid);
- versionCode = 0;
- } else {
- // unknown installer; report UID only
- pkg = std::to_string(uid);
- versionCode = 0;
- }
- } else {
- // unvalidated by package_mgr just send uid.
- pkg = std::to_string(uid);
- }
-
- // add it to the map, to save a subsequent lookup
- std::lock_guard _l(mUidInfoLock);
- // always overwrite
- mapping.uid = uid;
- mapping.pkg = std::move(pkg);
- mapping.installer = std::move(installer);
- mapping.versionCode = versionCode;
- mapping.expiration = now + PKG_EXPIRATION_NS;
- ALOGV("%s: adding uid %d pkg '%s' expiration: %lld",
- __func__, uid, mapping.pkg.c_str(), (long long)mapping.expiration);
- mPkgMappings[uid] = mapping;
- }
-
- if (mapping.uid != (uid_t)(-1)) {
- if (setName) {
- item->setPkgName(mapping.pkg);
- }
- if (setVersion) {
- item->setPkgVersionCode(mapping.versionCode);
- }
- }
-}
-
} // namespace android
diff --git a/services/mediametrics/MediaMetricsService.h b/services/mediametrics/MediaMetricsService.h
index b736c30..74a114a 100644
--- a/services/mediametrics/MediaMetricsService.h
+++ b/services/mediametrics/MediaMetricsService.h
@@ -24,6 +24,7 @@
// IMediaMetricsService must include Vector, String16, Errors
#include <media/IMediaMetricsService.h>
+#include <mediautils/ServiceUtilities.h>
#include <utils/String8.h>
#include "AudioAnalytics.h"
@@ -62,6 +63,11 @@
*/
static nsecs_t roundTime(nsecs_t timeNs);
+ /**
+ * Returns true if we should use uid for package name when uploading to WestWorld.
+ */
+ static bool useUidForPackage(const std::string& package, const std::string& installer);
+
protected:
// Internal call where release is true if ownership of item is transferred
@@ -96,27 +102,10 @@
const size_t mMaxRecordsExpiredAtOnce;
const int mDumpProtoDefault;
- class UidInfo {
- public:
- void setPkgInfo(mediametrics::Item *item, uid_t uid, bool setName, bool setVersion);
-
- private:
- std::mutex mUidInfoLock;
-
- struct UidToPkgInfo {
- uid_t uid = -1;
- std::string pkg;
- std::string installer;
- int64_t versionCode = 0;
- nsecs_t expiration = 0; // TODO: remove expiration.
- };
-
- // TODO: use concurrent hashmap with striped lock.
- std::unordered_map<uid_t, struct UidToPkgInfo> mPkgMappings; // GUARDED_BY(mUidInfoLock)
- } mUidInfo; // mUidInfo can be accessed without lock (locked internally)
-
std::atomic<int64_t> mItemsSubmitted{}; // accessed outside of lock.
+ mediautils::UidInfo mUidInfo; // mUidInfo can be accessed without lock (locked internally)
+
mediametrics::AudioAnalytics mAudioAnalytics;
std::mutex mLock;
diff --git a/services/mediametrics/tests/Android.bp b/services/mediametrics/tests/Android.bp
index 9eb2d89..bdeda30 100644
--- a/services/mediametrics/tests/Android.bp
+++ b/services/mediametrics/tests/Android.bp
@@ -17,6 +17,7 @@
"liblog",
"libmediametrics",
"libmediametricsservice",
+ "libmediautils",
"libutils",
],
diff --git a/services/mediametrics/tests/mediametrics_tests.cpp b/services/mediametrics/tests/mediametrics_tests.cpp
index ccf2d63..90a8565 100644
--- a/services/mediametrics/tests/mediametrics_tests.cpp
+++ b/services/mediametrics/tests/mediametrics_tests.cpp
@@ -89,6 +89,32 @@
mediaMetrics->dump(fileno(stdout), {} /* args */);
}
+TEST(mediametrics_tests, package_installer_check) {
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "abcd", "installer")); // ok, package name has no dot.
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "android.com", "installer")); // ok, package name starts with android
+
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "abc.def", "com.android.foo")); // ok, installer name starts with com.android
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "123.456", "com.google.bar")); // ok, installer name starts with com.google
+ ASSERT_EQ(false, MediaMetricsService::useUidForPackage(
+ "r2.d2", "preload")); // ok, installer name is preload
+
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "abc.def", "installer")); // unknown installer
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "123.456", "installer")); // unknown installer
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "r2.d2", "preload23")); // unknown installer
+
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "com.android.foo", "abc.def")); // unknown installer
+ ASSERT_EQ(true, MediaMetricsService::useUidForPackage(
+ "com.google.bar", "123.456")); // unknown installer
+}
+
TEST(mediametrics_tests, item_manipulation) {
mediametrics::Item item("audiorecord");