Merge "audioflinger: improve mmap stream volume" into oc-dev
diff --git a/camera/include/camera/ndk/NdkCameraMetadataTags.h b/camera/include/camera/ndk/NdkCameraMetadataTags.h
index ced6034..25d364e 100644
--- a/camera/include/camera/ndk/NdkCameraMetadataTags.h
+++ b/camera/include/camera/ndk/NdkCameraMetadataTags.h
@@ -1542,7 +1542,11 @@
      * request A.</p>
      * <p>Note that when enableZsl is <code>true</code>, it is not guaranteed to get output images captured in the
      * past for requests with STILL_CAPTURE capture intent.</p>
-     * <p>The value of enableZsl in capture templates is always <code>false</code> if present.</p>
+     * <p>For applications targeting SDK versions O and newer, the value of enableZsl in
+     * TEMPLATE_STILL_CAPTURE template may be <code>true</code>. The value in other templates is always
+     * <code>false</code> if present.</p>
+     * <p>For applications targeting SDK versions older than O, the value of enableZsl in all
+     * capture templates is always <code>false</code> if present.</p>
      *
      * @see ACAMERA_CONTROL_CAPTURE_INTENT
      * @see ACAMERA_SENSOR_TIMESTAMP
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index 1b26b87..120a074 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -295,6 +295,8 @@
     std::string toString() const {
         std::stringstream ss;
         ss << "mInterpolatorType: " << mInterpolatorType << std::endl;
+        ss << "mFirstSlope: " << mFirstSlope << std::endl;
+        ss << "mLastSlope: " << mLastSlope << std::endl;
         for (const auto &pt : *this) {
             ss << pt.first << " " << pt.second << std::endl;
         }
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index f5a74d8..1282124 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -95,7 +95,7 @@
             , mId(-1) {
         }
 
-        Configuration(const Configuration &configuration)
+        explicit Configuration(const Configuration &configuration)
             : Interpolator<S, T>(*static_cast<const Interpolator<S, T> *>(&configuration))
             , mType(configuration.mType)
             , mOptionFlags(configuration.mOptionFlags)
@@ -236,6 +236,7 @@
             clampVolume();
         }
 
+        // The parcel layout must match VolumeShaper.java
         status_t writeToParcel(Parcel *parcel) const {
             if (parcel == nullptr) return BAD_VALUE;
             return parcel->writeInt32((int32_t)mType)
@@ -300,15 +301,19 @@
             : Operation(FLAG_NONE, -1 /* replaceId */) {
         }
 
-        explicit Operation(Flag flags, int replaceId)
+        Operation(Flag flags, int replaceId)
             : Operation(flags, replaceId, std::numeric_limits<S>::quiet_NaN() /* xOffset */) {
         }
 
-        Operation(const Operation &operation)
+        explicit Operation(const Operation &operation)
             : Operation(operation.mFlags, operation.mReplaceId, operation.mXOffset) {
         }
 
-        explicit Operation(Flag flags, int replaceId, S xOffset)
+        explicit Operation(const sp<Operation> &operation)
+            : Operation(*operation.get()) {
+        }
+
+        Operation(Flag flags, int replaceId, S xOffset)
             : mFlags(flags)
             , mReplaceId(replaceId)
             , mXOffset(xOffset) {
@@ -375,7 +380,7 @@
     // must match with VolumeShaper.java in frameworks/base
     class State : public RefBase {
     public:
-        explicit State(T volume, S xOffset)
+        State(T volume, S xOffset)
             : mVolume(volume)
             , mXOffset(xOffset) {
         }
@@ -480,7 +485,7 @@
     // TODO: Since we pass configuration and operation as shared pointers
     // there is a potential risk that the caller may modify these after
     // delivery.  Currently, we don't require copies made here.
-    explicit VolumeShaper(
+    VolumeShaper(
             const sp<VolumeShaper::Configuration> &configuration,
             const sp<VolumeShaper::Operation> &operation)
         : mConfiguration(configuration) // we do not make a copy
@@ -523,6 +528,10 @@
         mDelayXOffset = xOffset;
     }
 
+    bool isStarted() const {
+        return mStartFrame >= 0;
+    }
+
     std::pair<T /* volume */, bool /* active */> getVolume(
             int64_t trackFrameCount, double trackSampleRate) {
         if ((getFlags() & VolumeShaper::Operation::FLAG_DELAY) != 0) {
@@ -628,7 +637,8 @@
     explicit VolumeHandler(uint32_t sampleRate)
         : mSampleRate((double)sampleRate)
         , mLastFrame(0)
-        , mVolumeShaperIdCounter(VolumeShaper::kSystemIdMax) {
+        , mVolumeShaperIdCounter(VolumeShaper::kSystemIdMax)
+        , mLastVolume(1.f, false) {
     }
 
     VolumeShaper::Status applyVolumeShaper(
@@ -746,6 +756,8 @@
         return it->getState();
     }
 
+    // getVolume() is not const, as it updates internal state.
+    // Once called, any VolumeShapers not already started begin running.
     std::pair<T /* volume */, bool /* active */> getVolume(int64_t trackFrameCount) {
         AutoMutex _l(mLock);
         mLastFrame = trackFrameCount;
@@ -758,7 +770,21 @@
             activeCount += shaperVolume.second;
             ++it;
         }
-        return std::make_pair(volume, activeCount != 0);
+        mLastVolume = std::make_pair(volume, activeCount != 0);
+        return mLastVolume;
+    }
+
+    // Used by a client side VolumeHandler to ensure all the VolumeShapers
+    // indicate that they have been started.  Upon a change in audioserver
+    // output sink, this information is used for restoration of the server side
+    // VolumeHandler.
+    void setStarted() {
+        (void)getVolume(mLastFrame);  // getVolume() will start the individual VolumeShapers.
+    }
+
+    std::pair<T /* volume */, bool /* active */> getLastVolume() const {
+        AutoMutex _l(mLock);
+        return mLastVolume;
     }
 
     std::string toString() const {
@@ -772,20 +798,19 @@
         return ss.str();
     }
 
-    void forall(const std::function<VolumeShaper::Status (
-            const sp<VolumeShaper::Configuration> &configuration,
-            const sp<VolumeShaper::Operation> &operation)> &lambda) {
+    void forall(const std::function<VolumeShaper::Status (const VolumeShaper &)> &lambda) {
         AutoMutex _l(mLock);
+        VS_LOG("forall: mVolumeShapers.size() %zu", mVolumeShapers.size());
         for (const auto &shaper : mVolumeShapers) {
-            VS_LOG("forall applying lambda");
-            (void)lambda(shaper.mConfiguration, shaper.mOperation);
+            VolumeShaper::Status status = lambda(shaper);
+            VS_LOG("forall applying lambda on shaper (%p): %d", &shaper, (int)status);
         }
     }
 
     void reset() {
         AutoMutex _l(mLock);
         mVolumeShapers.clear();
-        mLastFrame = -1;
+        mLastFrame = 0;
         // keep mVolumeShaperIdCounter as is.
     }
 
@@ -827,8 +852,9 @@
 
     mutable Mutex mLock;
     double mSampleRate; // in samples (frames) per second
-    int64_t mLastFrame; // logging purpose only
+    int64_t mLastFrame; // logging purpose only, 0 on start
     int32_t mVolumeShaperIdCounter; // a counter to return a unique volume shaper id.
+    std::pair<T /* volume */, bool /* active */> mLastVolume;
     std::list<VolumeShaper> mVolumeShapers; // list provides stable iterators on erase
 }; // VolumeHandler
 
diff --git a/media/libaaudio/examples/write_sine/src/write_sine.cpp b/media/libaaudio/examples/write_sine/src/write_sine.cpp
index 6525c0a..df55c3f 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine.cpp
@@ -63,8 +63,8 @@
 
     aaudio_result_t result = AAUDIO_OK;
 
-    const int requestedSamplesPerFrame = 2;
-    int actualSamplesPerFrame = 0;
+    const int requestedChannelCount = 2;
+    int actualChannelCount = 0;
     const int requestedSampleRate = SAMPLE_RATE;
     int actualSampleRate = 0;
     aaudio_audio_format_t actualDataFormat = AAUDIO_FORMAT_UNSPECIFIED;
@@ -90,7 +90,7 @@
     // in a buffer if we hang or crash.
     setvbuf(stdout, nullptr, _IONBF, (size_t) 0);
 
-    printf("%s - Play a sine wave using AAudio, Z2\n", argv[0]);
+    printf("%s - Play a sine wave using AAudio\n", argv[0]);
 
     // Use an AAudioStreamBuilder to contain requested parameters.
     result = AAudio_createStreamBuilder(&aaudioBuilder);
@@ -100,7 +100,7 @@
 
     // Request stream properties.
     AAudioStreamBuilder_setSampleRate(aaudioBuilder, requestedSampleRate);
-    AAudioStreamBuilder_setSamplesPerFrame(aaudioBuilder, requestedSamplesPerFrame);
+    AAudioStreamBuilder_setChannelCount(aaudioBuilder, requestedChannelCount);
     AAudioStreamBuilder_setFormat(aaudioBuilder, REQUESTED_FORMAT);
     AAudioStreamBuilder_setSharingMode(aaudioBuilder, REQUESTED_SHARING_MODE);
 
@@ -120,9 +120,9 @@
     sineOsc1.setup(440.0, actualSampleRate);
     sineOsc2.setup(660.0, actualSampleRate);
 
-    actualSamplesPerFrame = AAudioStream_getSamplesPerFrame(aaudioStream);
-    printf("SamplesPerFrame: requested = %d, actual = %d\n",
-            requestedSamplesPerFrame, actualSamplesPerFrame);
+    actualChannelCount = AAudioStream_getChannelCount(aaudioStream);
+    printf("ChannelCount: requested = %d, actual = %d\n",
+            requestedChannelCount, actualChannelCount);
 
     actualSharingMode = AAudioStream_getSharingMode(aaudioStream);
     printf("SharingMode: requested = %s, actual = %s\n",
@@ -152,9 +152,9 @@
 
     // Allocate a buffer for the audio data.
     if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
-        floatData = new float[framesPerWrite * actualSamplesPerFrame];
+        floatData = new float[framesPerWrite * actualChannelCount];
     } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
-        shortData = new int16_t[framesPerWrite * actualSamplesPerFrame];
+        shortData = new int16_t[framesPerWrite * actualChannelCount];
     } else {
         printf("ERROR Unsupported data format!\n");
         goto finish;
@@ -178,15 +178,15 @@
 
         if (actualDataFormat == AAUDIO_FORMAT_PCM_FLOAT) {
             // Render sine waves to left and right channels.
-            sineOsc1.render(&floatData[0], actualSamplesPerFrame, framesPerWrite);
-            if (actualSamplesPerFrame > 1) {
-                sineOsc2.render(&floatData[1], actualSamplesPerFrame, framesPerWrite);
+            sineOsc1.render(&floatData[0], actualChannelCount, framesPerWrite);
+            if (actualChannelCount > 1) {
+                sineOsc2.render(&floatData[1], actualChannelCount, framesPerWrite);
             }
         } else if (actualDataFormat == AAUDIO_FORMAT_PCM_I16) {
             // Render sine waves to left and right channels.
-            sineOsc1.render(&shortData[0], actualSamplesPerFrame, framesPerWrite);
-            if (actualSamplesPerFrame > 1) {
-                sineOsc2.render(&shortData[1], actualSamplesPerFrame, framesPerWrite);
+            sineOsc1.render(&shortData[0], actualChannelCount, framesPerWrite);
+            if (actualChannelCount > 1) {
+                sineOsc2.render(&shortData[1], actualChannelCount, framesPerWrite);
             }
         }
 
diff --git a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
index 8c1072d..a7e32bd 100644
--- a/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
+++ b/media/libaaudio/examples/write_sine/src/write_sine_callback.cpp
@@ -65,11 +65,11 @@
     /**
      * Only call this after open() has been called.
      */
-    int32_t getSamplesPerFrame() {
+    int32_t getChannelCount() {
         if (mStream == nullptr) {
             return AAUDIO_ERROR_INVALID_STATE;
         }
-        return AAudioStream_getSamplesPerFrame(mStream);;
+        return AAudioStream_getChannelCount(mStream);;
     }
 
     /**
@@ -119,7 +119,7 @@
 
     // Write zero data to fill up the buffer and prevent underruns.
     aaudio_result_t prime() {
-        int32_t samplesPerFrame = AAudioStream_getSamplesPerFrame(mStream);
+        int32_t samplesPerFrame = AAudioStream_getChannelCount(mStream);
         const int numFrames = 32;
         float zeros[numFrames * samplesPerFrame];
         memset(zeros, 0, sizeof(zeros));
@@ -186,7 +186,7 @@
         sineData->schedulerChecked = true;
     }
 
-    int32_t samplesPerFrame = AAudioStream_getSamplesPerFrame(stream);
+    int32_t samplesPerFrame = AAudioStream_getChannelCount(stream);
     // This code only plays on the first one or two channels.
     // TODO Support arbitrary number of channels.
     switch (AAudioStream_getFormat(stream)) {
@@ -239,7 +239,7 @@
         goto error;
     }
     printf("player.getFramesPerSecond() = %d\n", player.getFramesPerSecond());
-    printf("player.getSamplesPerFrame() = %d\n", player.getSamplesPerFrame());
+    printf("player.getChannelCount() = %d\n", player.getChannelCount());
     myData.sineOsc1.setup(440.0, 48000);
     myData.sineOsc1.setSweep(300.0, 600.0, 5.0);
     myData.sineOsc2.setup(660.0, 48000);
diff --git a/media/libaaudio/include/aaudio/AAudio.h b/media/libaaudio/include/aaudio/AAudio.h
index 4c1ea55..532c372 100644
--- a/media/libaaudio/include/aaudio/AAudio.h
+++ b/media/libaaudio/include/aaudio/AAudio.h
@@ -206,20 +206,28 @@
                                                        int32_t sampleRate);
 
 /**
- * Request a number of samples per frame.
+ * Request a number of channels for the stream.
  *
  * The stream may be opened with a different value.
  * So the application should query for the actual value after the stream is opened.
  *
  * The default, if you do not call this function, is AAUDIO_UNSPECIFIED.
  *
- * Note, this quantity is sometimes referred to as "channel count".
+ * Note, this quantity is sometimes referred to as "samples per frame".
  *
  * @param builder reference provided by AAudio_createStreamBuilder()
- * @param samplesPerFrame Number of samples in one frame, ie. numChannels.
+ * @param channelCount Number of channels desired.
  */
+AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* builder,
+                                                   int32_t channelCount);
+
+/**
+ *
+ * @deprecated use AAudioStreamBuilder_setChannelCount()
+ */
+// TODO remove as soon as the NDK and OS are in sync, before RC1
 AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
-                                                   int32_t samplesPerFrame);
+                                                       int32_t samplesPerFrame);
 
 /**
  * Request a sample data format, for example AAUDIO_FORMAT_PCM_I16.
@@ -677,8 +685,18 @@
 AAUDIO_API int32_t AAudioStream_getSampleRate(AAudioStream* stream);
 
 /**
+ * A stream has one or more channels of data.
+ * A frame will contain one sample for each channel.
+ *
+ * @param stream reference provided by AAudioStreamBuilder_openStream()
+ * @return actual number of channels
+ */
+AAUDIO_API int32_t AAudioStream_getChannelCount(AAudioStream* stream);
+
+/**
  * The samplesPerFrame is also known as channelCount.
  *
+ * @deprecated use AAudioStream_getChannelCount()
  * @param stream reference provided by AAudioStreamBuilder_openStream()
  * @return actual samples per frame
  */
diff --git a/media/libaaudio/libaaudio.map.txt b/media/libaaudio/libaaudio.map.txt
index 1024e1f..efd92ae 100644
--- a/media/libaaudio/libaaudio.map.txt
+++ b/media/libaaudio/libaaudio.map.txt
@@ -9,6 +9,7 @@
     AAudioStreamBuilder_setFramesPerDataCallback;
     AAudioStreamBuilder_setSampleRate;
     AAudioStreamBuilder_setSamplesPerFrame;
+    AAudioStreamBuilder_setChannelCount;
     AAudioStreamBuilder_setFormat;
     AAudioStreamBuilder_setSharingMode;
     AAudioStreamBuilder_setDirection;
@@ -32,6 +33,7 @@
     AAudioStream_getXRunCount;
     AAudioStream_getSampleRate;
     AAudioStream_getSamplesPerFrame;
+    AAudioStream_getChannelCount;
     AAudioStream_getDeviceId;
     AAudioStream_getFormat;
     AAudioStream_getSharingMode;
diff --git a/media/libaaudio/src/core/AAudioAudio.cpp b/media/libaaudio/src/core/AAudioAudio.cpp
index 97726e6..462ecb3 100644
--- a/media/libaaudio/src/core/AAudioAudio.cpp
+++ b/media/libaaudio/src/core/AAudioAudio.cpp
@@ -128,8 +128,15 @@
     streamBuilder->setSampleRate(sampleRate);
 }
 
+AAUDIO_API void AAudioStreamBuilder_setChannelCount(AAudioStreamBuilder* builder,
+                                                       int32_t channelCount)
+{
+    AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
+    streamBuilder->setSamplesPerFrame(channelCount);
+}
+
 AAUDIO_API void AAudioStreamBuilder_setSamplesPerFrame(AAudioStreamBuilder* builder,
-                                                   int32_t samplesPerFrame)
+                                                       int32_t samplesPerFrame)
 {
     AudioStreamBuilder *streamBuilder = convertAAudioBuilderToStreamBuilder(builder);
     streamBuilder->setSamplesPerFrame(samplesPerFrame);
@@ -334,6 +341,12 @@
     return audioStream->getSampleRate();
 }
 
+AAUDIO_API int32_t AAudioStream_getChannelCount(AAudioStream* stream)
+{
+    AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
+    return audioStream->getSamplesPerFrame();
+}
+
 AAUDIO_API int32_t AAudioStream_getSamplesPerFrame(AAudioStream* stream)
 {
     AudioStream *audioStream = convertAAudioStreamToAudioStream(stream);
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 3a0ce5e..4baf253 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -652,6 +652,9 @@
             get_sched_policy(0, &mPreviousSchedulingGroup);
             androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
         }
+
+        // Start our local VolumeHandler for restoration purposes.
+        mVolumeHandler->setStarted();
     } else {
         ALOGE("start() status %d", status);
         mState = previousState;
@@ -2254,17 +2257,20 @@
             }
         }
         // restore volume handler
-        mVolumeHandler->forall([this](const sp<VolumeShaper::Configuration> &configuration,
-                const sp<VolumeShaper::Operation> &operation) -> VolumeShaper::Status {
-            sp<VolumeShaper::Operation> operationToEnd = new VolumeShaper::Operation(*operation);
+        mVolumeHandler->forall([this](const VolumeShaper &shaper) -> VolumeShaper::Status {
+            sp<VolumeShaper::Operation> operationToEnd =
+                    new VolumeShaper::Operation(shaper.mOperation);
             // TODO: Ideally we would restore to the exact xOffset position
             // as returned by getVolumeShaperState(), but we don't have that
             // information when restoring at the client unless we periodically poll
             // the server or create shared memory state.
             //
-            // For now, we simply advance to the end of the VolumeShaper effect.
-            operationToEnd->setXOffset(1.f);
-            return mAudioTrack->applyVolumeShaper(configuration, operationToEnd);
+            // For now, we simply advance to the end of the VolumeShaper effect
+            // if it has been started.
+            if (shaper.isStarted()) {
+                operationToEnd->setXOffset(1.f);
+            }
+            return mAudioTrack->applyVolumeShaper(shaper.mConfiguration, operationToEnd);
         });
 
         if (mState == STATE_ACTIVE) {
@@ -2334,19 +2340,36 @@
     AutoMutex lock(mLock);
     mVolumeHandler->setIdIfNecessary(configuration);
     VolumeShaper::Status status = mAudioTrack->applyVolumeShaper(configuration, operation);
+
+    if (status == DEAD_OBJECT) {
+        if (restoreTrack_l("applyVolumeShaper") == OK) {
+            status = mAudioTrack->applyVolumeShaper(configuration, operation);
+        }
+    }
     if (status >= 0) {
         // save VolumeShaper for restore
         mVolumeHandler->applyVolumeShaper(configuration, operation);
+        if (mState == STATE_ACTIVE || mState == STATE_STOPPING) {
+            mVolumeHandler->setStarted();
+        }
+    } else {
+        // warn only if not an expected restore failure.
+        ALOGW_IF(!((isOffloadedOrDirect_l() || mDoNotReconnect) && status == DEAD_OBJECT),
+                "applyVolumeShaper failed: %d", status);
     }
     return status;
 }
 
 sp<VolumeShaper::State> AudioTrack::getVolumeShaperState(int id)
 {
-    // TODO: To properly restore the AudioTrack
-    // we will need to save the last state in AudioTrackShared.
     AutoMutex lock(mLock);
-    return mAudioTrack->getVolumeShaperState(id);
+    sp<VolumeShaper::State> state = mAudioTrack->getVolumeShaperState(id);
+    if (state.get() == nullptr && (mCblk->mFlags & CBLK_INVALID) != 0) {
+        if (restoreTrack_l("getVolumeShaperState") == OK) {
+            state = mAudioTrack->getVolumeShaperState(id);
+        }
+    }
+    return state;
 }
 
 status_t AudioTrack::getTimestamp(ExtendedTimestamp *timestamp)
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index a7d9f0f..05b726a 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -302,6 +302,12 @@
 void AudioMixer::track_t::unprepareForDownmix() {
     ALOGV("AudioMixer::unprepareForDownmix(%p)", this);
 
+    if (mPostDownmixReformatBufferProvider != nullptr) {
+        // release any buffers held by the mPostDownmixReformatBufferProvider
+        // before deallocating the downmixerBufferProvider.
+        mPostDownmixReformatBufferProvider->reset();
+    }
+
     mDownmixRequiresFormat = AUDIO_FORMAT_INVALID;
     if (downmixerBufferProvider != NULL) {
         // this track had previously been configured with a downmixer, delete it
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index 229e747..43881b3 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -34,6 +34,7 @@
 #include <binder/IServiceManager.h>
 #include <media/IMediaAnalyticsService.h>
 #include <media/MediaAnalyticsItem.h>
+#include <private/android_filesystem_config.h>
 
 namespace android {
 
@@ -776,6 +777,24 @@
         return NULL;
     }
 
+    // completely skip logging from certain UIDs. We do this here
+    // to avoid the multi-second timeouts while we learn that
+    // sepolicy will not let us find the service.
+    // We do this only for a select set of UIDs
+    // The sepolicy protection is still in place, we just want a faster
+    // response from this specific, small set of uids.
+    {
+        uid_t uid = getuid();
+        switch (uid) {
+            case AID_RADIO:     // telephony subsystem, RIL
+                return NULL;
+                break;
+            default:
+                // let sepolicy deny access if appropriate
+                break;
+        }
+    }
+
     {
         Mutex::Autolock _l(sInitMutex);
         const char *badness = "";
diff --git a/media/libmediaplayerservice/MediaPlayerService.cpp b/media/libmediaplayerservice/MediaPlayerService.cpp
index b082654..cba5cf5 100644
--- a/media/libmediaplayerservice/MediaPlayerService.cpp
+++ b/media/libmediaplayerservice/MediaPlayerService.cpp
@@ -2029,12 +2029,23 @@
     ALOGV("setVolume");
     t->setVolume(mLeftVolume, mRightVolume);
 
-    // Dispatch any queued VolumeShapers when the track was not open.
-    mVolumeHandler->forall([&t](const sp<VolumeShaper::Configuration> &configuration,
-            const sp<VolumeShaper::Operation> &operation) -> VolumeShaper::Status {
-        return t->applyVolumeShaper(configuration, operation);
+    // Restore VolumeShapers for the MediaPlayer in case the track was recreated
+    // due to an output sink error (e.g. offload to non-offload switch).
+    mVolumeHandler->forall([&t](const VolumeShaper &shaper) -> VolumeShaper::Status {
+        sp<VolumeShaper::Operation> operationToEnd =
+                new VolumeShaper::Operation(shaper.mOperation);
+        // TODO: Ideally we would restore to the exact xOffset position
+        // as returned by getVolumeShaperState(), but we don't have that
+        // information when restoring at the client unless we periodically poll
+        // the server or create shared memory state.
+        //
+        // For now, we simply advance to the end of the VolumeShaper effect
+        // if it has been started.
+        if (shaper.isStarted()) {
+            operationToEnd->setXOffset(1.f);
+        }
+        return t->applyVolumeShaper(shaper.mConfiguration, operationToEnd);
     });
-    mVolumeHandler->reset(); // After dispatching, clear VolumeShaper queue.
 
     mSampleRateHz = sampleRate;
     mFlags = flags;
@@ -2075,7 +2086,11 @@
     if (mTrack != 0) {
         mTrack->setVolume(mLeftVolume, mRightVolume);
         mTrack->setAuxEffectSendLevel(mSendLevel);
-        return mTrack->start();
+        status_t status = mTrack->start();
+        if (status == NO_ERROR) {
+            mVolumeHandler->setStarted();
+        }
+        return status;
     }
     return NO_INIT;
 }
@@ -2279,13 +2294,20 @@
     Mutex::Autolock lock(mLock);
     ALOGV("AudioOutput::applyVolumeShaper");
 
-    // We take ownership of the VolumeShaper if set before the track is created.
     mVolumeHandler->setIdIfNecessary(configuration);
+
+    VolumeShaper::Status status;
     if (mTrack != 0) {
-        return mTrack->applyVolumeShaper(configuration, operation);
+        status = mTrack->applyVolumeShaper(configuration, operation);
+        if (status >= 0) {
+            (void)mVolumeHandler->applyVolumeShaper(configuration, operation);
+            // TODO: start on exact AudioTrack state (STATE_ACTIVE || STATE_STOPPING)
+            mVolumeHandler->setStarted();
+        }
     } else {
-        return mVolumeHandler->applyVolumeShaper(configuration, operation);
+        status = mVolumeHandler->applyVolumeShaper(configuration, operation);
     }
+    return status;
 }
 
 sp<VolumeShaper::State> MediaPlayerService::AudioOutput::getVolumeShaperState(int id)
diff --git a/media/libmediaplayerservice/nuplayer/GenericSource.cpp b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
index aedca3f..fb1f42b 100644
--- a/media/libmediaplayerservice/nuplayer/GenericSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/GenericSource.cpp
@@ -156,6 +156,7 @@
     extractor = MediaExtractor::Create(mDataSource, NULL);
 
     if (extractor == NULL) {
+        ALOGE("initFromDataSource, cannot create extractor!");
         return UNKNOWN_ERROR;
     }
 
@@ -171,6 +172,7 @@
 
     size_t numtracks = extractor->countTracks();
     if (numtracks == 0) {
+        ALOGE("initFromDataSource, source has no track!");
         return UNKNOWN_ERROR;
     }
 
@@ -1952,12 +1954,12 @@
     size_t psshsize;
 
     if (!mFileMeta->findData(kKeyPssh, &type, &pssh, &psshsize)) {
-        ALOGE("checkDrmInfo: No PSSH");
+        ALOGV("checkDrmInfo: No PSSH");
         return OK; // source without DRM info
     }
 
     Parcel parcel;
-    NuPlayerDrm::retrieveDrmInfo(pssh, psshsize, mMimes, &parcel);
+    NuPlayerDrm::retrieveDrmInfo(pssh, psshsize, &parcel);
     ALOGV("checkDrmInfo: MEDIA_DRM_INFO PSSH size: %d  Parcel size: %d  objects#: %d",
           (int)psshsize, (int)parcel.dataSize(), (int)parcel.objectsCount());
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 9e579f9..a4a5861 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -95,7 +95,11 @@
 }
 
 NuPlayer::Decoder::~Decoder() {
-    mCodec->release();
+    // Need to stop looper first since mCodec could be accessed on the mDecoderLooper.
+    stopLooper();
+    if (mCodec != NULL) {
+        mCodec->release();
+    }
     releaseAndResetMediaBuffers();
 }
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
index 1210dc9..d0de7b0 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.cpp
@@ -43,8 +43,7 @@
 }
 
 NuPlayer::DecoderBase::~DecoderBase() {
-    mDecoderLooper->unregisterHandler(id());
-    mDecoderLooper->stop();
+    stopLooper();
 }
 
 static
@@ -73,6 +72,11 @@
     mDecoderLooper->registerHandler(this);
 }
 
+void NuPlayer::DecoderBase::stopLooper() {
+    mDecoderLooper->unregisterHandler(id());
+    mDecoderLooper->stop();
+}
+
 void NuPlayer::DecoderBase::setParameters(const sp<AMessage> &params) {
     sp<AMessage> msg = new AMessage(kWhatSetParameters, this);
     msg->setMessage("params", params);
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
index dcdfcaf..d44c396 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoderBase.h
@@ -69,6 +69,8 @@
 
     virtual ~DecoderBase();
 
+    void stopLooper();
+
     virtual void onMessageReceived(const sp<AMessage> &msg);
 
     virtual void onConfigure(const sp<AMessage> &format) = 0;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index ce6cedc..b7c9db7 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -205,26 +205,8 @@
 }
 
 // Parcel has only private copy constructor so passing it in rather than returning
-void NuPlayerDrm::retrieveDrmInfo(const void *pssh, size_t psshsize,
-        const Vector<String8> &mimes_in, Parcel *parcel)
+void NuPlayerDrm::retrieveDrmInfo(const void *pssh, size_t psshsize, Parcel *parcel)
 {
-    // 0) Make mimes a vector of unique items while keeping the original order; video first
-    Vector<String8> mimes;
-    for (size_t j = 0; j < mimes_in.size(); j++) {
-        String8 mime = mimes_in[j];
-        bool exists = false;
-        for (size_t i = 0; i < mimes.size() && !exists; i++) {
-            if (mimes[i] == mime) {
-                exists = true;
-            }
-        } // for i
-
-        if (!exists) {
-            mimes.add(mime);
-        }
-    } // for j
-
-
     // 1) PSSH bytes
     parcel->writeUint32(psshsize);
     parcel->writeByteArray(psshsize, (const uint8_t*)pssh);
@@ -242,18 +224,6 @@
         ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  supportedScheme[%zu] %s", i,
                 uuid.toHexString().string());
     }
-
-    // TODO: remove mimes after it's removed from Java DrmInfo
-    // 3) mimes
-    parcel->writeUint32(mimes.size());
-    for (size_t i = 0; i < mimes.size(); i++) {
-        // writing as String16 so the Java framework side can unpack it to Java String
-        String16 mime(mimes[i]);
-        parcel->writeString16(mime);
-
-        ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO  MIME[%zu] %s",
-                i, mimes[i].string());
-    }
 }
 
 ////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
index 6704bd1..6b8a2d9 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.h
@@ -84,8 +84,7 @@
         static sp<ICrypto> createCryptoAndPlugin(const uint8_t uuid[16],
                 const Vector<uint8_t> &drmSessionId, status_t &status);
         // Parcel has only private copy constructor so passing it in rather than returning
-        static void retrieveDrmInfo(const void *pssh, size_t psshsize,
-                const Vector<String8> &mimes_in, Parcel *parcel);
+        static void retrieveDrmInfo(const void *pssh, size_t psshsize, Parcel *parcel);
 
         ////////////////////////////////////////////////////////////////////////////////////////////
         /// Helpers for NuPlayerDecoder
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 8b91541..2877ba2 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -251,6 +251,7 @@
 
     virtual PortMode getPortMode(OMX_U32 portIndex);
 
+    virtual void stateExited();
     virtual bool onMessageReceived(const sp<AMessage> &msg);
 
     virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2);
@@ -553,6 +554,7 @@
       mTunneled(false),
       mDescribeColorAspectsIndex((OMX_INDEXTYPE)0),
       mDescribeHDRStaticInfoIndex((OMX_INDEXTYPE)0),
+      mStateGeneration(0),
       mVendorExtensionsStatus(kExtensionsUnchecked) {
     mUninitializedState = new UninitializedState(this);
     mLoadedState = new LoadedState(this);
@@ -5322,6 +5324,10 @@
     return KEEP_BUFFERS;
 }
 
+void ACodec::BaseState::stateExited() {
+    ++mCodec->mStateGeneration;
+}
+
 bool ACodec::BaseState::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         case kWhatInputBufferFilled:
@@ -5398,6 +5404,12 @@
             break;
         }
 
+        case ACodec::kWhatForceStateTransition:
+        {
+            ALOGV("Already transitioned --- ignore");
+            break;
+        }
+
         default:
             return false;
     }
@@ -6988,7 +7000,6 @@
 
 void ACodec::ExecutingState::stateEntered() {
     ALOGV("[%s] Now Executing", mCodec->mComponentName.c_str());
-
     mCodec->mRenderTracker.clear(systemTime(CLOCK_MONOTONIC));
     mCodec->processDeferredMessages();
 }
@@ -7614,6 +7625,30 @@
     mCallback->onSignaledInputEOS(err);
 }
 
+void ACodec::forceStateTransition(int generation) {
+    if (generation != mStateGeneration) {
+        ALOGV("Ignoring stale force state transition message: #%d (now #%d)",
+                generation, mStateGeneration);
+        return;
+    }
+    ALOGE("State machine stuck");
+    // Error must have already been signalled to the client.
+
+    // Deferred messages will be handled at LoadedState at the end of the
+    // transition.
+    mShutdownInProgress = true;
+    // No shutdown complete callback at the end of the transition.
+    mExplicitShutdown = false;
+    mKeepComponentAllocated = true;
+
+    status_t err = mOMXNode->sendCommand(OMX_CommandStateSet, OMX_StateIdle);
+    if (err != OK) {
+        // TODO: do some recovery here.
+    } else {
+        changeState(mExecutingToIdleState);
+    }
+}
+
 bool ACodec::ExecutingState::onOMXFrameRendered(int64_t mediaTimeUs, nsecs_t systemNano) {
     mCodec->onFrameRendered(mediaTimeUs, systemNano);
     return true;
@@ -7680,7 +7715,14 @@
 
     switch (msg->what()) {
         case kWhatFlush:
-        case kWhatShutdown:
+        case kWhatShutdown: {
+            if (mCodec->mFatalError) {
+                sp<AMessage> msg = new AMessage(ACodec::kWhatForceStateTransition, mCodec);
+                msg->setInt32("generation", mCodec->mStateGeneration);
+                msg->post(3000000);
+            }
+            // fall-through
+        }
         case kWhatResume:
         case kWhatSetParameters:
         {
@@ -7693,6 +7735,16 @@
             break;
         }
 
+        case kWhatForceStateTransition:
+        {
+            int32_t generation = 0;
+            CHECK(msg->findInt32("generation", &generation));
+            mCodec->forceStateTransition(generation);
+
+            handled = true;
+            break;
+        }
+
         default:
             handled = BaseState::onMessageReceived(msg);
             break;
@@ -7752,15 +7804,7 @@
 
                 if (err != OK) {
                     mCodec->signalError(OMX_ErrorUndefined, makeNoSideEffectStatus(err));
-
-                    // This is technically not correct, but appears to be
-                    // the only way to free the component instance.
-                    // Controlled transitioning from excecuting->idle
-                    // and idle->loaded seem impossible probably because
-                    // the output port never finishes re-enabling.
-                    mCodec->mShutdownInProgress = true;
-                    mCodec->mKeepComponentAllocated = false;
-                    mCodec->changeState(mCodec->mLoadedState);
+                    ALOGE("Error occurred while disabling the output port");
                 }
 
                 return true;
@@ -7785,7 +7829,7 @@
         }
 
         default:
-            return false;
+            return BaseState::onOMXEvent(event, data1, data2);
     }
 }
 
@@ -7987,6 +8031,11 @@
         case kWhatShutdown:
         {
             mCodec->deferMessage(msg);
+            if (mCodec->mFatalError) {
+                sp<AMessage> msg = new AMessage(ACodec::kWhatForceStateTransition, mCodec);
+                msg->setInt32("generation", mCodec->mStateGeneration);
+                msg->post(3000000);
+            }
             break;
         }
 
@@ -7997,6 +8046,16 @@
             break;
         }
 
+        case kWhatForceStateTransition:
+        {
+            int32_t generation = 0;
+            CHECK(msg->findInt32("generation", &generation));
+            mCodec->forceStateTransition(generation);
+
+            handled = true;
+            break;
+        }
+
         default:
             handled = BaseState::onMessageReceived(msg);
             break;
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 9965462..c91c82b 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -158,7 +158,7 @@
     if (mime == NULL) {
         float confidence;
         if (!sniff(source, &tmp, &confidence, &meta)) {
-            ALOGV("FAILED to autodetect media content.");
+            ALOGW("FAILED to autodetect media content.");
 
             return NULL;
         }
diff --git a/media/libstagefright/include/ACodec.h b/media/libstagefright/include/ACodec.h
index 06ee0e8..22b8657 100644
--- a/media/libstagefright/include/ACodec.h
+++ b/media/libstagefright/include/ACodec.h
@@ -150,6 +150,7 @@
         kWhatSubmitOutputMetadataBufferIfEOS = 'subm',
         kWhatOMXDied                 = 'OMXd',
         kWhatReleaseCodecInstance    = 'relC',
+        kWhatForceStateTransition    = 'fstt',
     };
 
     enum {
@@ -305,6 +306,8 @@
 
     std::shared_ptr<ACodecBufferChannel> mBufferChannel;
 
+    int32_t mStateGeneration;
+
     enum {
         kExtensionsUnchecked,
         kExtensionsNone,
@@ -569,6 +572,9 @@
     // Send EOS on input stream.
     void onSignalEndOfInputStream();
 
+    // Force EXEC->IDLE->LOADED shutdown sequence if not stale.
+    void forceStateTransition(int generation);
+
     DISALLOW_EVIL_CONSTRUCTORS(ACodec);
 };
 
diff --git a/media/libstagefright/omx/1.0/OmxStore.cpp b/media/libstagefright/omx/1.0/OmxStore.cpp
new file mode 100644
index 0000000..0e37af9
--- /dev/null
+++ b/media/libstagefright/omx/1.0/OmxStore.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ios>
+#include <list>
+
+#include <android-base/logging.h>
+
+#include "Conversion.h"
+#include "OmxStore.h"
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+OmxStore::OmxStore() {
+}
+
+OmxStore::~OmxStore() {
+}
+
+Return<void> OmxStore::listServiceAttributes(listServiceAttributes_cb _hidl_cb) {
+    _hidl_cb(toStatus(NO_ERROR), hidl_vec<ServiceAttribute>());
+    return Void();
+}
+
+Return<void> OmxStore::getNodePrefix(getNodePrefix_cb _hidl_cb) {
+    _hidl_cb(hidl_string());
+    return Void();
+}
+
+Return<void> OmxStore::listRoles(listRoles_cb _hidl_cb) {
+    _hidl_cb(hidl_vec<RoleInfo>());
+    return Void();
+}
+
+Return<sp<IOmx>> OmxStore::getOmx(hidl_string const& omxName) {
+    return IOmx::tryGetService(omxName);
+}
+
+// Methods from ::android::hidl::base::V1_0::IBase follow.
+
+IOmxStore* HIDL_FETCH_IOmxStore(const char* /* name */) {
+    return new OmxStore();
+}
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
diff --git a/media/libstagefright/omx/1.0/OmxStore.h b/media/libstagefright/omx/1.0/OmxStore.h
new file mode 100644
index 0000000..f377f5a
--- /dev/null
+++ b/media/libstagefright/omx/1.0/OmxStore.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXSTORE_H
+#define ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXSTORE_H
+
+#include <hidl/MQDescriptor.h>
+#include <hidl/Status.h>
+
+#include <android/hardware/media/omx/1.0/IOmxStore.h>
+
+namespace android {
+namespace hardware {
+namespace media {
+namespace omx {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::hardware::media::omx::V1_0::IOmxStore;
+using ::android::hardware::media::omx::V1_0::IOmx;
+using ::android::hardware::media::omx::V1_0::Status;
+using ::android::hidl::base::V1_0::IBase;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+using ::android::sp;
+using ::android::wp;
+
+struct OmxStore : public IOmxStore {
+    OmxStore();
+    virtual ~OmxStore();
+
+    // Methods from IOmx
+    Return<void> listServiceAttributes(listServiceAttributes_cb) override;
+    Return<void> getNodePrefix(getNodePrefix_cb) override;
+    Return<void> listRoles(listRoles_cb) override;
+    Return<sp<IOmx>> getOmx(hidl_string const&) override;
+};
+
+extern "C" IOmxStore* HIDL_FETCH_IOmxStore(const char* name);
+
+}  // namespace implementation
+}  // namespace V1_0
+}  // namespace omx
+}  // namespace media
+}  // namespace hardware
+}  // namespace android
+
+#endif  // ANDROID_HARDWARE_MEDIA_OMX_V1_0_OMXSTORE_H
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk
index 90333ef..29e2ccc 100644
--- a/media/libstagefright/omx/Android.mk
+++ b/media/libstagefright/omx/Android.mk
@@ -15,6 +15,7 @@
         SoftVideoDecoderOMXComponent.cpp   \
         SoftVideoEncoderOMXComponent.cpp   \
         1.0/Omx.cpp                        \
+        1.0/OmxStore.cpp                   \
         1.0/WGraphicBufferProducer.cpp     \
         1.0/WProducerListener.cpp          \
         1.0/WGraphicBufferSource.cpp       \
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 0521460..103a3e9 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -766,7 +766,6 @@
 status_t GraphicBufferSource::submitBuffer_l(const VideoBuffer &item) {
     CHECK(!mFreeCodecBuffers.empty());
     IOMX::buffer_id codecBufferId = *mFreeCodecBuffers.begin();
-    mFreeCodecBuffers.erase(mFreeCodecBuffers.begin());
 
     ALOGV("submitBuffer_l [slot=%d, bufferId=%d]", item.mBuffer->getSlot(), codecBufferId);
 
@@ -797,6 +796,8 @@
         return err;
     }
 
+    mFreeCodecBuffers.erase(mFreeCodecBuffers.begin());
+
     ssize_t cbix = mSubmittedCodecBuffers.add(codecBufferId, buffer);
     ALOGV("emptyGraphicBuffer succeeded, bufferId=%u@%zd bufhandle=%p",
             codecBufferId, cbix, graphicBuffer->handle);
@@ -815,7 +816,6 @@
         return;
     }
     IOMX::buffer_id codecBufferId = *mFreeCodecBuffers.begin();
-    mFreeCodecBuffers.erase(mFreeCodecBuffers.begin());
 
     // We reject any additional incoming graphic buffers. There is no acquired buffer used for EOS
     status_t err = mOMXNode->emptyBuffer(
@@ -823,6 +823,7 @@
     if (err != OK) {
         ALOGW("emptyDirectBuffer EOS failed: 0x%x", err);
     } else {
+        mFreeCodecBuffers.erase(mFreeCodecBuffers.begin());
         ssize_t cbix = mSubmittedCodecBuffers.add(codecBufferId, nullptr);
         ALOGV("submitEndOfInputStream_l: buffer submitted, bufferId=%u@%zd", codecBufferId, cbix);
         mEndOfStreamSent = true;
@@ -897,7 +898,7 @@
     ++mNumAvailableUnacquiredBuffers;
 
     // For BufferQueue we cannot acquire a buffer if we cannot immediately feed it to the codec
-    // OR we are discarding this buffer (acquiring and immediately releasing it), which makes
+    // UNLESS we are discarding this buffer (acquiring and immediately releasing it), which makes
     // this an ugly logic.
     // NOTE: We could also rely on our debug counter but that is meant only as a debug counter.
     if (!areWeDiscardingAvailableBuffers_l() && mFreeCodecBuffers.empty()) {
@@ -906,6 +907,7 @@
         ALOGV("onFrameAvailable: cannot acquire buffer right now, do it later");
 
         ++mRepeatLastFrameGeneration; // cancel any pending frame repeat
+        return;
     }
 
     VideoBuffer buffer;
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 5e07e3b..5480513 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -489,7 +489,7 @@
 /*static*/ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
 {
     result.append("    Name Active Client Type      Fmt Chn mask Session fCount S F SRate  "
-                  "L dB  R dB    Server Main buf  Aux buf Flags UndFrmCnt  Flushed\n");
+                  "L dB  R dB  VS dB    Server Main buf  Aux buf Flags UndFrmCnt  Flushed\n");
 }
 
 void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size, bool active)
@@ -555,8 +555,11 @@
         nowInUnderrun = '?';
         break;
     }
-    snprintf(&buffer[8], size-8, " %6s %6u %4u %08X %08X %7u %6zu %1c %1d %5u %5.2g %5.2g  "
-                                 "%08X %08zX %08zX 0x%03X %9u%c %7u\n",
+
+    std::pair<float /* volume */, bool /* active */> vsVolume = mVolumeHandler->getLastVolume();
+    snprintf(&buffer[8], size - 8, " %6s %6u %4u %08X %08X %7u %6zu %1c %1d %5u "
+                                   "%5.2g %5.2g %5.2g%c  "
+                                   "%08X %08zX %08zX 0x%03X %9u%c %7u\n",
             active ? "yes" : "no",
             (mClient == 0) ? getpid_cached : mClient->pid(),
             mStreamType,
@@ -569,6 +572,8 @@
             mAudioTrackServerProxy->getSampleRate(),
             20.0 * log10(float_from_gain(gain_minifloat_unpack_left(vlr))),
             20.0 * log10(float_from_gain(gain_minifloat_unpack_right(vlr))),
+            20.0 * log10(vsVolume.first), // VolumeShaper(s) total volume
+            vsVolume.second ? 'A' : ' ',  // if any VolumeShapers active
             mCblk->mServer,
             (size_t)mMainBuffer, // use %zX as %p appends 0x
             (size_t)mAuxBuffer,  // use %zX as %p appends 0x
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index df8726e..f12cc7b 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -478,14 +478,23 @@
 // stop recording mode
 void CameraClient::stopRecording() {
     LOG1("stopRecording (pid %d)", getCallingPid());
-    Mutex::Autolock lock(mLock);
-    if (checkPidAndHardware() != NO_ERROR) return;
+    {
+        Mutex::Autolock lock(mLock);
+        if (checkPidAndHardware() != NO_ERROR) return;
 
-    disableMsgType(CAMERA_MSG_VIDEO_FRAME);
-    mHardware->stopRecording();
-    sCameraService->playSound(CameraService::SOUND_RECORDING_STOP);
+        disableMsgType(CAMERA_MSG_VIDEO_FRAME);
+        mHardware->stopRecording();
+        sCameraService->playSound(CameraService::SOUND_RECORDING_STOP);
 
-    mPreviewBuffer.clear();
+        mPreviewBuffer.clear();
+    }
+
+    {
+        Mutex::Autolock l(mAvailableCallbackBuffersLock);
+        if (!mAvailableCallbackBuffers.empty()) {
+            mAvailableCallbackBuffers.clear();
+        }
+    }
 }
 
 // release a recording frame
diff --git a/services/mediacodec/main_codecservice.cpp b/services/mediacodec/main_codecservice.cpp
index c4e4cff..c59944a 100644
--- a/services/mediacodec/main_codecservice.cpp
+++ b/services/mediacodec/main_codecservice.cpp
@@ -31,9 +31,9 @@
 #include "MediaCodecService.h"
 #include "minijail.h"
 
-#include <android/hardware/media/omx/1.0/IOmx.h>
 #include <hidl/HidlTransportSupport.h>
 #include <omx/1.0/Omx.h>
+#include <omx/1.0/OmxStore.h>
 
 using namespace android;
 
@@ -61,17 +61,23 @@
 
     if (treble) {
         using namespace ::android::hardware::media::omx::V1_0;
+        sp<IOmxStore> omxStore = new implementation::OmxStore();
+        if (omxStore == nullptr) {
+            LOG(ERROR) << "Cannot create IOmxStore HAL service.";
+        } else if (omxStore->registerAsService() != OK) {
+            LOG(ERROR) << "Cannot register IOmxStore HAL service.";
+        }
         sp<IOmx> omx = new implementation::Omx();
         if (omx == nullptr) {
-            LOG(ERROR) << "Cannot create a Treble IOmx service.";
+            LOG(ERROR) << "Cannot create IOmx HAL service.";
         } else if (omx->registerAsService() != OK) {
-            LOG(ERROR) << "Cannot register a Treble IOmx service.";
+            LOG(ERROR) << "Cannot register IOmx HAL service.";
         } else {
-            LOG(INFO) << "Treble IOmx service created.";
+            LOG(INFO) << "Treble OMX service created.";
         }
     } else {
         MediaCodecService::instantiate();
-        LOG(INFO) << "Non-Treble IOMX service created.";
+        LOG(INFO) << "Non-Treble OMX service created.";
     }
 
     ProcessState::self()->startThreadPool();
diff --git a/services/mediacodec/seccomp_policy/mediacodec-arm.policy b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
index 890d777..b8a5e90 100644
--- a/services/mediacodec/seccomp_policy/mediacodec-arm.policy
+++ b/services/mediacodec/seccomp_policy/mediacodec-arm.policy
@@ -29,6 +29,7 @@
 setpriority: 1
 getuid32: 1
 fstat64: 1
+fstatfs64: 1
 pread64: 1
 faccessat: 1
 readlinkat: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
index 4e4ce30..7e8af1a 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm.policy
@@ -20,6 +20,7 @@
 lseek: 1
 writev: 1
 fstatat64: 1
+fstatfs64: 1
 fstat64: 1
 restart_syscall: 1
 exit: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
index 1683adb..aa8be5b 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-arm64.policy
@@ -14,6 +14,7 @@
 madvise: 1
 getuid: 1
 fstat: 1
+fstatfs: 1
 read: 1
 setpriority: 1
 sigaltstack: 1
diff --git a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
index 83725cd..b5a6503 100644
--- a/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
+++ b/services/mediaextractor/seccomp_policy/mediaextractor-x86.policy
@@ -22,6 +22,7 @@
 setpriority: 1
 sigaltstack: 1
 fstatat64: 1
+fstatfs64: 1
 fstat64: 1
 restart_syscall: 1
 exit: 1