Merge "add media.metrics tracking of fatal codec errors" 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/OmxInfoBuilder.cpp b/media/libstagefright/OmxInfoBuilder.cpp
index 686bcc8..8717a79 100644
--- a/media/libstagefright/OmxInfoBuilder.cpp
+++ b/media/libstagefright/OmxInfoBuilder.cpp
@@ -61,9 +61,9 @@
     }
     for (const auto& attribute : node.attributes) {
         // All features have an int32 value except
-        // "feature-bitrate-control", which has a string value.
+        // "feature-bitrate-modes", which has a string value.
         if ((attribute.key.compare(0, 8, "feature-") == 0) &&
-                (attribute.key.compare(8, 15, "bitrate-control")
+                (attribute.key.compare(8, 15, "bitrate-modes")
                  != 0)) {
             // If this attribute.key is a feature that is not a bitrate
             // control, add an int32 value.
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index f1cdea3..7ec3ccb 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -77,7 +77,8 @@
     android.hardware.camera.common@1.0 \
     android.hardware.camera.provider@2.4 \
     android.hardware.camera.device@1.0 \
-    android.hardware.camera.device@3.2
+    android.hardware.camera.device@3.2 \
+    android.hardware.camera.device@3.3
 
 LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := libbinder libcamera_client libfmq
 
diff --git a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
index b6f443a..73dca73 100644
--- a/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp
@@ -324,7 +324,7 @@
             streamInfo.width != (uint32_t)params.videoWidth ||
             streamInfo.height != (uint32_t)params.videoHeight ||
             !streamInfo.matchFormat((uint32_t)params.videoFormat) ||
-            streamInfo.dataSpace != params.videoDataSpace) {
+            !streamInfo.matchDataSpace(params.videoDataSpace)) {
         *needsUpdate = true;
         return res;
     }
@@ -356,7 +356,7 @@
         if (streamInfo.width != (uint32_t)params.videoWidth ||
                 streamInfo.height != (uint32_t)params.videoHeight ||
                 !streamInfo.matchFormat((uint32_t)params.videoFormat) ||
-                streamInfo.dataSpace != params.videoDataSpace) {
+                !streamInfo.matchDataSpace(params.videoDataSpace)) {
             // TODO: Should wait to be sure previous recording has finished
             res = device->deleteStream(mRecordingStreamId);
 
diff --git a/services/camera/libcameraservice/common/CameraDeviceBase.h b/services/camera/libcameraservice/common/CameraDeviceBase.h
index fe4c8d7..3919bfa 100644
--- a/services/camera/libcameraservice/common/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/common/CameraDeviceBase.h
@@ -145,23 +145,42 @@
     struct StreamInfo {
         uint32_t width;
         uint32_t height;
+
         uint32_t format;
         bool formatOverridden;
         uint32_t originalFormat;
+
         android_dataspace dataSpace;
+        bool dataSpaceOverridden;
+        android_dataspace originalDataSpace;
+
         StreamInfo() : width(0), height(0), format(0), formatOverridden(false), originalFormat(0),
-                dataSpace(HAL_DATASPACE_UNKNOWN) {}
+                dataSpace(HAL_DATASPACE_UNKNOWN), dataSpaceOverridden(false),
+                originalDataSpace(HAL_DATASPACE_UNKNOWN) {}
         /**
          * Check whether the format matches the current or the original one in case
          * it got overridden.
          */
-        bool matchFormat(uint32_t clientFormat) {
+        bool matchFormat(uint32_t clientFormat) const {
             if ((formatOverridden && (originalFormat == clientFormat)) ||
                     (format == clientFormat)) {
                 return true;
             }
             return false;
         }
+
+        /**
+         * Check whether the dataspace matches the current or the original one in case
+         * it got overridden.
+         */
+        bool matchDataSpace(android_dataspace clientDataSpace) const {
+            if ((dataSpaceOverridden && (originalDataSpace == clientDataSpace)) ||
+                    (dataSpace == clientDataSpace)) {
+                return true;
+            }
+            return false;
+        }
+
     };
 
     /**
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 669f763..ced1d3a 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -154,6 +154,15 @@
                 resultQueueRet.description().c_str());
         return DEAD_OBJECT;
     }
+    IF_ALOGV() {
+        session->interfaceChain([](
+            ::android::hardware::hidl_vec<::android::hardware::hidl_string> interfaceChain) {
+                ALOGV("Session interface chain:");
+                for (auto iface : interfaceChain) {
+                    ALOGV("  %s", iface.c_str());
+                }
+            });
+    }
 
     mInterface = new HalInterface(session, queue);
     std::string providerType;
@@ -460,6 +469,11 @@
     return static_cast<uint32_t>(pixelFormat);
 }
 
+android_dataspace Camera3Device::mapToFrameworkDataspace(
+        DataspaceFlags dataSpace) {
+    return static_cast<android_dataspace>(dataSpace);
+}
+
 uint64_t Camera3Device::mapConsumerToFrameworkUsage(
         BufferUsageFlags usage) {
     return usage;
@@ -1382,6 +1396,8 @@
     streamInfo->dataSpace = mOutputStreams[idx]->getDataSpace();
     streamInfo->formatOverridden = mOutputStreams[idx]->isFormatOverridden();
     streamInfo->originalFormat = mOutputStreams[idx]->getOriginalFormat();
+    streamInfo->dataSpaceOverridden = mOutputStreams[idx]->isDataSpaceOverridden();
+    streamInfo->originalDataSpace = mOutputStreams[idx]->getOriginalDataSpace();
     return OK;
 }
 
@@ -3196,17 +3212,51 @@
 
     // Invoke configureStreams
 
-    HalStreamConfiguration finalConfiguration;
+    device::V3_3::HalStreamConfiguration finalConfiguration;
     common::V1_0::Status status;
-    auto err = mHidlSession->configureStreams(requestedConfiguration,
+
+    // See if we have v3.3 HAL
+    sp<device::V3_3::ICameraDeviceSession> hidlSession_3_3;
+    auto castResult = device::V3_3::ICameraDeviceSession::castFrom(mHidlSession);
+    if (castResult.isOk()) {
+        hidlSession_3_3 = castResult;
+    } else {
+        ALOGE("%s: Transaction error when casting ICameraDeviceSession: %s", __FUNCTION__,
+                castResult.description().c_str());
+    }
+    if (hidlSession_3_3 != nullptr) {
+        // We do; use v3.3 for the call
+        ALOGV("%s: v3.3 device found", __FUNCTION__);
+        auto err = hidlSession_3_3->configureStreams_3_3(requestedConfiguration,
             [&status, &finalConfiguration]
-            (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+            (common::V1_0::Status s, const device::V3_3::HalStreamConfiguration& halConfiguration) {
                 finalConfiguration = halConfiguration;
                 status = s;
             });
-    if (!err.isOk()) {
-        ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
-        return DEAD_OBJECT;
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+            return DEAD_OBJECT;
+        }
+    } else {
+        // We don't; use v3.2 call and construct a v3.3 HalStreamConfiguration
+        ALOGV("%s: v3.2 device found", __FUNCTION__);
+        HalStreamConfiguration finalConfiguration_3_2;
+        auto err = mHidlSession->configureStreams(requestedConfiguration,
+                [&status, &finalConfiguration_3_2]
+                (common::V1_0::Status s, const HalStreamConfiguration& halConfiguration) {
+                    finalConfiguration_3_2 = halConfiguration;
+                    status = s;
+                });
+        if (!err.isOk()) {
+            ALOGE("%s: Transaction error: %s", __FUNCTION__, err.description().c_str());
+            return DEAD_OBJECT;
+        }
+        finalConfiguration.streams.resize(finalConfiguration_3_2.streams.size());
+        for (size_t i = 0; i < finalConfiguration_3_2.streams.size(); i++) {
+            finalConfiguration.streams[i].v3_2 = finalConfiguration_3_2.streams[i];
+            finalConfiguration.streams[i].overrideDataSpace =
+                    requestedConfiguration.streams[i].dataSpace;
+        }
     }
 
     if (status != common::V1_0::Status::OK ) {
@@ -3223,7 +3273,7 @@
         size_t realIdx = i;
         bool found = false;
         for (size_t idx = 0; idx < finalConfiguration.streams.size(); idx++) {
-            if (finalConfiguration.streams[realIdx].id == streamId) {
+            if (finalConfiguration.streams[realIdx].v3_2.id == streamId) {
                 found = true;
                 break;
             }
@@ -3234,42 +3284,51 @@
                     __FUNCTION__, streamId);
             return INVALID_OPERATION;
         }
-        HalStream &src = finalConfiguration.streams[realIdx];
+        device::V3_3::HalStream &src = finalConfiguration.streams[realIdx];
 
         Camera3Stream* dstStream = Camera3Stream::cast(dst);
         dstStream->setFormatOverride(false);
-        int overrideFormat = mapToFrameworkFormat(src.overrideFormat);
+        dstStream->setDataSpaceOverride(false);
+        int overrideFormat = mapToFrameworkFormat(src.v3_2.overrideFormat);
+        android_dataspace overrideDataSpace = mapToFrameworkDataspace(src.overrideDataSpace);
+
         if (dst->format != HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
             if (dst->format != overrideFormat) {
                 ALOGE("%s: Stream %d: Format override not allowed for format 0x%x", __FUNCTION__,
                         streamId, dst->format);
             }
+            if (dst->data_space != overrideDataSpace) {
+                ALOGE("%s: Stream %d: DataSpace override not allowed for format 0x%x", __FUNCTION__,
+                        streamId, dst->format);
+            }
         } else {
             dstStream->setFormatOverride((dst->format != overrideFormat) ? true : false);
-            dstStream->setOriginalFormat(dst->format);
+            dstStream->setDataSpaceOverride((dst->data_space != overrideDataSpace) ? true : false);
+
             // Override allowed with IMPLEMENTATION_DEFINED
             dst->format = overrideFormat;
+            dst->data_space = overrideDataSpace;
         }
 
         if (dst->stream_type == CAMERA3_STREAM_INPUT) {
-            if (src.producerUsage != 0) {
+            if (src.v3_2.producerUsage != 0) {
                 ALOGE("%s: Stream %d: INPUT streams must have 0 for producer usage",
                         __FUNCTION__, streamId);
                 return INVALID_OPERATION;
             }
-            Camera3Stream::cast(dst)->setUsage(
-                    mapConsumerToFrameworkUsage(src.consumerUsage));
+            dstStream->setUsage(
+                    mapConsumerToFrameworkUsage(src.v3_2.consumerUsage));
         } else {
             // OUTPUT
-            if (src.consumerUsage != 0) {
+            if (src.v3_2.consumerUsage != 0) {
                 ALOGE("%s: Stream %d: OUTPUT streams must have 0 for consumer usage",
                         __FUNCTION__, streamId);
                 return INVALID_OPERATION;
             }
-            Camera3Stream::cast(dst)->setUsage(
-                    mapProducerToFrameworkUsage(src.producerUsage));
+            dstStream->setUsage(
+                    mapProducerToFrameworkUsage(src.v3_2.producerUsage));
         }
-        dst->max_buffers = src.maxBuffers;
+        dst->max_buffers = src.v3_2.maxBuffers;
     }
 
     return res;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 298a3d8..fbbbd08 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -30,6 +30,7 @@
 
 #include <android/hardware/camera/device/3.2/ICameraDevice.h>
 #include <android/hardware/camera/device/3.2/ICameraDeviceSession.h>
+#include <android/hardware/camera/device/3.3/ICameraDeviceSession.h>
 #include <android/hardware/camera/device/3.2/ICameraDeviceCallback.h>
 #include <fmq/MessageQueue.h>
 #include <hardware/camera3.h>
@@ -595,6 +596,8 @@
             /*out*/ hardware::camera::device::V3_2::StreamConfigurationMode *mode);
     static camera3_buffer_status_t mapHidlBufferStatus(hardware::camera::device::V3_2::BufferStatus status);
     static int mapToFrameworkFormat(hardware::graphics::common::V1_0::PixelFormat pixelFormat);
+    static android_dataspace mapToFrameworkDataspace(
+            hardware::camera::device::V3_2::DataspaceFlags);
     static uint64_t mapConsumerToFrameworkUsage(
             hardware::camera::device::V3_2::BufferUsageFlags usage);
     static uint64_t mapProducerToFrameworkUsage(
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index c186208..fbe8f4f 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -116,18 +116,28 @@
 
 void Camera3Stream::setFormatOverride(bool formatOverridden) {
     mFormatOverridden = formatOverridden;
+    if (formatOverridden) mOriginalFormat = camera3_stream::format;
 }
 
-bool Camera3Stream::isFormatOverridden() {
+bool Camera3Stream::isFormatOverridden() const {
     return mFormatOverridden;
 }
 
-void Camera3Stream::setOriginalFormat(int originalFormat) {
-    mOriginalFormat = originalFormat;
+int Camera3Stream::getOriginalFormat() const {
+    return mOriginalFormat;
 }
 
-int Camera3Stream::getOriginalFormat() {
-    return mOriginalFormat;
+void Camera3Stream::setDataSpaceOverride(bool dataSpaceOverridden) {
+    mDataSpaceOverridden = dataSpaceOverridden;
+    if (dataSpaceOverridden) mOriginalDataSpace = camera3_stream::data_space;
+}
+
+bool Camera3Stream::isDataSpaceOverridden() const {
+    return mDataSpaceOverridden;
+}
+
+android_dataspace Camera3Stream::getOriginalDataSpace() const {
+    return mOriginalDataSpace;
 }
 
 camera3_stream* Camera3Stream::startConfiguration() {
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index 1843ae8..6e7912e 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -147,9 +147,11 @@
     uint64_t          getUsage() const;
     void              setUsage(uint64_t usage);
     void              setFormatOverride(bool formatOverriden);
-    bool              isFormatOverridden();
-    void              setOriginalFormat(int originalFormat);
-    int               getOriginalFormat();
+    bool              isFormatOverridden() const;
+    int               getOriginalFormat() const;
+    void              setDataSpaceOverride(bool dataSpaceOverriden);
+    bool              isDataSpaceOverridden() const;
+    android_dataspace getOriginalDataSpace() const;
 
     camera3_stream*   asHalStream() override {
         return this;
@@ -522,6 +524,11 @@
     //Keep track of original format in case it gets overridden
     bool mFormatOverridden;
     int mOriginalFormat;
+
+    //Keep track of original dataSpace in case it gets overridden
+    bool mDataSpaceOverridden;
+    android_dataspace mOriginalDataSpace;
+
 }; // class Camera3Stream
 
 }; // namespace camera3
diff --git a/services/camera/libcameraservice/device3/Camera3StreamInterface.h b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
index 63456c4..cc9bf8e 100644
--- a/services/camera/libcameraservice/device3/Camera3StreamInterface.h
+++ b/services/camera/libcameraservice/device3/Camera3StreamInterface.h
@@ -72,9 +72,11 @@
     virtual int      getFormat() const = 0;
     virtual android_dataspace getDataSpace() const = 0;
     virtual void setFormatOverride(bool formatOverriden) = 0;
-    virtual bool isFormatOverridden() = 0;
-    virtual void setOriginalFormat(int originalFormat) = 0;
-    virtual int getOriginalFormat() = 0;
+    virtual bool isFormatOverridden() const = 0;
+    virtual int getOriginalFormat() const = 0;
+    virtual void setDataSpaceOverride(bool dataSpaceOverriden) = 0;
+    virtual bool isDataSpaceOverridden() const = 0;
+    virtual android_dataspace getOriginalDataSpace() const = 0;
 
     /**
      * Get a HAL3 handle for the stream, without starting stream configuration.
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);
 
 };