Merge "Allows MediaMetadataRetriever to retrieve video rotation angle" into jb-mr1-dev
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index fe9d09d..a921ad6 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -868,16 +868,19 @@
             if (mBtNrecIsOff != btNrecIsOff) {
                 for (size_t i = 0; i < mRecordThreads.size(); i++) {
                     sp<RecordThread> thread = mRecordThreads.valueAt(i);
-                    RecordThread::RecordTrack *track = thread->track();
-                    if (track != NULL) {
-                        audio_devices_t device = thread->device() & AUDIO_DEVICE_IN_ALL;
-                        bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff;
+                    audio_devices_t device = thread->device() & AUDIO_DEVICE_IN_ALL;
+                    bool suspend = audio_is_bluetooth_sco_device(device) && btNrecIsOff;
+                    // collect all of the thread's session IDs
+                    KeyedVector<int, bool> ids = thread->sessionIds();
+                    // suspend effects associated with those session IDs
+                    for (size_t j = 0; j < ids.size(); ++j) {
+                        int sessionId = ids.keyAt(j);
                         thread->setEffectSuspended(FX_IID_AEC,
                                                    suspend,
-                                                   track->sessionId());
+                                                   sessionId);
                         thread->setEffectSuspended(FX_IID_NS,
                                                    suspend,
-                                                   track->sessionId());
+                                                   sessionId);
                     }
                 }
                 mBtNrecIsOff = btNrecIsOff;
@@ -4277,11 +4280,6 @@
 AudioFlinger::PlaybackThread::Track::~Track()
 {
     ALOGV("PlaybackThread::Track destructor");
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread != 0) {
-        Mutex::Autolock _l(thread->mLock);
-        mState = TERMINATED;
-    }
 }
 
 void AudioFlinger::PlaybackThread::Track::destroy()
@@ -5301,10 +5299,7 @@
 
 AudioFlinger::RecordThread::RecordTrack::~RecordTrack()
 {
-    sp<ThreadBase> thread = mThread.promote();
-    if (thread != 0) {
-        AudioSystem::releaseInput(thread->id());
-    }
+    ALOGV("%s", __func__);
 }
 
 // AudioBufferProvider interface
@@ -5377,6 +5372,11 @@
     }
 }
 
+/*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result)
+{
+    result.append("   Clien Fmt Chn mask   Session Buf  S SRate  Serv     User\n");
+}
+
 void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size)
 {
     snprintf(buffer, size, "   %05d %03u 0x%08x %05d   %04u %01d %05u  %08x %08x\n",
@@ -5861,6 +5861,7 @@
 
 AudioFlinger::RecordHandle::~RecordHandle() {
     stop_nonvirtual();
+    mRecordTrack->destroy();
 }
 
 sp<IMemory> AudioFlinger::RecordHandle::getCblk() const {
@@ -5896,7 +5897,7 @@
                                          audio_io_handle_t id,
                                          audio_devices_t device) :
     ThreadBase(audioFlinger, id, device, RECORD),
-    mInput(input), mTrack(NULL), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
+    mInput(input), mResampler(NULL), mRsmpOutBuffer(NULL), mRsmpInBuffer(NULL),
     // mRsmpInIndex and mInputBytes set by readInputParameters()
     mReqChannelCount(popcount(channelMask)),
     mReqSampleRate(sampleRate)
@@ -5980,6 +5981,9 @@
                         mStartStopCond.broadcast();
                     }
                     mStandby = false;
+                } else if (mActiveTrack->mState == TrackBase::TERMINATED) {
+                    removeTrack_l(mActiveTrack);
+                    mActiveTrack.clear();
                 }
             }
             lockEffectChains_l(effectChains);
@@ -6168,8 +6172,8 @@
             lStatus = NO_MEMORY;
             goto Exit;
         }
+        mTracks.add(track);
 
-        mTrack = track.get();
         // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
         bool suspend = audio_is_bluetooth_sco_device(mDevice & AUDIO_DEVICE_IN_ALL) &&
                         mAudioFlinger->btNrecIsOff();
@@ -6320,17 +6324,64 @@
         return BAD_VALUE;
     }
 
+    int eventSession = event->triggerSession();
+    status_t ret = NAME_NOT_FOUND;
+
     Mutex::Autolock _l(mLock);
 
-    if (mTrack != NULL && event->triggerSession() == mTrack->sessionId()) {
-        mTrack->setSyncEvent(event);
-        return NO_ERROR;
+    for (size_t i = 0; i < mTracks.size(); i++) {
+        sp<RecordTrack> track = mTracks[i];
+        if (eventSession == track->sessionId()) {
+            track->setSyncEvent(event);
+            ret = NO_ERROR;
+        }
     }
-    return NAME_NOT_FOUND;
+    return ret;
+}
+
+void AudioFlinger::RecordThread::RecordTrack::destroy()
+{
+    // see comments at AudioFlinger::PlaybackThread::Track::destroy()
+    sp<RecordTrack> keep(this);
+    {
+        sp<ThreadBase> thread = mThread.promote();
+        if (thread != 0) {
+            if (mState == ACTIVE || mState == RESUMING) {
+                AudioSystem::stopInput(thread->id());
+            }
+            AudioSystem::releaseInput(thread->id());
+            Mutex::Autolock _l(thread->mLock);
+            RecordThread *recordThread = (RecordThread *) thread.get();
+            recordThread->destroyTrack_l(this);
+        }
+    }
+}
+
+// destroyTrack_l() must be called with ThreadBase::mLock held
+void AudioFlinger::RecordThread::destroyTrack_l(const sp<RecordTrack>& track)
+{
+    track->mState = TrackBase::TERMINATED;
+    // active tracks are removed by threadLoop()
+    if (mActiveTrack != track) {
+        removeTrack_l(track);
+    }
+}
+
+void AudioFlinger::RecordThread::removeTrack_l(const sp<RecordTrack>& track)
+{
+    mTracks.remove(track);
+    // need anything related to effects here?
 }
 
 void AudioFlinger::RecordThread::dump(int fd, const Vector<String16>& args)
 {
+    dumpInternals(fd, args);
+    dumpTracks(fd, args);
+    dumpEffectChains(fd, args);
+}
+
+void AudioFlinger::RecordThread::dumpInternals(int fd, const Vector<String16>& args)
+{
     const size_t SIZE = 256;
     char buffer[SIZE];
     String8 result;
@@ -6339,11 +6390,6 @@
     result.append(buffer);
 
     if (mActiveTrack != 0) {
-        result.append("Active Track:\n");
-        result.append("   Clien Fmt Chn mask   Session Buf  S SRate  Serv     User\n");
-        mActiveTrack->dump(buffer, SIZE);
-        result.append(buffer);
-
         snprintf(buffer, SIZE, "In index: %d\n", mRsmpInIndex);
         result.append(buffer);
         snprintf(buffer, SIZE, "In size: %d\n", mInputBytes);
@@ -6354,15 +6400,41 @@
         result.append(buffer);
         snprintf(buffer, SIZE, "Out sample rate: %d\n", mReqSampleRate);
         result.append(buffer);
-
-
     } else {
-        result.append("No record client\n");
+        result.append("No active record client\n");
     }
+
     write(fd, result.string(), result.size());
 
     dumpBase(fd, args);
-    dumpEffectChains(fd, args);
+}
+
+void AudioFlinger::RecordThread::dumpTracks(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 256;
+    char buffer[SIZE];
+    String8 result;
+
+    snprintf(buffer, SIZE, "Input thread %p tracks\n", this);
+    result.append(buffer);
+    RecordTrack::appendDumpHeader(result);
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        sp<RecordTrack> track = mTracks[i];
+        if (track != 0) {
+            track->dump(buffer, SIZE);
+            result.append(buffer);
+        }
+    }
+
+    if (mActiveTrack != 0) {
+        snprintf(buffer, SIZE, "\nInput thread %p active tracks\n", this);
+        result.append(buffer);
+        RecordTrack::appendDumpHeader(result);
+        mActiveTrack->dump(buffer, SIZE);
+        result.append(buffer);
+
+    }
+    write(fd, result.string(), result.size());
 }
 
 // AudioBufferProvider interface
@@ -6462,11 +6534,14 @@
             } else {
                 newDevice &= ~(value & AUDIO_DEVICE_IN_ALL);
                 // disable AEC and NS if the device is a BT SCO headset supporting those pre processings
-                if (mTrack != NULL) {
+                if (mTracks.size() > 0) {
                     bool suspend = audio_is_bluetooth_sco_device(
                             (audio_devices_t)value) && mAudioFlinger->btNrecIsOff();
-                    setEffectSuspended_l(FX_IID_AEC, suspend, mTrack->sessionId());
-                    setEffectSuspended_l(FX_IID_NS, suspend, mTrack->sessionId());
+                    for (size_t i = 0; i < mTracks.size(); i++) {
+                        sp<RecordTrack> track = mTracks[i];
+                        setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
+                        setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
+                    }
                 }
             }
             newDevice |= value;
@@ -6605,17 +6680,28 @@
         result = EFFECT_SESSION;
     }
 
-    if (mTrack != NULL && sessionId == mTrack->sessionId()) {
-        result |= TRACK_SESSION;
+    for (size_t i = 0; i < mTracks.size(); ++i) {
+        if (sessionId == mTracks[i]->sessionId()) {
+            result |= TRACK_SESSION;
+            break;
+        }
     }
 
     return result;
 }
 
-AudioFlinger::RecordThread::RecordTrack* AudioFlinger::RecordThread::track()
+KeyedVector<int, bool> AudioFlinger::RecordThread::sessionIds()
 {
+    KeyedVector<int, bool> ids;
     Mutex::Autolock _l(mLock);
-    return mTrack;
+    for (size_t j = 0; j < mTracks.size(); ++j) {
+        sp<RecordThread::RecordTrack> track = mTracks[j];
+        int sessionId = track->sessionId();
+        if (ids.indexOfKey(sessionId) < 0) {
+            ids.add(sessionId, true);
+        }
+    }
+    return ids;
 }
 
 AudioFlinger::AudioStreamIn* AudioFlinger::RecordThread::clearInput()
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index e629533..2b6d00f 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -1381,11 +1381,14 @@
             virtual status_t    start(AudioSystem::sync_event_t event, int triggerSession);
             virtual void        stop();
 
+                    void        destroy();
+
                     // clear the buffer overflow flag
                     void        clearOverflow() { mOverflow = false; }
                     // set the buffer overflow flag and return previous value
                     bool        setOverflow() { bool tmp = mOverflow; mOverflow = true; return tmp; }
 
+            static  void        appendDumpHeader(String8& result);
                     void        dump(char* buffer, size_t size);
 
         private:
@@ -1409,6 +1412,13 @@
                         audio_devices_t device);
                 virtual     ~RecordThread();
 
+        // no addTrack_l ?
+        void        destroyTrack_l(const sp<RecordTrack>& track);
+        void        removeTrack_l(const sp<RecordTrack>& track);
+
+        void        dumpInternals(int fd, const Vector<String16>& args);
+        void        dumpTracks(int fd, const Vector<String16>& args);
+
         // Thread
         virtual bool        threadLoop();
         virtual status_t    readyToRun();
@@ -1453,7 +1463,11 @@
         virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
         virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
         virtual uint32_t hasAudioSession(int sessionId);
-                RecordTrack* track();
+
+                // Return the set of unique session IDs across all tracks.
+                // The keys are the session IDs, and the associated values are meaningless.
+                // FIXME replace by Set [and implement Bag/Multiset for other uses].
+                KeyedVector<int, bool> sessionIds();
 
         virtual status_t setSyncEvent(const sp<SyncEvent>& event);
         virtual bool     isValidSyncEvent(const sp<SyncEvent>& event);
@@ -1471,7 +1485,9 @@
                 void inputStandBy();
 
                 AudioStreamIn                       *mInput;
-                RecordTrack*                        mTrack;
+                SortedVector < sp<RecordTrack> >    mTracks;
+                // mActiveTrack has dual roles:  it indicates the current active track, and
+                // is used together with mStartStopCond to indicate start()/stop() progress
                 sp<RecordTrack>                     mActiveTrack;
                 Condition                           mStartStopCond;
                 AudioResampler                      *mResampler;
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 47d1588..62741d5 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -86,9 +86,10 @@
     }
 
     if (gLogLevel >= 1) {
+        LockedParameters::Key k(mParameters);
         ALOGD("%s: Default parameters converted from camera %d:", __FUNCTION__,
               mCameraId);
-        ALOGD("%s", mParamsFlattened.string());
+        ALOGD("%s", k.mParameters.paramsFlattened.string());
     }
 
     mState = STOPPED;
@@ -115,38 +116,40 @@
     result.append("  State: ");
 #define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break;
 
+    const Parameters& p = mParameters.unsafeUnlock();
+
     result.append(getStateName(mState));
 
     result.append("\n  Current parameters:\n");
     result.appendFormat("    Preview size: %d x %d\n",
-            mParameters.previewWidth, mParameters.previewHeight);
+            p.previewWidth, p.previewHeight);
     result.appendFormat("    Preview FPS range: %d - %d\n",
-            mParameters.previewFpsRange[0], mParameters.previewFpsRange[1]);
+            p.previewFpsRange[0], p.previewFpsRange[1]);
     result.appendFormat("    Preview HAL pixel format: 0x%x\n",
-            mParameters.previewFormat);
+            p.previewFormat);
     result.appendFormat("    Preview transform: %x\n",
-            mParameters.previewTransform);
+            p.previewTransform);
     result.appendFormat("    Picture size: %d x %d\n",
-            mParameters.pictureWidth, mParameters.pictureHeight);
+            p.pictureWidth, p.pictureHeight);
     result.appendFormat("    Jpeg thumbnail size: %d x %d\n",
-            mParameters.jpegThumbSize[0], mParameters.jpegThumbSize[1]);
+            p.jpegThumbSize[0], p.jpegThumbSize[1]);
     result.appendFormat("    Jpeg quality: %d, thumbnail quality: %d\n",
-            mParameters.jpegQuality, mParameters.jpegThumbQuality);
-    result.appendFormat("    Jpeg rotation: %d\n", mParameters.jpegRotation);
+            p.jpegQuality, p.jpegThumbQuality);
+    result.appendFormat("    Jpeg rotation: %d\n", p.jpegRotation);
     result.appendFormat("    GPS tags %s\n",
-            mParameters.gpsEnabled ? "enabled" : "disabled");
-    if (mParameters.gpsEnabled) {
+            p.gpsEnabled ? "enabled" : "disabled");
+    if (p.gpsEnabled) {
         result.appendFormat("    GPS lat x long x alt: %f x %f x %f\n",
-                mParameters.gpsCoordinates[0], mParameters.gpsCoordinates[1],
-                mParameters.gpsCoordinates[2]);
+                p.gpsCoordinates[0], p.gpsCoordinates[1],
+                p.gpsCoordinates[2]);
         result.appendFormat("    GPS timestamp: %lld\n",
-                mParameters.gpsTimestamp);
+                p.gpsTimestamp);
         result.appendFormat("    GPS processing method: %s\n",
-                mParameters.gpsProcessingMethod.string());
+                p.gpsProcessingMethod.string());
     }
 
     result.append("    White balance mode: ");
-    switch (mParameters.wbMode) {
+    switch (p.wbMode) {
         CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_AUTO)
         CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_INCANDESCENT)
         CASE_APPEND_ENUM(ANDROID_CONTROL_AWB_FLUORESCENT)
@@ -159,7 +162,7 @@
     }
 
     result.append("    Effect mode: ");
-    switch (mParameters.effectMode) {
+    switch (p.effectMode) {
         CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_OFF)
         CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_MONO)
         CASE_APPEND_ENUM(ANDROID_CONTROL_EFFECT_NEGATIVE)
@@ -173,7 +176,7 @@
     }
 
     result.append("    Antibanding mode: ");
-    switch (mParameters.antibandingMode) {
+    switch (p.antibandingMode) {
         CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_AUTO)
         CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_OFF)
         CASE_APPEND_ENUM(ANDROID_CONTROL_AE_ANTIBANDING_50HZ)
@@ -182,7 +185,7 @@
     }
 
     result.append("    Scene mode: ");
-    switch (mParameters.sceneMode) {
+    switch (p.sceneMode) {
         case ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED:
             result.append("AUTO\n"); break;
         CASE_APPEND_ENUM(ANDROID_CONTROL_SCENE_MODE_ACTION)
@@ -204,7 +207,7 @@
     }
 
     result.append("    Flash mode: ");
-    switch (mParameters.flashMode) {
+    switch (p.flashMode) {
         CASE_APPEND_ENUM(Parameters::FLASH_MODE_OFF)
         CASE_APPEND_ENUM(Parameters::FLASH_MODE_AUTO)
         CASE_APPEND_ENUM(Parameters::FLASH_MODE_ON)
@@ -215,7 +218,7 @@
     }
 
     result.append("    Focus mode: ");
-    switch (mParameters.focusMode) {
+    switch (p.focusMode) {
         CASE_APPEND_ENUM(Parameters::FOCUS_MODE_AUTO)
         CASE_APPEND_ENUM(Parameters::FOCUS_MODE_MACRO)
         CASE_APPEND_ENUM(Parameters::FOCUS_MODE_CONTINUOUS_VIDEO)
@@ -228,51 +231,52 @@
     }
 
     result.append("    Focusing areas:\n");
-    for (size_t i = 0; i < mParameters.focusingAreas.size(); i++) {
+    for (size_t i = 0; i < p.focusingAreas.size(); i++) {
         result.appendFormat("      [ (%d, %d, %d, %d), weight %d ]\n",
-                mParameters.focusingAreas[i].left,
-                mParameters.focusingAreas[i].top,
-                mParameters.focusingAreas[i].right,
-                mParameters.focusingAreas[i].bottom,
-                mParameters.focusingAreas[i].weight);
+                p.focusingAreas[i].left,
+                p.focusingAreas[i].top,
+                p.focusingAreas[i].right,
+                p.focusingAreas[i].bottom,
+                p.focusingAreas[i].weight);
     }
 
     result.appendFormat("    Exposure compensation index: %d\n",
-            mParameters.exposureCompensation);
+            p.exposureCompensation);
 
     result.appendFormat("    AE lock %s, AWB lock %s\n",
-            mParameters.autoExposureLock ? "enabled" : "disabled",
-            mParameters.autoWhiteBalanceLock ? "enabled" : "disabled" );
+            p.autoExposureLock ? "enabled" : "disabled",
+            p.autoWhiteBalanceLock ? "enabled" : "disabled" );
 
     result.appendFormat("    Metering areas:\n");
-    for (size_t i = 0; i < mParameters.meteringAreas.size(); i++) {
+    for (size_t i = 0; i < p.meteringAreas.size(); i++) {
         result.appendFormat("      [ (%d, %d, %d, %d), weight %d ]\n",
-                mParameters.meteringAreas[i].left,
-                mParameters.meteringAreas[i].top,
-                mParameters.meteringAreas[i].right,
-                mParameters.meteringAreas[i].bottom,
-                mParameters.meteringAreas[i].weight);
+                p.meteringAreas[i].left,
+                p.meteringAreas[i].top,
+                p.meteringAreas[i].right,
+                p.meteringAreas[i].bottom,
+                p.meteringAreas[i].weight);
     }
 
-    result.appendFormat("    Zoom index: %d\n", mParameters.zoom);
-    result.appendFormat("    Video size: %d x %d\n", mParameters.videoWidth,
-            mParameters.videoHeight);
+    result.appendFormat("    Zoom index: %d\n", p.zoom);
+    result.appendFormat("    Video size: %d x %d\n", p.videoWidth,
+            p.videoHeight);
 
     result.appendFormat("    Recording hint is %s\n",
-            mParameters.recordingHint ? "set" : "not set");
+            p.recordingHint ? "set" : "not set");
 
     result.appendFormat("    Video stabilization is %s\n",
-            mParameters.videoStabilization ? "enabled" : "disabled");
+            p.videoStabilization ? "enabled" : "disabled");
 
     result.append("  Current streams:\n");
     result.appendFormat("    Preview stream ID: %d\n", mPreviewStreamId);
     result.appendFormat("    Capture stream ID: %d\n", mCaptureStreamId);
+    result.appendFormat("    Recording stream ID: %d\n", mRecordingStreamId);
 
     result.append("  Current requests:\n");
     if (mPreviewRequest != NULL) {
         result.append("    Preview request:\n");
         write(fd, result.string(), result.size());
-        dump_camera_metadata(mPreviewRequest, fd, 2);
+        dump_indented_camera_metadata(mPreviewRequest, fd, 2, 6);
     } else {
         result.append("    Preview request: undefined\n");
         write(fd, result.string(), result.size());
@@ -281,12 +285,21 @@
     if (mCaptureRequest != NULL) {
         result = "    Capture request:\n";
         write(fd, result.string(), result.size());
-        dump_camera_metadata(mCaptureRequest, fd, 2);
+        dump_indented_camera_metadata(mCaptureRequest, fd, 2, 6);
     } else {
         result = "    Capture request: undefined\n";
         write(fd, result.string(), result.size());
     }
 
+    if (mRecordingRequest != NULL) {
+        result = "    Recording request:\n";
+        write(fd, result.string(), result.size());
+        dump_indented_camera_metadata(mRecordingRequest, fd, 2, 6);
+    } else {
+        result = "    Recording request: undefined\n";
+        write(fd, result.string(), result.size());
+    }
+
     result = "  Device dump:\n";
     write(fd, result.string(), result.size());
 
@@ -524,9 +537,9 @@
     }
     mState = STOPPED;
 
-    Mutex::Autolock pl(mParamsLock);
+    LockedParameters::Key k(mParameters);
 
-    res = updatePreviewStream();
+    res = updatePreviewStream(k.mParameters);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update preview stream: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
@@ -534,7 +547,7 @@
     }
 
     if (mPreviewRequest == NULL) {
-        res = updatePreviewRequest();
+        res = updatePreviewRequest(k.mParameters);
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to create preview request: %s (%d)",
                     __FUNCTION__, mCameraId, strerror(-res), res);
@@ -622,9 +635,9 @@
             // OK
             break;
     }
-    Mutex::Autolock pl(mParamsLock);
+    LockedParameters::Key k(mParameters);
 
-    mParameters.storeMetadataInBuffers = enabled;
+    k.mParameters.storeMetadataInBuffers = enabled;
 
     return OK;
 }
@@ -653,16 +666,16 @@
             return INVALID_OPERATION;
     };
 
-    Mutex::Autolock pl(mParamsLock);
+    LockedParameters::Key k(mParameters);
 
-    if (!mParameters.storeMetadataInBuffers) {
+    if (!k.mParameters.storeMetadataInBuffers) {
         ALOGE("%s: Camera %d: Recording only supported in metadata mode, but "
                 "non-metadata recording mode requested!", __FUNCTION__,
                 mCameraId);
         return INVALID_OPERATION;
     }
 
-    res = updateRecordingStream();
+    res = updateRecordingStream(k.mParameters);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update recording stream: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
@@ -670,7 +683,7 @@
     }
 
     if (mRecordingRequest == NULL) {
-        res = updateRecordingRequest();
+        res = updateRecordingRequest(k.mParameters);
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to create recording request: %s (%d)",
                     __FUNCTION__, mCameraId, strerror(-res), res);
@@ -816,9 +829,9 @@
             return INVALID_OPERATION;
     }
 
-    Mutex::Autolock pl(mParamsLock);
+    LockedParameters::Key k(mParameters);
 
-    res = updateCaptureStream();
+    res = updateCaptureStream(k.mParameters);
     if (res != OK) {
         ALOGE("%s: Camera %d: Can't set up still image stream: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
@@ -826,7 +839,7 @@
     }
 
     if (mCaptureRequest == NULL) {
-        res = updateCaptureRequest();
+        res = updateCaptureRequest(k.mParameters);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create still image capture request: "
                     "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
@@ -904,7 +917,7 @@
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
     Mutex::Autolock icl(mICameraLock);
-    Mutex::Autolock pl(mParamsLock);
+    LockedParameters::Key k(mParameters);
     status_t res;
 
     CameraParameters newParams(params);
@@ -921,13 +934,13 @@
     int previewWidth, previewHeight;
     newParams.getPreviewSize(&previewWidth, &previewHeight);
 
-    if (previewWidth != mParameters.previewWidth ||
-            previewHeight != mParameters.previewHeight) {
+    if (previewWidth != k.mParameters.previewWidth ||
+            previewHeight != k.mParameters.previewHeight) {
         if (mState >= PREVIEW) {
             ALOGE("%s: Preview size cannot be updated when preview "
                     "is active! (Currently %d x %d, requested %d x %d",
                     __FUNCTION__,
-                    mParameters.previewWidth, mParameters.previewHeight,
+                    k.mParameters.previewWidth, k.mParameters.previewHeight,
                     previewWidth, previewHeight);
             return BAD_VALUE;
         }
@@ -949,8 +962,8 @@
     int previewFps = 0;
     bool fpsRangeChanged = false;
     newParams.getPreviewFpsRange(&previewFpsRange[0], &previewFpsRange[1]);
-    if (previewFpsRange[0] != mParameters.previewFpsRange[0] ||
-            previewFpsRange[1] != mParameters.previewFpsRange[1]) {
+    if (previewFpsRange[0] != k.mParameters.previewFpsRange[0] ||
+            previewFpsRange[1] != k.mParameters.previewFpsRange[1]) {
         fpsRangeChanged = true;
         camera_metadata_entry_t availablePreviewFpsRanges =
             staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
@@ -972,7 +985,7 @@
 
     // PREVIEW_FORMAT
     int previewFormat = formatStringToEnum(newParams.getPreviewFormat());
-    if (previewFormat != mParameters.previewFormat) {
+    if (previewFormat != k.mParameters.previewFormat) {
         if (mState >= PREVIEW) {
             ALOGE("%s: Preview format cannot be updated when preview "
                     "is active!", __FUNCTION__);
@@ -995,7 +1008,7 @@
     // The single-value FPS is the same as the minimum of the range.
     if (!fpsRangeChanged) {
         previewFps = newParams.getPreviewFrameRate();
-        if (previewFps != mParameters.previewFps) {
+        if (previewFps != k.mParameters.previewFps) {
             camera_metadata_entry_t availableFrameRates =
                 staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES);
             for (i = 0; i < availableFrameRates.count; i+=2) {
@@ -1014,8 +1027,8 @@
     // PICTURE_SIZE
     int pictureWidth, pictureHeight;
     newParams.getPictureSize(&pictureWidth, &pictureHeight);
-    if (pictureWidth == mParameters.pictureWidth ||
-            pictureHeight == mParameters.pictureHeight) {
+    if (pictureWidth == k.mParameters.pictureWidth ||
+            pictureHeight == k.mParameters.pictureHeight) {
         camera_metadata_entry_t availablePictureSizes =
             staticInfo(ANDROID_SCALER_AVAILABLE_JPEG_SIZES);
         for (i = 0; i < availablePictureSizes.count; i+=2) {
@@ -1035,8 +1048,8 @@
             newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH);
     jpegThumbSize[1] =
             newParams.getInt(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT);
-    if (jpegThumbSize[0] != mParameters.jpegThumbSize[0] ||
-            jpegThumbSize[1] != mParameters.jpegThumbSize[1]) {
+    if (jpegThumbSize[0] != k.mParameters.jpegThumbSize[0] ||
+            jpegThumbSize[1] != k.mParameters.jpegThumbSize[1]) {
         camera_metadata_entry_t availableJpegThumbSizes =
             staticInfo(ANDROID_JPEG_AVAILABLE_THUMBNAIL_SIZES);
         for (i = 0; i < availableJpegThumbSizes.count; i+=2) {
@@ -1140,7 +1153,7 @@
     // WHITE_BALANCE
     int wbMode = wbModeStringToEnum(
         newParams.get(CameraParameters::KEY_WHITE_BALANCE) );
-    if (wbMode != mParameters.wbMode) {
+    if (wbMode != k.mParameters.wbMode) {
         camera_metadata_entry_t availableWbModes =
             staticInfo(ANDROID_CONTROL_AWB_AVAILABLE_MODES);
         for (i = 0; i < availableWbModes.count; i++) {
@@ -1157,7 +1170,7 @@
     // EFFECT
     int effectMode = effectModeStringToEnum(
         newParams.get(CameraParameters::KEY_EFFECT) );
-    if (effectMode != mParameters.effectMode) {
+    if (effectMode != k.mParameters.effectMode) {
         camera_metadata_entry_t availableEffectModes =
             staticInfo(ANDROID_CONTROL_AVAILABLE_EFFECTS);
         for (i = 0; i < availableEffectModes.count; i++) {
@@ -1174,7 +1187,7 @@
     // ANTIBANDING
     int antibandingMode = abModeStringToEnum(
         newParams.get(CameraParameters::KEY_ANTIBANDING) );
-    if (antibandingMode != mParameters.antibandingMode) {
+    if (antibandingMode != k.mParameters.antibandingMode) {
         camera_metadata_entry_t availableAbModes =
             staticInfo(ANDROID_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES);
         for (i = 0; i < availableAbModes.count; i++) {
@@ -1191,7 +1204,7 @@
     // SCENE_MODE
     int sceneMode = sceneModeStringToEnum(
         newParams.get(CameraParameters::KEY_SCENE_MODE) );
-    if (sceneMode != mParameters.sceneMode) {
+    if (sceneMode != k.mParameters.sceneMode) {
         camera_metadata_entry_t availableSceneModes =
             staticInfo(ANDROID_CONTROL_AVAILABLE_SCENE_MODES);
         for (i = 0; i < availableSceneModes.count; i++) {
@@ -1208,7 +1221,7 @@
     // FLASH_MODE
     Parameters::flashMode_t flashMode = flashModeStringToEnum(
         newParams.get(CameraParameters::KEY_FLASH_MODE) );
-    if (flashMode != mParameters.flashMode) {
+    if (flashMode != k.mParameters.flashMode) {
         camera_metadata_entry_t flashAvailable =
             staticInfo(ANDROID_FLASH_AVAILABLE, 1, 1);
         if (!flashAvailable.data.u8[0] &&
@@ -1240,7 +1253,7 @@
     // FOCUS_MODE
     Parameters::focusMode_t focusMode = focusModeStringToEnum(
         newParams.get(CameraParameters::KEY_FOCUS_MODE));
-    if (focusMode != mParameters.focusMode) {
+    if (focusMode != k.mParameters.focusMode) {
         if (focusMode != Parameters::FOCUS_MODE_FIXED) {
             camera_metadata_entry_t minFocusDistance =
                 staticInfo(ANDROID_LENS_MINIMUM_FOCUS_DISTANCE);
@@ -1322,8 +1335,8 @@
     // VIDEO_SIZE
     int videoWidth, videoHeight;
     newParams.getVideoSize(&videoWidth, &videoHeight);
-    if (videoWidth != mParameters.videoWidth ||
-            videoHeight != mParameters.videoHeight) {
+    if (videoWidth != k.mParameters.videoWidth ||
+            videoHeight != k.mParameters.videoHeight) {
         if (mState == RECORD) {
             ALOGE("%s: Video size cannot be updated when recording is active!",
                     __FUNCTION__);
@@ -1357,63 +1370,63 @@
 
     /** Update internal parameters */
 
-    mParameters.previewWidth = previewWidth;
-    mParameters.previewHeight = previewHeight;
-    mParameters.previewFpsRange[0] = previewFpsRange[0];
-    mParameters.previewFpsRange[1] = previewFpsRange[1];
-    mParameters.previewFps = previewFps;
-    mParameters.previewFormat = previewFormat;
+    k.mParameters.previewWidth = previewWidth;
+    k.mParameters.previewHeight = previewHeight;
+    k.mParameters.previewFpsRange[0] = previewFpsRange[0];
+    k.mParameters.previewFpsRange[1] = previewFpsRange[1];
+    k.mParameters.previewFps = previewFps;
+    k.mParameters.previewFormat = previewFormat;
 
-    mParameters.pictureWidth = pictureWidth;
-    mParameters.pictureHeight = pictureHeight;
+    k.mParameters.pictureWidth = pictureWidth;
+    k.mParameters.pictureHeight = pictureHeight;
 
-    mParameters.jpegThumbSize[0] = jpegThumbSize[0];
-    mParameters.jpegThumbSize[1] = jpegThumbSize[1];
-    mParameters.jpegQuality = jpegQuality;
-    mParameters.jpegThumbQuality = jpegThumbQuality;
+    k.mParameters.jpegThumbSize[0] = jpegThumbSize[0];
+    k.mParameters.jpegThumbSize[1] = jpegThumbSize[1];
+    k.mParameters.jpegQuality = jpegQuality;
+    k.mParameters.jpegThumbQuality = jpegThumbQuality;
 
-    mParameters.gpsEnabled = gpsEnabled;
-    mParameters.gpsCoordinates[0] = gpsCoordinates[0];
-    mParameters.gpsCoordinates[1] = gpsCoordinates[1];
-    mParameters.gpsCoordinates[2] = gpsCoordinates[2];
-    mParameters.gpsTimestamp = gpsTimestamp;
-    mParameters.gpsProcessingMethod = gpsProcessingMethod;
+    k.mParameters.gpsEnabled = gpsEnabled;
+    k.mParameters.gpsCoordinates[0] = gpsCoordinates[0];
+    k.mParameters.gpsCoordinates[1] = gpsCoordinates[1];
+    k.mParameters.gpsCoordinates[2] = gpsCoordinates[2];
+    k.mParameters.gpsTimestamp = gpsTimestamp;
+    k.mParameters.gpsProcessingMethod = gpsProcessingMethod;
 
-    mParameters.wbMode = wbMode;
-    mParameters.effectMode = effectMode;
-    mParameters.antibandingMode = antibandingMode;
-    mParameters.sceneMode = sceneMode;
+    k.mParameters.wbMode = wbMode;
+    k.mParameters.effectMode = effectMode;
+    k.mParameters.antibandingMode = antibandingMode;
+    k.mParameters.sceneMode = sceneMode;
 
-    mParameters.flashMode = flashMode;
-    mParameters.focusMode = focusMode;
+    k.mParameters.flashMode = flashMode;
+    k.mParameters.focusMode = focusMode;
 
-    mParameters.focusingAreas = focusingAreas;
-    mParameters.exposureCompensation = exposureCompensation;
-    mParameters.autoExposureLock = autoExposureLock;
-    mParameters.autoWhiteBalanceLock = autoWhiteBalanceLock;
-    mParameters.meteringAreas = meteringAreas;
-    mParameters.zoom = zoom;
+    k.mParameters.focusingAreas = focusingAreas;
+    k.mParameters.exposureCompensation = exposureCompensation;
+    k.mParameters.autoExposureLock = autoExposureLock;
+    k.mParameters.autoWhiteBalanceLock = autoWhiteBalanceLock;
+    k.mParameters.meteringAreas = meteringAreas;
+    k.mParameters.zoom = zoom;
 
-    mParameters.videoWidth = videoWidth;
-    mParameters.videoHeight = videoHeight;
+    k.mParameters.videoWidth = videoWidth;
+    k.mParameters.videoHeight = videoHeight;
 
-    mParameters.recordingHint = recordingHint;
-    mParameters.videoStabilization = videoStabilization;
+    k.mParameters.recordingHint = recordingHint;
+    k.mParameters.videoStabilization = videoStabilization;
 
-    res = updatePreviewRequest();
+    res = updatePreviewRequest(k.mParameters);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update preview request: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
         return res;
     }
-    res = updateCaptureRequest();
+    res = updateCaptureRequest(k.mParameters);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update capture request: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
         return res;
     }
 
-    res = updateRecordingRequest();
+    res = updateRecordingRequest(k.mParameters);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update recording request: %s (%d)",
                 __FUNCTION__, mCameraId, strerror(-res), res);
@@ -1436,7 +1449,7 @@
         }
     }
 
-    mParamsFlattened = params;
+    k.mParameters.paramsFlattened = params;
 
     return OK;
 }
@@ -1445,10 +1458,10 @@
     ATRACE_CALL();
     Mutex::Autolock icl(mICameraLock);
 
-    Mutex::Autolock pl(mParamsLock);
+    LockedParameters::ReadKey k(mParameters);
 
     // TODO: Deal with focus distances
-    return mParamsFlattened;
+    return k.mParameters.paramsFlattened;
 }
 
 status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
@@ -1459,6 +1472,7 @@
             cmd, arg1, arg2);
 
     if (cmd == CAMERA_CMD_SET_DISPLAY_ORIENTATION) {
+        LockedParameters::Key k(mParameters);
         int transform = degToTransform(arg1,
                 mCameraFacing == CAMERA_FACING_FRONT);
         if (transform == -1) {
@@ -1466,11 +1480,11 @@
                     __FUNCTION__, mCameraId, arg1);
             return BAD_VALUE;
         }
-        if (transform != mParameters.previewTransform &&
+        if (transform != k.mParameters.previewTransform &&
                 mPreviewStreamId != NO_STREAM) {
             mDevice->setStreamTransform(mPreviewStreamId, transform);
         }
-        mParameters.previewTransform = transform;
+        k.mParameters.previewTransform = transform;
         return OK;
     }
 
@@ -1673,7 +1687,7 @@
 
 status_t Camera2Client::buildDefaultParameters() {
     ATRACE_CALL();
-    Mutex::Autolock pl(mParamsLock);
+    LockedParameters::Key k(mParameters);
 
     status_t res;
     CameraParameters params;
@@ -1683,16 +1697,16 @@
     if (!availableProcessedSizes.count) return NO_INIT;
 
     // TODO: Pick more intelligently
-    mParameters.previewWidth = availableProcessedSizes.data.i32[0];
-    mParameters.previewHeight = availableProcessedSizes.data.i32[1];
-    mParameters.videoWidth = mParameters.previewWidth;
-    mParameters.videoHeight = mParameters.previewHeight;
+    k.mParameters.previewWidth = availableProcessedSizes.data.i32[0];
+    k.mParameters.previewHeight = availableProcessedSizes.data.i32[1];
+    k.mParameters.videoWidth = k.mParameters.previewWidth;
+    k.mParameters.videoHeight = k.mParameters.previewHeight;
 
-    params.setPreviewSize(mParameters.previewWidth, mParameters.previewHeight);
-    params.setVideoSize(mParameters.videoWidth, mParameters.videoHeight);
+    params.setPreviewSize(k.mParameters.previewWidth, k.mParameters.previewHeight);
+    params.setVideoSize(k.mParameters.videoWidth, k.mParameters.videoHeight);
     params.set(CameraParameters::KEY_PREFERRED_PREVIEW_SIZE_FOR_VIDEO,
             String8::format("%dx%d",
-                    mParameters.previewWidth, mParameters.previewHeight));
+                    k.mParameters.previewWidth, k.mParameters.previewHeight));
     {
         String8 supportedPreviewSizes;
         for (size_t i=0; i < availableProcessedSizes.count; i += 2) {
@@ -1711,13 +1725,13 @@
         staticInfo(ANDROID_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, 2);
     if (!availableFpsRanges.count) return NO_INIT;
 
-    mParameters.previewFpsRange[0] = availableFpsRanges.data.i32[0];
-    mParameters.previewFpsRange[1] = availableFpsRanges.data.i32[1];
+    k.mParameters.previewFpsRange[0] = availableFpsRanges.data.i32[0];
+    k.mParameters.previewFpsRange[1] = availableFpsRanges.data.i32[1];
 
     params.set(CameraParameters::KEY_PREVIEW_FPS_RANGE,
             String8::format("%d,%d",
-                    mParameters.previewFpsRange[0],
-                    mParameters.previewFpsRange[1]));
+                    k.mParameters.previewFpsRange[0],
+                    k.mParameters.previewFpsRange[1]));
 
     {
         String8 supportedPreviewFpsRange;
@@ -1731,11 +1745,11 @@
                 supportedPreviewFpsRange);
     }
 
-    mParameters.previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+    k.mParameters.previewFormat = HAL_PIXEL_FORMAT_YCrCb_420_SP;
     params.set(CameraParameters::KEY_PREVIEW_FORMAT,
-            formatEnumToString(mParameters.previewFormat)); // NV21
+            formatEnumToString(k.mParameters.previewFormat)); // NV21
 
-    mParameters.previewTransform = degToTransform(0,
+    k.mParameters.previewTransform = degToTransform(0,
             mCameraFacing == CAMERA_FACING_FRONT);
 
     camera_metadata_entry_t availableFormats =
@@ -1793,7 +1807,7 @@
     // still have to do something sane for them
 
     params.set(CameraParameters::KEY_PREVIEW_FRAME_RATE,
-            mParameters.previewFpsRange[0]);
+            k.mParameters.previewFpsRange[0]);
 
     {
         String8 supportedPreviewFrameRates;
@@ -1811,11 +1825,11 @@
     if (!availableJpegSizes.count) return NO_INIT;
 
     // TODO: Pick maximum
-    mParameters.pictureWidth = availableJpegSizes.data.i32[0];
-    mParameters.pictureHeight = availableJpegSizes.data.i32[1];
+    k.mParameters.pictureWidth = availableJpegSizes.data.i32[0];
+    k.mParameters.pictureHeight = availableJpegSizes.data.i32[1];
 
-    params.setPictureSize(mParameters.pictureWidth,
-            mParameters.pictureHeight);
+    params.setPictureSize(k.mParameters.pictureWidth,
+            k.mParameters.pictureHeight);
 
     {
         String8 supportedPictureSizes;
@@ -1838,13 +1852,13 @@
     if (!availableJpegThumbnailSizes.count) return NO_INIT;
 
     // TODO: Pick default thumbnail size sensibly
-    mParameters.jpegThumbSize[0] = availableJpegThumbnailSizes.data.i32[0];
-    mParameters.jpegThumbSize[1] = availableJpegThumbnailSizes.data.i32[1];
+    k.mParameters.jpegThumbSize[0] = availableJpegThumbnailSizes.data.i32[0];
+    k.mParameters.jpegThumbSize[1] = availableJpegThumbnailSizes.data.i32[1];
 
     params.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH,
-            mParameters.jpegThumbSize[0]);
+            k.mParameters.jpegThumbSize[0]);
     params.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT,
-            mParameters.jpegThumbSize[1]);
+            k.mParameters.jpegThumbSize[1]);
 
     {
         String8 supportedJpegThumbSizes;
@@ -1858,21 +1872,21 @@
                 supportedJpegThumbSizes);
     }
 
-    mParameters.jpegThumbQuality = 90;
+    k.mParameters.jpegThumbQuality = 90;
     params.set(CameraParameters::KEY_JPEG_THUMBNAIL_QUALITY,
-            mParameters.jpegThumbQuality);
-    mParameters.jpegQuality = 90;
+            k.mParameters.jpegThumbQuality);
+    k.mParameters.jpegQuality = 90;
     params.set(CameraParameters::KEY_JPEG_QUALITY,
-            mParameters.jpegQuality);
-    mParameters.jpegRotation = 0;
+            k.mParameters.jpegQuality);
+    k.mParameters.jpegRotation = 0;
     params.set(CameraParameters::KEY_ROTATION,
-            mParameters.jpegRotation);
+            k.mParameters.jpegRotation);
 
-    mParameters.gpsEnabled = false;
-    mParameters.gpsProcessingMethod = "unknown";
+    k.mParameters.gpsEnabled = false;
+    k.mParameters.gpsProcessingMethod = "unknown";
     // GPS fields in CameraParameters are not set by implementation
 
-    mParameters.wbMode = ANDROID_CONTROL_AWB_AUTO;
+    k.mParameters.wbMode = ANDROID_CONTROL_AWB_AUTO;
     params.set(CameraParameters::KEY_WHITE_BALANCE,
             CameraParameters::WHITE_BALANCE_AUTO);
 
@@ -1933,7 +1947,7 @@
                 supportedWhiteBalance);
     }
 
-    mParameters.effectMode = ANDROID_CONTROL_EFFECT_OFF;
+    k.mParameters.effectMode = ANDROID_CONTROL_EFFECT_OFF;
     params.set(CameraParameters::KEY_EFFECT,
             CameraParameters::EFFECT_NONE);
 
@@ -1993,7 +2007,7 @@
         params.set(CameraParameters::KEY_SUPPORTED_EFFECTS, supportedEffects);
     }
 
-    mParameters.antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_AUTO;
+    k.mParameters.antibandingMode = ANDROID_CONTROL_AE_ANTIBANDING_AUTO;
     params.set(CameraParameters::KEY_ANTIBANDING,
             CameraParameters::ANTIBANDING_AUTO);
 
@@ -2035,7 +2049,7 @@
                 supportedAntibanding);
     }
 
-    mParameters.sceneMode = ANDROID_CONTROL_OFF;
+    k.mParameters.sceneMode = ANDROID_CONTROL_OFF;
     params.set(CameraParameters::KEY_SCENE_MODE,
             CameraParameters::SCENE_MODE_AUTO);
 
@@ -2140,7 +2154,7 @@
     if (!availableAeModes.count) return NO_INIT;
 
     if (flashAvailable.data.u8[0]) {
-        mParameters.flashMode = Parameters::FLASH_MODE_AUTO;
+        k.mParameters.flashMode = Parameters::FLASH_MODE_AUTO;
         params.set(CameraParameters::KEY_FLASH_MODE,
                 CameraParameters::FLASH_MODE_AUTO);
 
@@ -2160,7 +2174,7 @@
         params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
                 supportedFlashModes);
     } else {
-        mParameters.flashMode = Parameters::FLASH_MODE_OFF;
+        k.mParameters.flashMode = Parameters::FLASH_MODE_OFF;
         params.set(CameraParameters::KEY_FLASH_MODE,
                 CameraParameters::FLASH_MODE_OFF);
         params.set(CameraParameters::KEY_SUPPORTED_FLASH_MODES,
@@ -2177,13 +2191,13 @@
 
     if (minFocusDistance.data.f[0] == 0) {
         // Fixed-focus lens
-        mParameters.focusMode = Parameters::FOCUS_MODE_FIXED;
+        k.mParameters.focusMode = Parameters::FOCUS_MODE_FIXED;
         params.set(CameraParameters::KEY_FOCUS_MODE,
                 CameraParameters::FOCUS_MODE_FIXED);
         params.set(CameraParameters::KEY_SUPPORTED_FOCUS_MODES,
                 CameraParameters::FOCUS_MODE_FIXED);
     } else {
-        mParameters.focusMode = Parameters::FOCUS_MODE_AUTO;
+        k.mParameters.focusMode = Parameters::FOCUS_MODE_AUTO;
         params.set(CameraParameters::KEY_FOCUS_MODE,
                 CameraParameters::FOCUS_MODE_AUTO);
         String8 supportedFocusModes(CameraParameters::FOCUS_MODE_FIXED);
@@ -2238,8 +2252,8 @@
             max3aRegions.data.i32[0]);
     params.set(CameraParameters::KEY_FOCUS_AREAS,
             "(0,0,0,0,0)");
-    mParameters.focusingAreas.clear();
-    mParameters.focusingAreas.add(Parameters::Area(0,0,0,0,0));
+    k.mParameters.focusingAreas.clear();
+    k.mParameters.focusingAreas.add(Parameters::Area(0,0,0,0,0));
 
     camera_metadata_entry_t availableFocalLengths =
         staticInfo(ANDROID_LENS_AVAILABLE_FOCAL_LENGTHS);
@@ -2260,9 +2274,9 @@
     params.setFloat(CameraParameters::KEY_HORIZONTAL_VIEW_ANGLE, horizFov);
     params.setFloat(CameraParameters::KEY_VERTICAL_VIEW_ANGLE, vertFov);
 
-    mParameters.exposureCompensation = 0;
+    k.mParameters.exposureCompensation = 0;
     params.set(CameraParameters::KEY_EXPOSURE_COMPENSATION,
-                mParameters.exposureCompensation);
+                k.mParameters.exposureCompensation);
 
     camera_metadata_entry_t exposureCompensationRange =
         staticInfo(ANDROID_CONTROL_AE_EXP_COMPENSATION_RANGE, 2, 2);
@@ -2281,26 +2295,26 @@
             exposureCompensationStep.data.r[0].numerator /
             exposureCompensationStep.data.r[0].denominator);
 
-    mParameters.autoExposureLock = false;
+    k.mParameters.autoExposureLock = false;
     params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK,
             CameraParameters::FALSE);
     params.set(CameraParameters::KEY_AUTO_EXPOSURE_LOCK_SUPPORTED,
             CameraParameters::TRUE);
 
-    mParameters.autoWhiteBalanceLock = false;
+    k.mParameters.autoWhiteBalanceLock = false;
     params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK,
             CameraParameters::FALSE);
     params.set(CameraParameters::KEY_AUTO_WHITEBALANCE_LOCK_SUPPORTED,
             CameraParameters::TRUE);
 
-    mParameters.meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
+    k.mParameters.meteringAreas.add(Parameters::Area(0, 0, 0, 0, 0));
     params.set(CameraParameters::KEY_MAX_NUM_METERING_AREAS,
             max3aRegions.data.i32[0]);
     params.set(CameraParameters::KEY_METERING_AREAS,
             "(0,0,0,0,0)");
 
-    mParameters.zoom = 0;
-    params.set(CameraParameters::KEY_ZOOM, mParameters.zoom);
+    k.mParameters.zoom = 0;
+    params.set(CameraParameters::KEY_ZOOM, k.mParameters.zoom);
     params.set(CameraParameters::KEY_MAX_ZOOM, NUM_ZOOM_STEPS - 1);
 
     camera_metadata_entry_t maxDigitalZoom =
@@ -2362,16 +2376,17 @@
     }
 
     // Always use metadata mode for recording
-    mParameters.storeMetadataInBuffers = true;
+    k.mParameters.storeMetadataInBuffers = true;
 
-    mParamsFlattened = params.flatten();
+    k.mParameters.paramsFlattened = params.flatten();
 
     return OK;
 }
 
-status_t Camera2Client::updatePreviewStream() {
+status_t Camera2Client::updatePreviewStream(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
+
     if (mPreviewStreamId != NO_STREAM) {
         // Check if stream parameters have to change
         uint32_t currentWidth, currentHeight;
@@ -2382,11 +2397,11 @@
                     "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)mParameters.previewWidth ||
-                currentHeight != (uint32_t)mParameters.previewHeight) {
+        if (currentWidth != (uint32_t)params.previewWidth ||
+                currentHeight != (uint32_t)params.previewHeight) {
             ALOGV("%s: Camera %d: Preview size switch: %d x %d -> %d x %d",
                     __FUNCTION__, mCameraId, currentWidth, currentHeight,
-                    mParameters.previewWidth, mParameters.previewHeight);
+                    params.previewWidth, params.previewHeight);
             res = mDevice->waitUntilDrained();
             if (res != OK) {
                 ALOGE("%s: Camera %d: Error waiting for preview to drain: "
@@ -2406,7 +2421,7 @@
 
     if (mPreviewStreamId == NO_STREAM) {
         res = mDevice->createStream(mPreviewWindow,
-                mParameters.previewWidth, mParameters.previewHeight,
+                params.previewWidth, params.previewHeight,
                 CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0,
                 &mPreviewStreamId);
         if (res != OK) {
@@ -2417,7 +2432,7 @@
     }
 
     res = mDevice->setStreamTransform(mPreviewStreamId,
-            mParameters.previewTransform);
+            params.previewTransform);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to set preview stream transform: "
                 "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
@@ -2427,7 +2442,7 @@
     return OK;
 }
 
-status_t Camera2Client::updatePreviewRequest() {
+status_t Camera2Client::updatePreviewRequest(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
     if (mPreviewRequest == NULL) {
@@ -2440,7 +2455,7 @@
         }
     }
 
-    res = updateRequestCommon(mPreviewRequest);
+    res = updateRequestCommon(mPreviewRequest, params);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update common entries of preview "
                 "request: %s (%d)", __FUNCTION__, mCameraId,
@@ -2451,7 +2466,7 @@
     return OK;
 }
 
-status_t Camera2Client::updateCaptureStream() {
+status_t Camera2Client::updateCaptureStream(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
     // Find out buffer size for JPEG
@@ -2490,8 +2505,8 @@
                     "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)mParameters.pictureWidth ||
-                currentHeight != (uint32_t)mParameters.pictureHeight) {
+        if (currentWidth != (uint32_t)params.pictureWidth ||
+                currentHeight != (uint32_t)params.pictureHeight) {
             res = mDevice->deleteStream(mCaptureStreamId);
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to delete old output stream "
@@ -2506,7 +2521,7 @@
     if (mCaptureStreamId == NO_STREAM) {
         // Create stream for HAL production
         res = mDevice->createStream(mCaptureWindow,
-                mParameters.pictureWidth, mParameters.pictureHeight,
+                params.pictureWidth, params.pictureHeight,
                 HAL_PIXEL_FORMAT_BLOB, maxJpegSize.data.i32[0],
                 &mCaptureStreamId);
         if (res != OK) {
@@ -2519,7 +2534,7 @@
     return OK;
 }
 
-status_t Camera2Client::updateCaptureRequest() {
+status_t Camera2Client::updateCaptureRequest(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
     if (mCaptureRequest == NULL) {
@@ -2532,7 +2547,7 @@
         }
     }
 
-    res = updateRequestCommon(mCaptureRequest);
+    res = updateRequestCommon(mCaptureRequest, params);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update common entries of capture "
                 "request: %s (%d)", __FUNCTION__, mCameraId,
@@ -2542,34 +2557,34 @@
 
     res = updateEntry(mCaptureRequest,
             ANDROID_JPEG_THUMBNAIL_SIZE,
-            mParameters.jpegThumbSize, 2);
+            params.jpegThumbSize, 2);
     if (res != OK) return res;
     res = updateEntry(mCaptureRequest,
             ANDROID_JPEG_THUMBNAIL_QUALITY,
-            &mParameters.jpegThumbQuality, 1);
+            &params.jpegThumbQuality, 1);
     if (res != OK) return res;
     res = updateEntry(mCaptureRequest,
             ANDROID_JPEG_QUALITY,
-            &mParameters.jpegQuality, 1);
+            &params.jpegQuality, 1);
     if (res != OK) return res;
     res = updateEntry(mCaptureRequest,
             ANDROID_JPEG_ORIENTATION,
-            &mParameters.jpegRotation, 1);
+            &params.jpegRotation, 1);
     if (res != OK) return res;
 
-    if (mParameters.gpsEnabled) {
+    if (params.gpsEnabled) {
         res = updateEntry(mCaptureRequest,
                 ANDROID_JPEG_GPS_COORDINATES,
-                mParameters.gpsCoordinates, 3);
+                params.gpsCoordinates, 3);
         if (res != OK) return res;
         res = updateEntry(mCaptureRequest,
                 ANDROID_JPEG_GPS_TIMESTAMP,
-                &mParameters.gpsTimestamp, 1);
+                &params.gpsTimestamp, 1);
         if (res != OK) return res;
         res = updateEntry(mCaptureRequest,
                 ANDROID_JPEG_GPS_PROCESSING_METHOD,
-                mParameters.gpsProcessingMethod.string(),
-                mParameters.gpsProcessingMethod.size());
+                params.gpsProcessingMethod.string(),
+                params.gpsProcessingMethod.size());
         if (res != OK) return res;
     } else {
         res = deleteEntry(mCaptureRequest,
@@ -2586,7 +2601,7 @@
     return OK;
 }
 
-status_t Camera2Client::updateRecordingRequest() {
+status_t Camera2Client::updateRecordingRequest(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
     if (mRecordingRequest == NULL) {
@@ -2599,7 +2614,7 @@
         }
     }
 
-    res = updateRequestCommon(mRecordingRequest);
+    res = updateRequestCommon(mRecordingRequest, params);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update common entries of recording "
                 "request: %s (%d)", __FUNCTION__, mCameraId,
@@ -2610,7 +2625,7 @@
     return OK;
 }
 
-status_t Camera2Client::updateRecordingStream() {
+status_t Camera2Client::updateRecordingStream(const Parameters &params) {
     status_t res;
 
     if (mRecordingConsumer == 0) {
@@ -2633,8 +2648,8 @@
                     "%s (%d)", __FUNCTION__, mCameraId, strerror(-res), res);
             return res;
         }
-        if (currentWidth != (uint32_t)mParameters.videoWidth ||
-                currentHeight != (uint32_t)mParameters.videoHeight) {
+        if (currentWidth != (uint32_t)params.videoWidth ||
+                currentHeight != (uint32_t)params.videoHeight) {
             // TODO: Should wait to be sure previous recording has finished
             res = mDevice->deleteStream(mRecordingStreamId);
             if (res != OK) {
@@ -2649,7 +2664,7 @@
 
     if (mRecordingStreamId == NO_STREAM) {
         res = mDevice->createStream(mRecordingWindow,
-                mParameters.videoWidth, mParameters.videoHeight,
+                params.videoWidth, params.videoHeight,
                 CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mRecordingStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for recording: "
@@ -2661,28 +2676,29 @@
     return OK;
 }
 
-status_t Camera2Client::updateRequestCommon(camera_metadata_t *request) {
+status_t Camera2Client::updateRequestCommon(camera_metadata_t *request,
+        const Parameters &params) {
     ATRACE_CALL();
     status_t res;
     res = updateEntry(request,
-            ANDROID_CONTROL_AE_TARGET_FPS_RANGE, mParameters.previewFpsRange, 2);
+            ANDROID_CONTROL_AE_TARGET_FPS_RANGE, params.previewFpsRange, 2);
     if (res != OK) return res;
 
-    uint8_t wbMode = mParameters.autoWhiteBalanceLock ?
-            ANDROID_CONTROL_AWB_LOCKED : mParameters.wbMode;
+    uint8_t wbMode = params.autoWhiteBalanceLock ?
+            ANDROID_CONTROL_AWB_LOCKED : params.wbMode;
     res = updateEntry(request,
             ANDROID_CONTROL_AWB_MODE, &wbMode, 1);
     if (res != OK) return res;
     res = updateEntry(request,
-            ANDROID_CONTROL_EFFECT_MODE, &mParameters.effectMode, 1);
+            ANDROID_CONTROL_EFFECT_MODE, &params.effectMode, 1);
     if (res != OK) return res;
     res = updateEntry(request,
             ANDROID_CONTROL_AE_ANTIBANDING_MODE,
-            &mParameters.antibandingMode, 1);
+            &params.antibandingMode, 1);
     if (res != OK) return res;
 
     uint8_t controlMode =
-            (mParameters.sceneMode == ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) ?
+            (params.sceneMode == ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) ?
             ANDROID_CONTROL_AUTO : ANDROID_CONTROL_USE_SCENE_MODE;
     res = updateEntry(request,
             ANDROID_CONTROL_MODE, &controlMode, 1);
@@ -2690,13 +2706,13 @@
     if (controlMode == ANDROID_CONTROL_USE_SCENE_MODE) {
         res = updateEntry(request,
                 ANDROID_CONTROL_SCENE_MODE,
-                &mParameters.sceneMode, 1);
+                &params.sceneMode, 1);
         if (res != OK) return res;
     }
 
     uint8_t flashMode = ANDROID_FLASH_OFF;
     uint8_t aeMode;
-    switch (mParameters.flashMode) {
+    switch (params.flashMode) {
         case Parameters::FLASH_MODE_OFF:
             aeMode = ANDROID_CONTROL_AE_ON; break;
         case Parameters::FLASH_MODE_AUTO:
@@ -2711,10 +2727,10 @@
             aeMode = ANDROID_CONTROL_AE_ON_AUTO_FLASH_REDEYE; break;
         default:
             ALOGE("%s: Camera %d: Unknown flash mode %d", __FUNCTION__,
-                    mCameraId, mParameters.flashMode);
+                    mCameraId, params.flashMode);
             return BAD_VALUE;
     }
-    if (mParameters.autoExposureLock) aeMode = ANDROID_CONTROL_AE_LOCKED;
+    if (params.autoExposureLock) aeMode = ANDROID_CONTROL_AE_LOCKED;
 
     res = updateEntry(request,
             ANDROID_FLASH_MODE, &flashMode, 1);
@@ -2725,13 +2741,13 @@
 
     float focusDistance = 0; // infinity focus in diopters
     uint8_t focusMode;
-    switch (mParameters.focusMode) {
+    switch (params.focusMode) {
         case Parameters::FOCUS_MODE_AUTO:
         case Parameters::FOCUS_MODE_MACRO:
         case Parameters::FOCUS_MODE_CONTINUOUS_VIDEO:
         case Parameters::FOCUS_MODE_CONTINUOUS_PICTURE:
         case Parameters::FOCUS_MODE_EDOF:
-            focusMode = mParameters.focusMode;
+            focusMode = params.focusMode;
             break;
         case Parameters::FOCUS_MODE_INFINITY:
         case Parameters::FOCUS_MODE_FIXED:
@@ -2739,7 +2755,7 @@
             break;
         default:
             ALOGE("%s: Camera %d: Unknown focus mode %d", __FUNCTION__,
-                    mCameraId, mParameters.focusMode);
+                    mCameraId, params.focusMode);
             return BAD_VALUE;
     }
     res = updateEntry(request,
@@ -2749,14 +2765,14 @@
             ANDROID_CONTROL_AF_MODE, &focusMode, 1);
     if (res != OK) return res;
 
-    size_t focusingAreasSize = mParameters.focusingAreas.size() * 5;
+    size_t focusingAreasSize = params.focusingAreas.size() * 5;
     int32_t *focusingAreas = new int32_t[focusingAreasSize];
     for (size_t i = 0; i < focusingAreasSize; i += 5) {
-        focusingAreas[i + 0] = mParameters.focusingAreas[i].left;
-        focusingAreas[i + 1] = mParameters.focusingAreas[i].top;
-        focusingAreas[i + 2] = mParameters.focusingAreas[i].right;
-        focusingAreas[i + 3] = mParameters.focusingAreas[i].bottom;
-        focusingAreas[i + 4] = mParameters.focusingAreas[i].weight;
+        focusingAreas[i + 0] = params.focusingAreas[i].left;
+        focusingAreas[i + 1] = params.focusingAreas[i].top;
+        focusingAreas[i + 2] = params.focusingAreas[i].right;
+        focusingAreas[i + 3] = params.focusingAreas[i].bottom;
+        focusingAreas[i + 4] = params.focusingAreas[i].weight;
     }
     res = updateEntry(request,
             ANDROID_CONTROL_AF_REGIONS, focusingAreas,focusingAreasSize);
@@ -2765,17 +2781,17 @@
 
     res = updateEntry(request,
             ANDROID_CONTROL_AE_EXP_COMPENSATION,
-            &mParameters.exposureCompensation, 1);
+            &params.exposureCompensation, 1);
     if (res != OK) return res;
 
-    size_t meteringAreasSize = mParameters.meteringAreas.size() * 5;
+    size_t meteringAreasSize = params.meteringAreas.size() * 5;
     int32_t *meteringAreas = new int32_t[meteringAreasSize];
     for (size_t i = 0; i < meteringAreasSize; i += 5) {
-        meteringAreas[i + 0] = mParameters.meteringAreas[i].left;
-        meteringAreas[i + 1] = mParameters.meteringAreas[i].top;
-        meteringAreas[i + 2] = mParameters.meteringAreas[i].right;
-        meteringAreas[i + 3] = mParameters.meteringAreas[i].bottom;
-        meteringAreas[i + 4] = mParameters.meteringAreas[i].weight;
+        meteringAreas[i + 0] = params.meteringAreas[i].left;
+        meteringAreas[i + 1] = params.meteringAreas[i].top;
+        meteringAreas[i + 2] = params.meteringAreas[i].right;
+        meteringAreas[i + 3] = params.meteringAreas[i].bottom;
+        meteringAreas[i + 4] = params.meteringAreas[i].weight;
     }
     res = updateEntry(request,
             ANDROID_CONTROL_AE_REGIONS, meteringAreas, meteringAreasSize);
@@ -2793,21 +2809,21 @@
             staticInfo(ANDROID_SCALER_AVAILABLE_MAX_ZOOM);
     float zoomIncrement = (maxDigitalZoom.data.f[0] - 1) /
             (NUM_ZOOM_STEPS-1);
-    float zoomRatio = 1 + zoomIncrement * mParameters.zoom;
+    float zoomRatio = 1 + zoomIncrement * params.zoom;
 
     camera_metadata_entry_t activePixelArraySize =
             staticInfo(ANDROID_SENSOR_ACTIVE_ARRAY_SIZE, 2, 2);
     int32_t arrayWidth = activePixelArraySize.data.i32[0];
     int32_t arrayHeight = activePixelArraySize.data.i32[1];
     float zoomLeft, zoomTop, zoomWidth, zoomHeight;
-    if (mParameters.previewWidth >= mParameters.previewHeight) {
+    if (params.previewWidth >= params.previewHeight) {
         zoomWidth =  arrayWidth / zoomRatio;
         zoomHeight = zoomWidth *
-                mParameters.previewHeight / mParameters.previewWidth;
+                params.previewHeight / params.previewWidth;
     } else {
         zoomHeight = arrayHeight / zoomRatio;
         zoomWidth = zoomHeight *
-                mParameters.previewWidth / mParameters.previewHeight;
+                params.previewWidth / params.previewHeight;
     }
     zoomLeft = (arrayWidth - zoomWidth) / 2;
     zoomTop = (arrayHeight - zoomHeight) / 2;
@@ -2819,7 +2835,7 @@
 
     // TODO: Decide how to map recordingHint, or whether just to ignore it
 
-    uint8_t vstabMode = mParameters.videoStabilization ?
+    uint8_t vstabMode = params.videoStabilization ?
             ANDROID_CONTROL_VIDEO_STABILIZATION_ON :
             ANDROID_CONTROL_VIDEO_STABILIZATION_OFF;
     res = updateEntry(request,
@@ -2873,6 +2889,7 @@
     }
     return res;
 }
+
 int Camera2Client::formatStringToEnum(const char *format) {
     return
         !strcmp(format, CameraParameters::PIXEL_FORMAT_YUV422SP) ?
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 83fe94e..3494114 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -89,7 +89,7 @@
     // Ensures serialization between incoming ICamera calls
     mutable Mutex mICameraLock;
 
-    // The following must be called with mICamaeraLock already locked
+    // The following must be called with mICameraLock already locked
 
     status_t setPreviewWindowLocked(const sp<IBinder>& binder,
             sp<ANativeWindow> window);
@@ -97,9 +97,6 @@
     void stopPreviewLocked();
     status_t startPreviewLocked();
 
-    // Mutex that must be locked before accessing mParameters, mParamsFlattened
-    mutable Mutex mParamsLock;
-    String8 mParamsFlattened;
     // Current camera state; this is the contents of the CameraParameters object
     // in a more-efficient format. The enum values are mostly based off the
     // corresponding camera2 enums, not the camera1 strings. A few are defined
@@ -173,6 +170,59 @@
         bool videoStabilization;
 
         bool storeMetadataInBuffers;
+
+        String8 paramsFlattened;
+    };
+
+    class LockedParameters {
+      public:
+        class Key {
+          public:
+            Key(LockedParameters &p):
+                    mParameters(p.mParameters),
+                    mLockedParameters(p) {
+                mLockedParameters.mLock.lock();
+            }
+
+            ~Key() {
+                mLockedParameters.mLock.unlock();
+            }
+            Parameters &mParameters;
+          private:
+            // Disallow copying, default construction
+            Key();
+            Key(const Key &);
+            Key &operator=(const Key &);
+            LockedParameters &mLockedParameters;
+        };
+        class ReadKey {
+          public:
+            ReadKey(const LockedParameters &p):
+                    mParameters(p.mParameters),
+                    mLockedParameters(p) {
+                mLockedParameters.mLock.lock();
+            }
+
+            ~ReadKey() {
+                mLockedParameters.mLock.unlock();
+            }
+            const Parameters &mParameters;
+          private:
+            // Disallow copying, default construction
+            ReadKey();
+            ReadKey(const ReadKey &);
+            ReadKey &operator=(const ReadKey &);
+            const LockedParameters &mLockedParameters;
+        };
+
+        // Only use for dumping or other debugging
+        const Parameters &unsafeUnlock() {
+            return mParameters;
+        }
+      private:
+        Parameters mParameters;
+        mutable Mutex mLock;
+
     } mParameters;
 
     /** Camera device-related private members */
@@ -190,10 +240,9 @@
     camera_metadata_t *mPreviewRequest;
     sp<IBinder> mPreviewSurface;
     sp<ANativeWindow> mPreviewWindow;
-    // Update preview request based on mParameters
-    status_t updatePreviewRequest();
-    // Update preview stream based on mParameters
-    status_t updatePreviewStream();
+
+    status_t updatePreviewRequest(const Parameters &params);
+    status_t updatePreviewStream(const Parameters &params);
 
     /* Still image capture related members */
 
@@ -214,10 +263,9 @@
     sp<Camera2Heap>    mCaptureHeap;
     // Handle captured image buffers
     void onCaptureAvailable();
-    // Update capture request based on mParameters
-    status_t updateCaptureRequest();
-    // Update capture stream based on mParameters
-    status_t updateCaptureStream();
+
+    status_t updateCaptureRequest(const Parameters &params);
+    status_t updateCaptureStream(const Parameters &params);
 
     /* Recording related members */
 
@@ -244,10 +292,9 @@
     size_t mRecordingHeapHead, mRecordingHeapFree;
     // Handle new recording image buffers
     void onRecordingFrameAvailable();
-    // Update recording request based on mParameters
-    status_t updateRecordingRequest();
-    // Update recording stream based on mParameters
-    status_t updateRecordingStream();
+
+    status_t updateRecordingRequest(const Parameters &params);
+    status_t updateRecordingStream(const Parameters &params);
 
     /** Camera2Device instance wrapping HAL2 entry */
 
@@ -293,7 +340,7 @@
     status_t buildDefaultParameters();
 
     // Update parameters all requests use, based on mParameters
-    status_t updateRequestCommon(camera_metadata_t *request);
+    status_t updateRequestCommon(camera_metadata_t *request, const Parameters &params);
 
     // Update specific metadata entry with new values. Adds entry if it does not
     // exist, which will invalidate sorting
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index f42e3a5..d760313 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -120,7 +120,7 @@
 
     result.appendFormat("    Static camera information metadata:\n");
     write(fd, result.string(), result.size());
-    dump_camera_metadata(mDeviceInfo, fd, 2);
+    dump_indented_camera_metadata(mDeviceInfo, fd, 2, 6);
 
     result = "    Request queue contents:\n";
     write(fd, result.string(), result.size());
@@ -487,7 +487,7 @@
              r != mStreamSlot.end(); r++) {
             result = String8::format("       Stream slot buffer %d:\n", i);
             write(fd, result.string(), result.size());
-            dump_camera_metadata(*r, fd, 2);
+            dump_indented_camera_metadata(*r, fd, 2, 10);
             i++;
         }
     }
@@ -502,7 +502,7 @@
              r != mEntries.end(); r++) {
             result = String8::format("       Queue entry %d:\n", i);
             write(fd, result.string(), result.size());
-            dump_camera_metadata(*r, fd, 2);
+            dump_indented_camera_metadata(*r, fd, 2, 10);
             i++;
         }
     }
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index a83c28f..878afde 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -472,7 +472,8 @@
                 if (deviceVersion >= CAMERA_DEVICE_API_VERSION_2_0) {
                     result.appendFormat("  Device static metadata:\n");
                     write(fd, result.string(), result.size());
-                    dump_camera_metadata(info.static_camera_characteristics, fd, 2);
+                    dump_indented_camera_metadata(info.static_camera_characteristics,
+                            fd, 2, 4);
                 } else {
                     write(fd, result.string(), result.size());
                 }