Merge "audioflinger: volume control to HAL for VoIP streams" into oc-mr1-dev
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 47a147e..30a31e6 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -59,6 +59,7 @@
 MediaAnalyticsItem::MediaAnalyticsItem()
     : mPid(-1),
       mUid(-1),
+      mPkgVersionCode(0),
       mSessionID(MediaAnalyticsItem::SessionIDNone),
       mTimestamp(0),
       mFinalized(0),
@@ -70,6 +71,7 @@
 MediaAnalyticsItem::MediaAnalyticsItem(MediaAnalyticsItem::Key key)
     : mPid(-1),
       mUid(-1),
+      mPkgVersionCode(0),
       mSessionID(MediaAnalyticsItem::SessionIDNone),
       mTimestamp(0),
       mFinalized(0),
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index abacf13..759e42d 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -78,6 +78,8 @@
 static const char *kCodecLevel = "android.media.mediacodec.level";  /* 0..n */
 static const char *kCodecMaxWidth = "android.media.mediacodec.maxwidth";  /* 0..n */
 static const char *kCodecMaxHeight = "android.media.mediacodec.maxheight";  /* 0..n */
+static const char *kCodecError = "android.media.mediacodec.errcode";
+static const char *kCodecErrorState = "android.media.mediacodec.errstate";
 
 
 static int64_t getId(const sp<IResourceManagerClient> &client) {
@@ -465,6 +467,7 @@
       mFlags(0),
       mStickyError(OK),
       mSoftRenderer(NULL),
+      mAnalyticsItem(NULL),
       mResourceManagerClient(new ResourceManagerClient(this)),
       mResourceManagerService(new ResourceManagerServiceProxy(pid)),
       mBatteryStatNotified(false),
@@ -483,6 +486,18 @@
     } else {
         mUid = uid;
     }
+    initAnalyticsItem();
+}
+
+MediaCodec::~MediaCodec() {
+    CHECK_EQ(mState, UNINITIALIZED);
+    mResourceManagerService->removeResource(getId(mResourceManagerClient));
+
+    flushAnalyticsItem();
+}
+
+void MediaCodec::initAnalyticsItem() {
+    CHECK(mAnalyticsItem == NULL);
     // set up our new record, get a sessionID, put it into the in-progress list
     mAnalyticsItem = new MediaAnalyticsItem(kCodecKeyName);
     if (mAnalyticsItem != NULL) {
@@ -492,11 +507,9 @@
     }
 }
 
-MediaCodec::~MediaCodec() {
-    CHECK_EQ(mState, UNINITIALIZED);
-    mResourceManagerService->removeResource(getId(mResourceManagerClient));
-
-    if (mAnalyticsItem != NULL ) {
+void MediaCodec::flushAnalyticsItem() {
+    if (mAnalyticsItem != NULL) {
+        // don't log empty records
         if (mAnalyticsItem->count() > 0) {
             mAnalyticsItem->setFinalized(true);
             mAnalyticsItem->selfrecord();
@@ -1425,6 +1438,12 @@
 
                         case CONFIGURING:
                         {
+                            if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+                            }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : INITIALIZED);
                             break;
@@ -1432,6 +1451,12 @@
 
                         case STARTING:
                         {
+                            if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+                            }
                             setState(actionCode == ACTION_CODE_FATAL ?
                                     UNINITIALIZED : CONFIGURED);
                             break;
@@ -1468,6 +1493,11 @@
                         case FLUSHING:
                         {
                             if (actionCode == ACTION_CODE_FATAL) {
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
+
                                 setState(UNINITIALIZED);
                             } else {
                                 setState(
@@ -1496,6 +1526,10 @@
                                 setState(INITIALIZED);
                                 break;
                             default:
+                                mAnalyticsItem->setInt32(kCodecError, err);
+                                mAnalyticsItem->setInt32(kCodecErrorState, mState);
+                                flushAnalyticsItem();
+                                initAnalyticsItem();
                                 setState(UNINITIALIZED);
                                 break;
                             }
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index 836534d..1030407 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -314,6 +314,8 @@
     SoftwareRenderer *mSoftRenderer;
 
     MediaAnalyticsItem *mAnalyticsItem;
+    void initAnalyticsItem();
+    void flushAnalyticsItem();
 
     sp<AMessage> mOutputFormat;
     sp<AMessage> mInputFormat;
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 2443301..c7f9270 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -222,6 +222,8 @@
 
     // we control these, generally not trusting user input
     nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    // round nsecs to seconds
+    now = ((now + 500000000) / 1000000000) * 1000000000;
     item->setTimestamp(now);
     int pid = IPCThreadState::self()->getCallingPid();
     int uid = IPCThreadState::self()->getCallingUid();
@@ -257,14 +259,15 @@
             break;
     }
 
+
     // Overwrite package name and version if the caller was untrusted.
     if (!isTrusted) {
-      item->setPkgName(getPkgName(item->getUid(), true));
-      item->setPkgVersionCode(0);
+      setPkgInfo(item, item->getUid(), true, true);
     } else if (item->getPkgName().empty()) {
-      // Only overwrite the package name if it was empty. Trust whatever
-      // version code was provided by the trusted caller.
-      item->setPkgName(getPkgName(uid, true));
+      // empty, so fill out both parts
+      setPkgInfo(item, item->getUid(), true, true);
+    } else {
+      // trusted, provided a package, do nothing
     }
 
     ALOGV("given uid %d; sanitized uid: %d sanitized pkg: %s "
@@ -800,85 +803,155 @@
 
 }
 
-// mapping uids to package names
+// how long we hold package info before we re-fetch it
+#define PKG_EXPIRATION_NS (30*60*1000000000ll)   // 30 minutes, in nsecs
 
 // give me the package name, perhaps going to find it
-AString MediaAnalyticsService::getPkgName(uid_t uid, bool addIfMissing) {
+void MediaAnalyticsService::setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion) {
+    ALOGV("asking for packagename to go with uid=%d", uid);
+
+    if (!setName && !setVersion) {
+        // setting nothing? strange
+        return;
+    }
+
+    nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
+    struct UidToPkgMap mapping;
+    mapping.uid = (-1);
+
     ssize_t i = mPkgMappings.indexOfKey(uid);
     if (i >= 0) {
-        AString pkg = mPkgMappings.valueAt(i);
-        ALOGV("returning pkg '%s' for uid %d", pkg.c_str(), uid);
-        return pkg;
-    }
-
-    AString pkg;
-
-    if (addIfMissing == false) {
-        return pkg;
-    }
-
-    struct passwd *pw = getpwuid(uid);
-    if (pw) {
-        pkg = pw->pw_name;
-    } else {
-        pkg = "-";
-    }
-
-    // find the proper value
-
-    sp<IBinder> binder = NULL;
-    sp<IServiceManager> sm = defaultServiceManager();
-    if (sm == NULL) {
-        ALOGE("defaultServiceManager failed");
-    } else {
-        binder = sm->getService(String16("package_native"));
-        if (binder == NULL) {
-            ALOGE("getService package_native failed");
+        mapping = mPkgMappings.valueAt(i);
+        ALOGV("Expiration? uid %d expiration %" PRId64 " now %" PRId64,
+              uid, mapping.expiration, now);
+        if (mapping.expiration < now) {
+            // purge our current entry and re-query
+            ALOGV("entry for uid %d expired, now= %" PRId64 "", uid, now);
+            mPkgMappings.removeItemsAt(i, 1);
+            // could cheat and use a goto back to the top of the routine.
+            // a good compiler should recognize the local tail recursion...
+            return setPkgInfo(item, uid, setName, setVersion);
         }
-    }
+    } else {
+        AString pkg;
+        std::string installer = "";
+        int32_t versionCode = 0;
 
-    if (binder != NULL) {
-        sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+        struct passwd *pw = getpwuid(uid);
+        if (pw) {
+            pkg = pw->pw_name;
+        }
 
-        std::vector<int> uids;
-        std::vector<std::string> names;
+        // find the proper value -- should we cache this binder??
 
-        uids.push_back(uid);
-
-        binder::Status status = package_mgr->getNamesForUids(uids, &names);
-        if (!status.isOk()) {
-            ALOGE("package_native::getNamesForUids failed: %s",
-                  status.exceptionMessage().c_str());
+        sp<IBinder> binder = NULL;
+        sp<IServiceManager> sm = defaultServiceManager();
+        if (sm == NULL) {
+            ALOGE("defaultServiceManager failed");
         } else {
-            if (!names[0].empty()) {
-                pkg = names[0].c_str();
+            binder = sm->getService(String16("package_native"));
+            if (binder == NULL) {
+                ALOGE("getService package_native failed");
+            }
+        }
+
+        if (binder != NULL) {
+            sp<IPackageManagerNative> package_mgr = interface_cast<IPackageManagerNative>(binder);
+            binder::Status status;
+
+            std::vector<int> uids;
+            std::vector<std::string> names;
+
+            uids.push_back(uid);
+
+            status = package_mgr->getNamesForUids(uids, &names);
+            if (!status.isOk()) {
+                ALOGE("package_native::getNamesForUids failed: %s",
+                      status.exceptionMessage().c_str());
+            } else {
+                if (!names[0].empty()) {
+                    pkg = names[0].c_str();
+                }
+            }
+
+            // strip any leading "shared:" strings that came back
+            if (pkg.startsWith("shared:")) {
+                pkg.erase(0, 7);
+            }
+
+            // determine how pkg was installed and the versionCode
+            //
+            if (pkg.empty()) {
+                // 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 {
+                String16 pkgName16(pkg.c_str());
+                status = package_mgr->getInstallerForPackage(pkgName16, &installer);
+                if (!status.isOk()) {
+                    ALOGE("package_native::getInstallerForPackage failed: %s",
+                          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("package_native::getVersionCodeForPackage failed: %s",
+                          status.exceptionMessage().c_str());
+                    }
+                }
+
+
+                ALOGV("package '%s' installed by '%s' versioncode %d / %08x",
+                      pkg.c_str(), installer.c_str(), versionCode, 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); do not report
+                        pkg = "";
+                        versionCode = 0;
+                } else {
+                        // unknown installer; do not report
+                        pkg = "";
+                        versionCode = 0;
+                }
+            }
+        }
+
+        // add it to the map, to save a subsequent lookup
+        if (!pkg.empty()) {
+            Mutex::Autolock _l(mLock_mappings);
+            ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
+            ssize_t i = mPkgMappings.indexOfKey(uid);
+            if (i < 0) {
+                mapping.uid = uid;
+                mapping.pkg = pkg;
+                mapping.installer = installer.c_str();
+                mapping.versionCode = versionCode;
+                mapping.expiration = now + PKG_EXPIRATION_NS;
+                ALOGV("expiration for uid %d set to %" PRId64 "", uid, mapping.expiration);
+
+                mPkgMappings.add(uid, mapping);
             }
         }
     }
 
-    // XXX determine whether package was side-loaded or from playstore.
-    // for privacy, we only list apps loaded from playstore.
-
-    // Sanitize the package name for ":"
-    // as an example, we get "shared:android.uid.systemui"
-    // replace : with something benign (I'm going to use !)
-    if (!pkg.empty()) {
-        int n = pkg.size();
-        char *p = (char *) pkg.c_str();
-        for (int i = 0 ; i < n; i++) {
-            if (p[i] == ':') {
-                p[i] = '!';
-            }
+    if (mapping.uid != (uid_t)(-1)) {
+        if (setName) {
+            item->setPkgName(mapping.pkg);
+        }
+        if (setVersion) {
+            item->setPkgVersionCode(mapping.versionCode);
         }
     }
-
-    // add it to the map, to save a subsequent lookup
-    if (!pkg.empty()) {
-        ALOGV("Adding uid %d pkg '%s'", uid, pkg.c_str());
-        mPkgMappings.add(uid, pkg);
-    }
-
-    return pkg;
 }
 
 } // namespace android
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index 4fe2fb2..52e4631 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -62,6 +62,7 @@
     // partitioned a bit so we don't over serialize
     mutable Mutex           mLock;
     mutable Mutex           mLock_ids;
+    mutable Mutex           mLock_mappings;
 
     // limit how many records we'll retain
     // by count (in each queue (open, finalized))
@@ -135,10 +136,13 @@
     struct UidToPkgMap {
         uid_t uid;
         AString pkg;
+        AString installer;
+        int32_t versionCode;
+        nsecs_t expiration;
     };
 
-    KeyedVector<uid_t,AString>  mPkgMappings;
-    AString getPkgName(uid_t uid, bool addIfMissing);
+    KeyedVector<uid_t,struct UidToPkgMap>  mPkgMappings;
+    void setPkgInfo(MediaAnalyticsItem *item, uid_t uid, bool setName, bool setVersion);
 
 };
 
diff --git a/services/mediaanalytics/MetricsSummarizerCodec.cpp b/services/mediaanalytics/MetricsSummarizerCodec.cpp
index 921dd63..6af3c9a 100644
--- a/services/mediaanalytics/MetricsSummarizerCodec.cpp
+++ b/services/mediaanalytics/MetricsSummarizerCodec.cpp
@@ -36,31 +36,10 @@
 
 namespace android {
 
-static const char *codec_ignorable[] = {
-    "android.media.mediacodec.bytesin",
-    0
-};
-
 MetricsSummarizerCodec::MetricsSummarizerCodec(const char *key)
     : MetricsSummarizer(key)
 {
     ALOGV("MetricsSummarizerCodec::MetricsSummarizerCodec");
-    setIgnorables(codec_ignorable);
-
 }
 
-void MetricsSummarizerCodec::mergeRecord(MediaAnalyticsItem &summation, MediaAnalyticsItem &item) {
-
-    ALOGV("MetricsSummarizerCodec::mergeRecord()");
-
-    int64_t bytesin = 0;
-    if (item.getInt64("android.media.mediacodec.bytesin", &bytesin)) {
-        ALOGV("found bytesin of %" PRId64, bytesin);
-    }
-    if (bytesin >= 0) {
-        minMaxVar64(summation,"android.media.mediacodec.bytesin", bytesin);
-    }
-}
-
-
 } // namespace android
diff --git a/services/mediaanalytics/MetricsSummarizerCodec.h b/services/mediaanalytics/MetricsSummarizerCodec.h
index 872a16c..c01196f 100644
--- a/services/mediaanalytics/MetricsSummarizerCodec.h
+++ b/services/mediaanalytics/MetricsSummarizerCodec.h
@@ -38,8 +38,6 @@
     MetricsSummarizerCodec(const char *key);
     virtual ~MetricsSummarizerCodec() {};
 
-    virtual void mergeRecord(MediaAnalyticsItem &have, MediaAnalyticsItem &incoming);
-
 };
 
 // ----------------------------------------------------------------------------