Merge "Camera: don't hold memory map lock during callback" into oc-mr1-dev
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 398d923..ba4acc6 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -120,7 +120,7 @@
         }
         // No lock here: worst case we remove a NULL callback which will be a nop
         if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
         }
         IInterface::asBinder(mAudioRecord)->unlinkToDeath(mDeathNotifier, this);
         mAudioRecord.clear();
@@ -499,19 +499,26 @@
     return mSelectedDeviceId;
 }
 
+// must be called with mLock held
+void AudioRecord::updateRoutedDeviceId_l()
+{
+    // if the record is inactive, do not update actual device as the input stream maybe routed
+    // from a device not relevant to this client because of other active use cases.
+    if (!mActive) {
+        return;
+    }
+    if (mInput != AUDIO_IO_HANDLE_NONE) {
+        audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
+        if (deviceId != AUDIO_PORT_HANDLE_NONE) {
+            mRoutedDeviceId = deviceId;
+        }
+     }
+}
+
 audio_port_handle_t AudioRecord::getRoutedDeviceId() {
     AutoMutex lock(mLock);
-    if (mInput == AUDIO_IO_HANDLE_NONE) {
-        return AUDIO_PORT_HANDLE_NONE;
-    }
-    // if the input stream does not have an active audio patch, use either the device initially
-    // selected by audio policy manager or the last routed device
-    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mInput);
-    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
-        deviceId = mRoutedDeviceId;
-    }
-    mRoutedDeviceId = deviceId;
-    return deviceId;
+    updateRoutedDeviceId_l();
+    return mRoutedDeviceId;
 }
 
 // -------------------------------------------------------------------------
@@ -537,9 +544,6 @@
         return NO_INIT;
     }
 
-    if (mDeviceCallback != 0 && mInput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
-    }
     audio_io_handle_t input;
 
     // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
@@ -744,6 +748,15 @@
     }
     mNotificationFramesAct = (uint32_t) notificationFrames;
 
+
+    //mInput != input includes the case where mInput == AUDIO_IO_HANDLE_NONE for first creation
+    if (mDeviceCallback != 0 && mInput != input) {
+        if (mInput != AUDIO_IO_HANDLE_NONE) {
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
+        }
+        AudioSystem::addAudioDeviceCallback(this, input);
+    }
+
     // We retain a copy of the I/O handle, but don't own the reference
     mInput = input;
     mRefreshRemaining = true;
@@ -763,10 +776,6 @@
     mDeathNotifier = new DeathNotifier(this);
     IInterface::asBinder(mAudioRecord)->linkToDeath(mDeathNotifier, this);
 
-    if (mDeviceCallback != 0) {
-        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mInput);
-    }
-
     return NO_ERROR;
 
     // End of retry loop.
@@ -1238,7 +1247,7 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback == callback) {
+    if (mDeviceCallback.unsafe_get() == callback.get()) {
         ALOGW("%s adding same callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -1246,9 +1255,9 @@
     if (mInput != AUDIO_IO_HANDLE_NONE) {
         if (mDeviceCallback != 0) {
             ALOGW("%s callback already present!", __FUNCTION__);
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+            AudioSystem::removeAudioDeviceCallback(this, mInput);
         }
-        status = AudioSystem::addAudioDeviceCallback(callback, mInput);
+        status = AudioSystem::addAudioDeviceCallback(this, mInput);
     }
     mDeviceCallback = callback;
     return status;
@@ -1262,17 +1271,38 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback != callback) {
+    if (mDeviceCallback.unsafe_get() != callback.get()) {
         ALOGW("%s removing different callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
+    mDeviceCallback.clear();
     if (mInput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mInput);
+        AudioSystem::removeAudioDeviceCallback(this, mInput);
     }
-    mDeviceCallback = 0;
     return NO_ERROR;
 }
 
+void AudioRecord::onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                 audio_port_handle_t deviceId)
+{
+    sp<AudioSystem::AudioDeviceCallback> callback;
+    {
+        AutoMutex lock(mLock);
+        if (audioIo != mInput) {
+            return;
+        }
+        callback = mDeviceCallback.promote();
+        // only update device if the record is active as route changes due to other use cases are
+        // irrelevant for this client
+        if (mActive) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+    if (callback.get() != nullptr) {
+        callback->onAudioDeviceUpdate(mInput, mRoutedDeviceId);
+    }
+}
+
 // =========================================================================
 
 void AudioRecord::DeathNotifier::binderDied(const wp<IBinder>& who __unused)
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 211bd7d..cdc75ac 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -493,14 +493,16 @@
     if (ioDesc == 0 || ioDesc->mIoHandle == AUDIO_IO_HANDLE_NONE) return;
 
     audio_port_handle_t deviceId = AUDIO_PORT_HANDLE_NONE;
-    Vector < sp<AudioDeviceCallback> > callbacks;
+    Vector < wp<AudioDeviceCallback> > callbacks;
 
     {
         Mutex::Autolock _l(mLock);
 
         switch (event) {
         case AUDIO_OUTPUT_OPENED:
-        case AUDIO_INPUT_OPENED: {
+        case AUDIO_OUTPUT_REGISTERED:
+        case AUDIO_INPUT_OPENED:
+        case AUDIO_INPUT_REGISTERED: {
             sp<AudioIoDescriptor> oldDesc = getIoDescriptor_l(ioDesc->mIoHandle);
             if (oldDesc == 0) {
                 mIoDescriptors.add(ioDesc->mIoHandle, ioDesc);
@@ -511,13 +513,19 @@
 
             if (ioDesc->getDeviceId() != AUDIO_PORT_HANDLE_NONE) {
                 deviceId = ioDesc->getDeviceId();
-                ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
-                if (ioIndex >= 0) {
-                    callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                if (event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED) {
+                    ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(ioDesc->mIoHandle);
+                    if (ioIndex >= 0) {
+                        callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+                    }
                 }
             }
-            ALOGV("ioConfigChanged() new %s opened %d samplingRate %u, format %#x channel mask %#x "
-                    "frameCount %zu deviceId %d", event == AUDIO_OUTPUT_OPENED ? "output" : "input",
+            ALOGV("ioConfigChanged() new %s %s %d samplingRate %u, format %#x channel mask %#x "
+                    "frameCount %zu deviceId %d",
+                    event == AUDIO_OUTPUT_OPENED || event == AUDIO_OUTPUT_REGISTERED ?
+                            "output" : "input",
+                            event == AUDIO_OUTPUT_OPENED || event == AUDIO_INPUT_OPENED ?
+                            "opened" : "registered",
                     ioDesc->mIoHandle, ioDesc->mSamplingRate, ioDesc->mFormat, ioDesc->mChannelMask,
                     ioDesc->mFrameCount, ioDesc->getDeviceId());
             } break;
@@ -563,9 +571,23 @@
         } break;
         }
     }
+    bool callbackRemoved = false;
     // callbacks.size() != 0 =>  ioDesc->mIoHandle and deviceId are valid
-    for (size_t i = 0; i < callbacks.size(); i++) {
-        callbacks[i]->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
+    for (size_t i = 0; i < callbacks.size(); ) {
+        sp<AudioDeviceCallback> callback = callbacks[i].promote();
+        if (callback.get() != nullptr) {
+            callback->onAudioDeviceUpdate(ioDesc->mIoHandle, deviceId);
+            i++;
+        } else {
+            callbacks.removeAt(i);
+            callbackRemoved = true;
+        }
+    }
+    // clean up callback list while we are here if some clients have disappeared without
+    // unregistering their callback
+    if (callbackRemoved) {
+        Mutex::Autolock _l(mLock);
+        mAudioDeviceCallbacks.replaceValueFor(ioDesc->mIoHandle, callbacks);
     }
 }
 
@@ -618,17 +640,17 @@
 }
 
 status_t AudioSystem::AudioFlingerClient::addAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     Mutex::Autolock _l(mLock);
-    Vector < sp<AudioDeviceCallback> > callbacks;
+    Vector < wp<AudioDeviceCallback> > callbacks;
     ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
     if (ioIndex >= 0) {
         callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
     }
 
     for (size_t cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
-        if (callbacks[cbIndex] == callback) {
+        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
             return INVALID_OPERATION;
         }
     }
@@ -639,18 +661,18 @@
 }
 
 status_t AudioSystem::AudioFlingerClient::removeAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     Mutex::Autolock _l(mLock);
     ssize_t ioIndex = mAudioDeviceCallbacks.indexOfKey(audioIo);
     if (ioIndex < 0) {
         return INVALID_OPERATION;
     }
-    Vector < sp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
+    Vector < wp<AudioDeviceCallback> > callbacks = mAudioDeviceCallbacks.valueAt(ioIndex);
 
     size_t cbIndex;
     for (cbIndex = 0; cbIndex < callbacks.size(); cbIndex++) {
-        if (callbacks[cbIndex] == callback) {
+        if (callbacks[cbIndex].unsafe_get() == callback.unsafe_get()) {
             break;
         }
     }
@@ -1128,7 +1150,7 @@
 }
 
 status_t AudioSystem::addAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     const sp<AudioFlingerClient> afc = getAudioFlingerClient();
     if (afc == 0) {
@@ -1145,7 +1167,7 @@
 }
 
 status_t AudioSystem::removeAudioDeviceCallback(
-        const sp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
+        const wp<AudioDeviceCallback>& callback, audio_io_handle_t audioIo)
 {
     const sp<AudioFlingerClient> afc = getAudioFlingerClient();
     if (afc == 0) {
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 31df414..3529d2c 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -276,7 +276,7 @@
         }
         // No lock here: worst case we remove a NULL callback which will be a nop
         if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
         }
         IInterface::asBinder(mAudioTrack)->unlinkToDeath(mDeathNotifier, this);
         mAudioTrack.clear();
@@ -1229,19 +1229,26 @@
     return mSelectedDeviceId;
 }
 
+// must be called with mLock held
+void AudioTrack::updateRoutedDeviceId_l()
+{
+    // if the track is inactive, do not update actual device as the output stream maybe routed
+    // to a device not relevant to this client because of other active use cases.
+    if (mState != STATE_ACTIVE) {
+        return;
+    }
+    if (mOutput != AUDIO_IO_HANDLE_NONE) {
+        audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
+        if (deviceId != AUDIO_PORT_HANDLE_NONE) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+}
+
 audio_port_handle_t AudioTrack::getRoutedDeviceId() {
     AutoMutex lock(mLock);
-    if (mOutput == AUDIO_IO_HANDLE_NONE) {
-        return AUDIO_PORT_HANDLE_NONE;
-    }
-    // if the output stream does not have an active audio patch, use either the device initially
-    // selected by audio policy manager or the last routed device
-    audio_port_handle_t deviceId = AudioSystem::getDeviceIdForIo(mOutput);
-    if (deviceId == AUDIO_PORT_HANDLE_NONE) {
-        deviceId = mRoutedDeviceId;
-    }
-    mRoutedDeviceId = deviceId;
-    return deviceId;
+    updateRoutedDeviceId_l();
+    return mRoutedDeviceId;
 }
 
 status_t AudioTrack::attachAuxEffect(int effectId)
@@ -1305,12 +1312,10 @@
         return NO_INIT;
     }
 
-    if (mDeviceCallback != 0 && mOutput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
-    }
     audio_io_handle_t output;
     audio_stream_type_t streamType = mStreamType;
     audio_attributes_t *attr = (mStreamType == AUDIO_STREAM_DEFAULT) ? &mAttributes : NULL;
+    bool callbackAdded = false;
 
     // mFlags (not mOrigFlags) is modified depending on whether fast request is accepted.
     // After fast request is denied, we will request again if IAudioTrack is re-created.
@@ -1515,12 +1520,14 @@
     sp<IMemory> iMem = track->getCblk();
     if (iMem == 0) {
         ALOGE("Could not get control block");
-        return NO_INIT;
+        status = NO_INIT;
+        goto release;
     }
     void *iMemPointer = iMem->pointer();
     if (iMemPointer == NULL) {
         ALOGE("Could not get control block pointer");
-        return NO_INIT;
+        status = NO_INIT;
+        goto release;
     }
     // invariant that mAudioTrack != 0 is true only after set() returns successfully
     if (mAudioTrack != 0) {
@@ -1582,6 +1589,15 @@
         }
     }
 
+    //mOutput != output includes the case where mOutput == AUDIO_IO_HANDLE_NONE for first creation
+    if (mDeviceCallback != 0 && mOutput != output) {
+        if (mOutput != AUDIO_IO_HANDLE_NONE) {
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
+        }
+        AudioSystem::addAudioDeviceCallback(this, output);
+        callbackAdded = true;
+    }
+
     // We retain a copy of the I/O handle, but don't own the reference
     mOutput = output;
     mRefreshRemaining = true;
@@ -1597,7 +1613,8 @@
         buffers = mSharedBuffer->pointer();
         if (buffers == NULL) {
             ALOGE("Could not get buffer pointer");
-            return NO_INIT;
+            status = NO_INIT;
+            goto release;
         }
     }
 
@@ -1642,15 +1659,15 @@
     mDeathNotifier = new DeathNotifier(this);
     IInterface::asBinder(mAudioTrack)->linkToDeath(mDeathNotifier, this);
 
-    if (mDeviceCallback != 0) {
-        AudioSystem::addAudioDeviceCallback(mDeviceCallback, mOutput);
-    }
-
     return NO_ERROR;
     }
 
 release:
     AudioSystem::releaseOutput(output, streamType, mSessionId);
+    if (callbackAdded) {
+        // note: mOutput is always valid is callbackAdded is true
+        AudioSystem::removeAudioDeviceCallback(this, mOutput);
+    }
     if (status == NO_ERROR) {
         status = NO_INIT;
     }
@@ -2851,7 +2868,7 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback == callback) {
+    if (mDeviceCallback.unsafe_get() == callback.get()) {
         ALOGW("%s adding same callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
@@ -2859,9 +2876,9 @@
     if (mOutput != AUDIO_IO_HANDLE_NONE) {
         if (mDeviceCallback != 0) {
             ALOGW("%s callback already present!", __FUNCTION__);
-            AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+            AudioSystem::removeAudioDeviceCallback(this, mOutput);
         }
-        status = AudioSystem::addAudioDeviceCallback(callback, mOutput);
+        status = AudioSystem::addAudioDeviceCallback(this, mOutput);
     }
     mDeviceCallback = callback;
     return status;
@@ -2875,17 +2892,39 @@
         return BAD_VALUE;
     }
     AutoMutex lock(mLock);
-    if (mDeviceCallback != callback) {
+    if (mDeviceCallback.unsafe_get() != callback.get()) {
         ALOGW("%s removing different callback!", __FUNCTION__);
         return INVALID_OPERATION;
     }
+    mDeviceCallback.clear();
     if (mOutput != AUDIO_IO_HANDLE_NONE) {
-        AudioSystem::removeAudioDeviceCallback(mDeviceCallback, mOutput);
+        AudioSystem::removeAudioDeviceCallback(this, mOutput);
     }
-    mDeviceCallback = 0;
     return NO_ERROR;
 }
 
+
+void AudioTrack::onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                 audio_port_handle_t deviceId)
+{
+    sp<AudioSystem::AudioDeviceCallback> callback;
+    {
+        AutoMutex lock(mLock);
+        if (audioIo != mOutput) {
+            return;
+        }
+        callback = mDeviceCallback.promote();
+        // only update device if the track is active as route changes due to other use cases are
+        // irrelevant for this client
+        if (mState == STATE_ACTIVE) {
+            mRoutedDeviceId = deviceId;
+        }
+    }
+    if (callback.get() != nullptr) {
+        callback->onAudioDeviceUpdate(mOutput, mRoutedDeviceId);
+    }
+}
+
 status_t AudioTrack::pendingDuration(int32_t *msec, ExtendedTimestamp::Location location)
 {
     if (msec == nullptr ||
diff --git a/media/libaudioclient/include/media/AudioIoDescriptor.h b/media/libaudioclient/include/media/AudioIoDescriptor.h
index fed86c9..859f1a9 100644
--- a/media/libaudioclient/include/media/AudioIoDescriptor.h
+++ b/media/libaudioclient/include/media/AudioIoDescriptor.h
@@ -20,9 +20,11 @@
 namespace android {
 
 enum audio_io_config_event {
+    AUDIO_OUTPUT_REGISTERED,
     AUDIO_OUTPUT_OPENED,
     AUDIO_OUTPUT_CLOSED,
     AUDIO_OUTPUT_CONFIG_CHANGED,
+    AUDIO_INPUT_REGISTERED,
     AUDIO_INPUT_OPENED,
     AUDIO_INPUT_CLOSED,
     AUDIO_INPUT_CONFIG_CHANGED,
diff --git a/media/libaudioclient/include/media/AudioRecord.h b/media/libaudioclient/include/media/AudioRecord.h
index e6a5efb..dd72170 100644
--- a/media/libaudioclient/include/media/AudioRecord.h
+++ b/media/libaudioclient/include/media/AudioRecord.h
@@ -33,7 +33,7 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioRecord : public RefBase
+class AudioRecord : public AudioSystem::AudioDeviceCallback
 {
 public:
 
@@ -424,7 +424,12 @@
 
      /* Returns the ID of the audio device actually used by the input to which this AudioRecord
       * is attached.
-      * A value of AUDIO_PORT_HANDLE_NONE indicates the AudioRecord is not attached to any input.
+      * The device ID is relevant only if the AudioRecord is active.
+      * When the AudioRecord is inactive, the device ID returned can be either:
+      * - AUDIO_PORT_HANDLE_NONE if the AudioRecord is not attached to any output.
+      * - The device ID used before paused or stopped.
+      * - The device ID selected by audio policy manager of setOutputDevice() if the AudioRecord
+      * has not been started yet.
       *
       * Parameters:
       *  none.
@@ -454,6 +459,10 @@
             status_t removeAudioDeviceCallback(
                     const sp<AudioSystem::AudioDeviceCallback>& callback);
 
+            // AudioSystem::AudioDeviceCallback> virtuals
+            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                             audio_port_handle_t deviceId);
+
 private:
     /* If nonContig is non-NULL, it is an output parameter that will be set to the number of
      * additional non-contiguous frames that are predicted to be available immediately,
@@ -561,6 +570,8 @@
             // FIXME enum is faster than strcmp() for parameter 'from'
             status_t restoreRecord_l(const char *from);
 
+            void     updateRoutedDeviceId_l();
+
     sp<AudioRecordThread>   mAudioRecordThread;
     mutable Mutex           mLock;
 
@@ -665,7 +676,7 @@
     audio_port_handle_t     mRoutedDeviceId;   // Device actually selected by audio policy manager:
                                               // May not match the app selection depending on other
                                               // activity and connected devices
-    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+    wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
     audio_port_handle_t    mPortId;  // unique ID allocated by audio policy
 
 };
diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 4d5b317..5a81d83 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -370,9 +370,9 @@
                                          audio_port_handle_t deviceId) = 0;
     };
 
-    static status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+    static status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                            audio_io_handle_t audioIo);
-    static status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+    static status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                               audio_io_handle_t audioIo);
 
     static audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@@ -403,9 +403,9 @@
                                      const sp<AudioIoDescriptor>& ioDesc);
 
 
-        status_t addAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+        status_t addAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                                audio_io_handle_t audioIo);
-        status_t removeAudioDeviceCallback(const sp<AudioDeviceCallback>& callback,
+        status_t removeAudioDeviceCallback(const wp<AudioDeviceCallback>& callback,
                                            audio_io_handle_t audioIo);
 
         audio_port_handle_t getDeviceIdForIo(audio_io_handle_t audioIo);
@@ -413,7 +413,7 @@
     private:
         Mutex                               mLock;
         DefaultKeyedVector<audio_io_handle_t, sp<AudioIoDescriptor> >   mIoDescriptors;
-        DefaultKeyedVector<audio_io_handle_t, Vector < sp<AudioDeviceCallback> > >
+        DefaultKeyedVector<audio_io_handle_t, Vector < wp<AudioDeviceCallback> > >
                                                                         mAudioDeviceCallbacks;
         // cached values for recording getInputBufferSize() queries
         size_t                              mInBuffSize;    // zero indicates cache is invalid
diff --git a/media/libaudioclient/include/media/AudioTrack.h b/media/libaudioclient/include/media/AudioTrack.h
index 7ae8ec5..47d87e9 100644
--- a/media/libaudioclient/include/media/AudioTrack.h
+++ b/media/libaudioclient/include/media/AudioTrack.h
@@ -35,7 +35,7 @@
 
 // ----------------------------------------------------------------------------
 
-class AudioTrack : public RefBase
+class AudioTrack : public AudioSystem::AudioDeviceCallback
 {
 public:
 
@@ -605,7 +605,11 @@
 
      /* Returns the ID of the audio device actually used by the output to which this AudioTrack is
       * attached.
-      * A value of AUDIO_PORT_HANDLE_NONE indicates the audio track is not attached to any output.
+      * When the AudioTrack is inactive, the device ID returned can be either:
+      * - AUDIO_PORT_HANDLE_NONE if the AudioTrack is not attached to any output.
+      * - The device ID used before paused or stopped.
+      * - The device ID selected by audio policy manager of setOutputDevice() if the AudioTrack
+      * has not been started yet.
       *
       * Parameters:
       *  none.
@@ -845,6 +849,12 @@
             status_t removeAudioDeviceCallback(
                     const sp<AudioSystem::AudioDeviceCallback>& callback);
 
+            // AudioSystem::AudioDeviceCallback> virtuals
+            virtual void onAudioDeviceUpdate(audio_io_handle_t audioIo,
+                                             audio_port_handle_t deviceId);
+
+
+
     /* Obtain the pending duration in milliseconds for playback of pure PCM
      * (mixable without embedded timing) data remaining in AudioTrack.
      *
@@ -974,6 +984,8 @@
 
             void     restartIfDisabled();
 
+            void     updateRoutedDeviceId_l();
+
     // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0
     sp<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
@@ -1165,7 +1177,7 @@
     uid_t                   mClientUid;
     pid_t                   mClientPid;
 
-    sp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
+    wp<AudioSystem::AudioDeviceCallback> mDeviceCallback;
     audio_port_handle_t     mPortId;  // unique ID allocated by audio policy
 };
 
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/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/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index c3d24c7..4ab1ab2 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -302,10 +302,27 @@
     while (!inQueue.empty() && !outQueue.empty()) {
         BufferInfo *inInfo = *inQueue.begin();
         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
+        BufferInfo *outInfo = *outQueue.begin();
+        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
         uint8_t* inBuffer = inHeader->pBuffer + inHeader->nOffset;
         uint32_t inBufferLength = inHeader->nFilledLen;
         bool endOfInput = (inHeader->nFlags & OMX_BUFFERFLAG_EOS) != 0;
 
+        if (inHeader->nFilledLen == 0) {
+            if (endOfInput) {
+                outHeader->nFilledLen = 0;
+                outHeader->nFlags = OMX_BUFFERFLAG_EOS;
+                outInfo->mOwnedByUs = false;
+                outQueue.erase(outQueue.begin());
+                notifyFillBufferDone(outHeader);
+            } else {
+                ALOGE("onQueueFilled: emptyInputBuffer received");
+            }
+            inInfo->mOwnedByUs = false;
+            inQueue.erase(inQueue.begin());
+            notifyEmptyBufferDone(inHeader);
+            return;
+        }
         if (mInputBufferCount == 0 && !(inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG)) {
             ALOGE("onQueueFilled: first buffer should have OMX_BUFFERFLAG_CODECCONFIG set");
             inHeader->nFlags |= OMX_BUFFERFLAG_CODECCONFIG;
@@ -343,8 +360,6 @@
             return;
         }
 
-        BufferInfo *outInfo = *outQueue.begin();
-        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
         short *outBuffer =
                 reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
         size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
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/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 6d28d1b..87b649a 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -53,21 +53,25 @@
 
 void
 AImage::close(int releaseFenceFd) {
+    lockReader();
     Mutex::Autolock _l(mLock);
     if (mIsClosed) {
         return;
     }
     sp<AImageReader> reader = mReader.promote();
-    if (reader == nullptr) {
-        LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
-        return;
+    if (reader != nullptr) {
+        reader->releaseImageLocked(this, releaseFenceFd);
+    } else if (mBuffer != nullptr) {
+        LOG_ALWAYS_FATAL("%s: parent AImageReader closed without releasing image %p",
+                __FUNCTION__, this);
     }
-    reader->releaseImageLocked(this, releaseFenceFd);
+
     // Should have been set to nullptr in releaseImageLocked
     // Set to nullptr here for extra safety only
     mBuffer = nullptr;
     mLockedBuffer = nullptr;
     mIsClosed = true;
+    unlockReader();
 }
 
 void
@@ -618,9 +622,7 @@
 void AImage_deleteAsync(AImage* image, int releaseFenceFd) {
     ALOGV("%s", __FUNCTION__);
     if (image != nullptr) {
-        image->lockReader();
         image->close(releaseFenceFd);
-        image->unlockReader();
         if (!image->isClosed()) {
             LOG_ALWAYS_FATAL("Image close failed!");
         }
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index a450dd3..e90783d 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -349,6 +349,7 @@
     for (auto it = mAcquiredImages.begin();
               it != mAcquiredImages.end(); it++) {
         AImage* image = *it;
+        releaseImageLocked(image, /*releaseFenceFd*/-1);
         image->close();
     }
 
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 13522f5..39f04fb 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -329,6 +329,11 @@
         thread->configure(attr, streamType, sessionId, callback, *deviceId, portId);
         *handle = portId;
     } else {
+        if (direction == MmapStreamInterface::DIRECTION_OUTPUT) {
+            AudioSystem::releaseOutput(io, streamType, sessionId);
+        } else {
+            AudioSystem::releaseInput(io, sessionId);
+        }
         ret = NO_INIT;
     }
 
@@ -1397,11 +1402,11 @@
     // the config change is always sent from playback or record threads to avoid deadlock
     // with AudioSystem::gLock
     for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
-        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_OPENED, pid);
+        mPlaybackThreads.valueAt(i)->sendIoConfigEvent(AUDIO_OUTPUT_REGISTERED, pid);
     }
 
     for (size_t i = 0; i < mRecordThreads.size(); i++) {
-        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_OPENED, pid);
+        mRecordThreads.valueAt(i)->sendIoConfigEvent(AUDIO_INPUT_REGISTERED, pid);
     }
 }
 
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 297608c..510d5db 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -1668,7 +1668,8 @@
         mScreenState(AudioFlinger::mScreenState),
         // index 0 is reserved for normal mixer's submix
         mFastTrackAvailMask(((1 << FastMixerState::sMaxFastTracks) - 1) & ~1),
-        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false)
+        mHwSupportsPause(false), mHwPaused(false), mFlushPending(false),
+        mLeftVolFloat(-1.0), mRightVolFloat(-1.0)
 {
     snprintf(mThreadName, kThreadNameLength, "AudioOut_%X", id);
     mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
@@ -2253,6 +2254,7 @@
 
     switch (event) {
     case AUDIO_OUTPUT_OPENED:
+    case AUDIO_OUTPUT_REGISTERED:
     case AUDIO_OUTPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
@@ -4294,6 +4296,7 @@
                     param = AudioMixer::RAMP_VOLUME;
                 }
                 mAudioMixer->setParameter(name, AudioMixer::RESAMPLE, AudioMixer::RESET, NULL);
+                mLeftVolFloat = -1.0;
             // FIXME should not make a decision based on mServer
             } else if (cblk->mServer != 0) {
                 // If the track is stopped before the first frame was mixed,
@@ -4304,6 +4307,10 @@
             // compute volume for this track
             uint32_t vl, vr;       // in U8.24 integer format
             float vlf, vrf, vaf;   // in [0.0, 1.0] float format
+            // read original volumes with volume control
+            float typeVolume = mStreamTypes[track->streamType()].volume;
+            float v = masterVolume * typeVolume;
+
             if (track->isPausing() || mStreamTypes[track->streamType()].mute) {
                 vl = vr = 0;
                 vlf = vrf = vaf = 0.;
@@ -4311,10 +4318,6 @@
                     track->setPaused();
                 }
             } else {
-
-                // read original volumes with volume control
-                float typeVolume = mStreamTypes[track->streamType()].volume;
-                float v = masterVolume * typeVolume;
                 sp<AudioTrackServerProxy> proxy = track->mAudioTrackServerProxy;
                 gain_minifloat_packed_t vlr = proxy->getVolumeLR();
                 vlf = float_from_gain(gain_minifloat_unpack_left(vlr));
@@ -4366,6 +4369,25 @@
                 track->mHasVolumeController = false;
             }
 
+            // For dedicated VoIP outputs, let the HAL apply the stream volume. Track volume is
+            // still applied by the mixer.
+            if ((mOutput->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) != 0) {
+                v = mStreamTypes[track->streamType()].mute ? 0.0f : v;
+                if (v != mLeftVolFloat) {
+                    status_t result = mOutput->stream->setVolume(v, v);
+                    ALOGE_IF(result != OK, "Error when setting output stream volume: %d", result);
+                    if (result == OK) {
+                        mLeftVolFloat = v;
+                    }
+                }
+                // if stream volume was successfully sent to the HAL, mLeftVolFloat == v here and we
+                // remove stream volume contribution from software volume.
+                if (v != 0.0f && mLeftVolFloat == v) {
+                   vlf = min(1.0f, vlf / v);
+                   vrf = min(1.0f, vrf / v);
+                   vaf = min(1.0f, vaf / v);
+               }
+            }
             // XXX: these things DON'T need to be done each time
             mAudioMixer->setBufferProvider(name, track);
             mAudioMixer->enable(name);
@@ -4807,7 +4829,6 @@
 AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger,
         AudioStreamOut* output, audio_io_handle_t id, audio_devices_t device, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, DIRECT, systemReady)
-        // mLeftVolFloat, mRightVolFloat
 {
 }
 
@@ -4815,7 +4836,6 @@
         AudioStreamOut* output, audio_io_handle_t id, uint32_t device,
         ThreadBase::type_t type, bool systemReady)
     :   PlaybackThread(audioFlinger, output, id, device, type, systemReady)
-        // mLeftVolFloat, mRightVolFloat
         , mVolumeShaperActive(false)
 {
 }
@@ -7242,6 +7262,7 @@
 
     switch (event) {
     case AUDIO_INPUT_OPENED:
+    case AUDIO_INPUT_REGISTERED:
     case AUDIO_INPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
@@ -7913,8 +7934,10 @@
 
     switch (event) {
     case AUDIO_INPUT_OPENED:
+    case AUDIO_INPUT_REGISTERED:
     case AUDIO_INPUT_CONFIG_CHANGED:
     case AUDIO_OUTPUT_OPENED:
+    case AUDIO_OUTPUT_REGISTERED:
     case AUDIO_OUTPUT_CONFIG_CHANGED:
         desc->mPatch = mPatch;
         desc->mChannelMask = mChannelMask;
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index 8d7bb1a..dd2b89b 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -999,6 +999,9 @@
                 bool        mHwSupportsPause;
                 bool        mHwPaused;
                 bool        mFlushPending;
+                // volumes last sent to audio HAL with stream->setVolume()
+                float mLeftVolFloat;
+                float mRightVolFloat;
 };
 
 class MixerThread : public PlaybackThread {
@@ -1116,9 +1119,6 @@
 
     virtual     void        onAddNewTrack_l();
 
-    // volumes last sent to audio HAL with stream->set_volume()
-    float mLeftVolFloat;
-    float mRightVolFloat;
     bool mVolumeShaperActive;
 
     DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index e6ee6c9..bdfaf2f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1499,62 +1499,13 @@
             "session %d, flags %#x",
           attr->source, config->sample_rate, config->format, config->channel_mask, session, flags);
 
-    // special case for mmap capture: if an input IO handle is specified, we reuse this input if
-    // possible
-    if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
-            *input != AUDIO_IO_HANDLE_NONE) {
-        ssize_t index = mInputs.indexOfKey(*input);
-        if (index < 0) {
-            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
-            return BAD_VALUE;
-        }
-        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
-        if (audioSession == 0) {
-            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
-            return BAD_VALUE;
-        }
-        // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
-        // The second call is for the first active client and sets the UID. Any further call
-        // corresponds to a new client and is only permitted from the same UId.
-        if (audioSession->openCount() == 1) {
-            audioSession->setUid(uid);
-        } else if (audioSession->uid() != uid) {
-            ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
-                  uid, session, audioSession->uid());
-            return INVALID_OPERATION;
-        }
-        audioSession->changeOpenCount(1);
-        *inputType = API_INPUT_LEGACY;
-        if (*portId == AUDIO_PORT_HANDLE_NONE) {
-            *portId = AudioPort::getNextUniqueId();
-        }
-        DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
-        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
-                : AUDIO_PORT_HANDLE_NONE;
-        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
-        return NO_ERROR;
-    }
-
-    *input = AUDIO_IO_HANDLE_NONE;
-    *inputType = API_INPUT_INVALID;
-
-    audio_devices_t device;
+    status_t status = NO_ERROR;
     // handle legacy remote submix case where the address was not always specified
     String8 address = String8("");
-    audio_source_t inputSource = attr->source;
     audio_source_t halInputSource;
+    audio_source_t inputSource = attr->source;
     AudioMix *policyMix = NULL;
-
-    if (inputSource == AUDIO_SOURCE_DEFAULT) {
-        inputSource = AUDIO_SOURCE_MIC;
-    }
-    halInputSource = inputSource;
-
-    // TODO: check for existing client for this port ID
-    if (*portId == AUDIO_PORT_HANDLE_NONE) {
-        *portId = AudioPort::getNextUniqueId();
-    }
+    DeviceVector inputDevices;
 
     // Explicit routing?
     sp<DeviceDescriptor> deviceDesc;
@@ -1568,11 +1519,67 @@
     }
     mInputRoutes.addRoute(session, SessionRoute::STREAM_TYPE_NA, inputSource, deviceDesc, uid);
 
+    // special case for mmap capture: if an input IO handle is specified, we reuse this input if
+    // possible
+    if ((flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) == AUDIO_INPUT_FLAG_MMAP_NOIRQ &&
+            *input != AUDIO_IO_HANDLE_NONE) {
+        ssize_t index = mInputs.indexOfKey(*input);
+        if (index < 0) {
+            ALOGW("getInputForAttr() unknown MMAP input %d", *input);
+            status = BAD_VALUE;
+            goto error;
+        }
+        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+        sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
+        if (audioSession == 0) {
+            ALOGW("getInputForAttr() unknown session %d on input %d", session, *input);
+            status = BAD_VALUE;
+            goto error;
+        }
+        // For MMAP mode, the first call to getInputForAttr() is made on behalf of audioflinger.
+        // The second call is for the first active client and sets the UID. Any further call
+        // corresponds to a new client and is only permitted from the same UId.
+        if (audioSession->openCount() == 1) {
+            audioSession->setUid(uid);
+        } else if (audioSession->uid() != uid) {
+            ALOGW("getInputForAttr() bad uid %d for session %d uid %d",
+                  uid, session, audioSession->uid());
+            status = INVALID_OPERATION;
+            goto error;
+        }
+        audioSession->changeOpenCount(1);
+        *inputType = API_INPUT_LEGACY;
+        if (*portId == AUDIO_PORT_HANDLE_NONE) {
+            *portId = AudioPort::getNextUniqueId();
+        }
+        inputDevices = mAvailableInputDevices.getDevicesFromType(inputDesc->mDevice);
+        *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
+                : AUDIO_PORT_HANDLE_NONE;
+        ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
+
+        return NO_ERROR;
+    }
+
+    *input = AUDIO_IO_HANDLE_NONE;
+    *inputType = API_INPUT_INVALID;
+
+    if (inputSource == AUDIO_SOURCE_DEFAULT) {
+        inputSource = AUDIO_SOURCE_MIC;
+    }
+    halInputSource = inputSource;
+
+    // TODO: check for existing client for this port ID
+    if (*portId == AUDIO_PORT_HANDLE_NONE) {
+        *portId = AudioPort::getNextUniqueId();
+    }
+
+    audio_devices_t device;
+
     if (inputSource == AUDIO_SOURCE_REMOTE_SUBMIX &&
             strncmp(attr->tags, "addr=", strlen("addr=")) == 0) {
-        status_t ret = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
-        if (ret != NO_ERROR) {
-            return ret;
+        status = mPolicyMixes.getInputMixForAttr(*attr, &policyMix);
+        if (status != NO_ERROR) {
+            goto error;
         }
         *inputType = API_INPUT_MIX_EXT_POLICY_REROUTE;
         device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
@@ -1581,7 +1588,8 @@
         device = getDeviceAndMixForInputSource(inputSource, &policyMix);
         if (device == AUDIO_DEVICE_NONE) {
             ALOGW("getInputForAttr() could not find device for source %d", inputSource);
-            return BAD_VALUE;
+            status = BAD_VALUE;
+            goto error;
         }
         if (policyMix != NULL) {
             address = policyMix->mDeviceAddress;
@@ -1610,11 +1618,11 @@
                                config->sample_rate, config->format, config->channel_mask, flags,
                                policyMix);
     if (*input == AUDIO_IO_HANDLE_NONE) {
-        mInputRoutes.removeRoute(session);
-        return INVALID_OPERATION;
+        status = INVALID_OPERATION;
+        goto error;
     }
 
-    DeviceVector inputDevices = mAvailableInputDevices.getDevicesFromType(device);
+    inputDevices = mAvailableInputDevices.getDevicesFromType(device);
     *selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
             : AUDIO_PORT_HANDLE_NONE;
 
@@ -1622,6 +1630,10 @@
             *input, *inputType, *selectedDeviceId);
 
     return NO_ERROR;
+
+error:
+    mInputRoutes.removeRoute(session);
+    return status;
 }
 
 
@@ -4926,12 +4938,13 @@
     // scan the whole RouteMap, for each entry, convert the stream type to a strategy
     // (getStrategy(stream)).
     // if the strategy from the stream type in the RouteMap is the same as the argument above,
-    // and activity count is non-zero
-    // the device = the device from the descriptor in the RouteMap, and exit.
+    // and activity count is non-zero and the device in the route descriptor is available
+    // then select this device.
     for (size_t routeIndex = 0; routeIndex < mOutputRoutes.size(); routeIndex++) {
         sp<SessionRoute> route = mOutputRoutes.valueAt(routeIndex);
         routing_strategy routeStrategy = getStrategy(route->mStreamType);
-        if ((routeStrategy == strategy) && route->isActive()) {
+        if ((routeStrategy == strategy) && route->isActive() &&
+                (mAvailableOutputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
             return route->mDeviceDescriptor->type();
         }
     }
@@ -5326,9 +5339,15 @@
 
 audio_devices_t AudioPolicyManager::getDeviceForInputSource(audio_source_t inputSource)
 {
+    // Routing
+    // Scan the whole RouteMap to see if we have an explicit route:
+    // if the input source in the RouteMap is the same as the argument above,
+    // and activity count is non-zero and the device in the route descriptor is available
+    // then select this device.
     for (size_t routeIndex = 0; routeIndex < mInputRoutes.size(); routeIndex++) {
          sp<SessionRoute> route = mInputRoutes.valueAt(routeIndex);
-         if (inputSource == route->mSource && route->isActive()) {
+         if ((inputSource == route->mSource) && route->isActive() &&
+                 (mAvailableInputDevices.indexOf(route->mDeviceDescriptor) >= 0)) {
              return route->mDeviceDescriptor->type();
          }
      }
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);
 
 };
 
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);
-
 };
 
 // ----------------------------------------------------------------------------