Merge "ProCamera: Add security permission checks for disabling transmit LED" into jb-mr2-dev
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 607ec6a..b89b1c8 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1257,6 +1257,13 @@
     switch (what) {
         case Source::kWhatPrepared:
         {
+            if (mSource == NULL) {
+                // This is a stale notification from a source that was
+                // asynchronously preparing when the client called reset().
+                // We handled the reset, the source is gone.
+                break;
+            }
+
             int32_t err;
             CHECK(msg->findInt32("err", &err));
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index bdafb29..68b9623 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -333,6 +333,14 @@
         case STATE_RESET_IN_PROGRESS:
             return INVALID_OPERATION;
 
+        case STATE_PREPARING:
+        {
+            CHECK(mIsAsyncPrepare);
+
+            notifyListener(MEDIA_PREPARED);
+            break;
+        }
+
         default:
             break;
     }
@@ -503,6 +511,14 @@
 void NuPlayerDriver::notifyPrepareCompleted(status_t err) {
     Mutex::Autolock autoLock(mLock);
 
+    if (mState != STATE_PREPARING) {
+        // We were preparing asynchronously when the client called
+        // reset(), we sent a premature "prepared" notification and
+        // then initiated the reset. This notification is stale.
+        CHECK(mState == STATE_RESET_IN_PROGRESS || mState == STATE_IDLE);
+        return;
+    }
+
     CHECK_EQ(mState, STATE_PREPARING);
 
     mAsyncResult = err;
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index f99ef60..061ae89 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -4,17 +4,10 @@
 
 LOCAL_SRC_FILES:= \
         ANetworkSession.cpp             \
-        MediaReceiver.cpp               \
         MediaSender.cpp                 \
         Parameters.cpp                  \
         ParsedMessage.cpp               \
-        rtp/RTPAssembler.cpp            \
-        rtp/RTPReceiver.cpp             \
         rtp/RTPSender.cpp               \
-        sink/DirectRenderer.cpp         \
-        sink/WifiDisplaySink.cpp        \
-        SNTPClient.cpp                  \
-        TimeSyncer.cpp                  \
         source/Converter.cpp            \
         source/MediaPuller.cpp          \
         source/PlaybackSession.cpp      \
@@ -67,72 +60,3 @@
 LOCAL_MODULE_TAGS := debug
 
 include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        udptest.cpp                 \
-
-LOCAL_SHARED_LIBRARIES:= \
-        libbinder                       \
-        libgui                          \
-        libmedia                        \
-        libstagefright                  \
-        libstagefright_foundation       \
-        libstagefright_wfd              \
-        libutils                        \
-        liblog                          \
-
-LOCAL_MODULE:= udptest
-
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        rtptest.cpp                 \
-
-LOCAL_SHARED_LIBRARIES:= \
-        libbinder                       \
-        libgui                          \
-        libmedia                        \
-        libstagefright                  \
-        libstagefright_foundation       \
-        libstagefright_wfd              \
-        libutils                        \
-        liblog                          \
-
-LOCAL_MODULE:= rtptest
-
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
-
-################################################################################
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-        nettest.cpp                     \
-
-LOCAL_SHARED_LIBRARIES:= \
-        libbinder                       \
-        libgui                          \
-        libmedia                        \
-        libstagefright                  \
-        libstagefright_foundation       \
-        libstagefright_wfd              \
-        libutils                        \
-        liblog                          \
-
-LOCAL_MODULE:= nettest
-
-LOCAL_MODULE_TAGS := debug
-
-include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
index 33af66d..8a3566f 100644
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ b/media/libstagefright/wifi-display/MediaSender.cpp
@@ -341,22 +341,6 @@
             break;
         }
 
-        case kWhatInformSender:
-        {
-            int64_t avgLatencyUs;
-            CHECK(msg->findInt64("avgLatencyUs", &avgLatencyUs));
-
-            int64_t maxLatencyUs;
-            CHECK(msg->findInt64("maxLatencyUs", &maxLatencyUs));
-
-            sp<AMessage> notify = mNotify->dup();
-            notify->setInt32("what", kWhatInformSender);
-            notify->setInt64("avgLatencyUs", avgLatencyUs);
-            notify->setInt64("maxLatencyUs", maxLatencyUs);
-            notify->post();
-            break;
-        }
-
         default:
             TRESPASS();
     }
diff --git a/media/libstagefright/wifi-display/MediaSender.h b/media/libstagefright/wifi-display/MediaSender.h
index 04538ea..64722c5 100644
--- a/media/libstagefright/wifi-display/MediaSender.h
+++ b/media/libstagefright/wifi-display/MediaSender.h
@@ -43,7 +43,6 @@
         kWhatInitDone,
         kWhatError,
         kWhatNetworkStall,
-        kWhatInformSender,
     };
 
     MediaSender(
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 6bbe650..095fd97 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -767,17 +767,6 @@
 }
 
 status_t RTPSender::parseAPP(const uint8_t *data, size_t size) {
-    if (!memcmp("late", &data[8], 4)) {
-        int64_t avgLatencyUs = (int64_t)U64_AT(&data[12]);
-        int64_t maxLatencyUs = (int64_t)U64_AT(&data[20]);
-
-        sp<AMessage> notify = mNotify->dup();
-        notify->setInt32("what", kWhatInformSender);
-        notify->setInt64("avgLatencyUs", avgLatencyUs);
-        notify->setInt64("maxLatencyUs", maxLatencyUs);
-        notify->post();
-    }
-
     return OK;
 }
 
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
index fefcab7..7dc138a 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.h
@@ -37,7 +37,6 @@
         kWhatInitDone,
         kWhatError,
         kWhatNetworkStall,
-        kWhatInformSender,
     };
     RTPSender(
             const sp<ANetworkSession> &netSession,
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index cacfcca..3d7b865 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -559,8 +559,6 @@
                         converter->dropAFrame();
                     }
                 }
-            } else if (what == MediaSender::kWhatInformSender) {
-                onSinkFeedback(msg);
             } else {
                 TRESPASS();
             }
@@ -656,89 +654,6 @@
     }
 }
 
-void WifiDisplaySource::PlaybackSession::onSinkFeedback(const sp<AMessage> &msg) {
-    int64_t avgLatencyUs;
-    CHECK(msg->findInt64("avgLatencyUs", &avgLatencyUs));
-
-    int64_t maxLatencyUs;
-    CHECK(msg->findInt64("maxLatencyUs", &maxLatencyUs));
-
-    ALOGI("sink reports avg. latency of %lld ms (max %lld ms)",
-          avgLatencyUs / 1000ll,
-          maxLatencyUs / 1000ll);
-
-    if (mVideoTrackIndex >= 0) {
-        const sp<Track> &videoTrack = mTracks.valueFor(mVideoTrackIndex);
-        sp<Converter> converter = videoTrack->converter();
-
-        if (converter != NULL) {
-            int32_t videoBitrate =
-                Converter::GetInt32Property("media.wfd.video-bitrate", -1);
-
-            char val[PROPERTY_VALUE_MAX];
-            if (videoBitrate < 0
-                    && property_get("media.wfd.video-bitrate", val, NULL)
-                    && !strcasecmp("adaptive", val)) {
-                videoBitrate = converter->getVideoBitrate();
-
-                if (avgLatencyUs > 300000ll) {
-                    videoBitrate *= 0.6;
-                } else if (avgLatencyUs < 100000ll) {
-                    videoBitrate *= 1.1;
-                }
-            }
-
-            if (videoBitrate > 0) {
-                if (videoBitrate < 500000) {
-                    videoBitrate = 500000;
-                } else if (videoBitrate > 10000000) {
-                    videoBitrate = 10000000;
-                }
-
-                if (videoBitrate != converter->getVideoBitrate()) {
-                    ALOGI("setting video bitrate to %d bps", videoBitrate);
-
-                    converter->setVideoBitrate(videoBitrate);
-                }
-            }
-        }
-
-        sp<RepeaterSource> repeaterSource = videoTrack->repeaterSource();
-        if (repeaterSource != NULL) {
-            double rateHz =
-                Converter::GetInt32Property(
-                        "media.wfd.video-framerate", -1);
-
-            char val[PROPERTY_VALUE_MAX];
-            if (rateHz < 0.0
-                    && property_get("media.wfd.video-framerate", val, NULL)
-                    && !strcasecmp("adaptive", val)) {
-                 rateHz = repeaterSource->getFrameRate();
-
-                if (avgLatencyUs > 300000ll) {
-                    rateHz *= 0.9;
-                } else if (avgLatencyUs < 200000ll) {
-                    rateHz *= 1.1;
-                }
-            }
-
-            if (rateHz > 0) {
-                if (rateHz < 5.0) {
-                    rateHz = 5.0;
-                } else if (rateHz > 30.0) {
-                    rateHz = 30.0;
-                }
-
-                if (rateHz != repeaterSource->getFrameRate()) {
-                    ALOGI("setting frame rate to %.2f Hz", rateHz);
-
-                    repeaterSource->setFrameRate(rateHz);
-                }
-            }
-        }
-    }
-}
-
 status_t WifiDisplaySource::PlaybackSession::setupMediaPacketizer(
         bool enableAudio, bool enableVideo) {
     DataSource::RegisterDefaultSniffers();
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 4a49811..2b5bee9 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -23,7 +23,6 @@
 #include "Parameters.h"
 #include "ParsedMessage.h"
 #include "rtp/RTPSender.h"
-#include "TimeSyncer.h"
 
 #include <binder/IServiceManager.h>
 #include <gui/IGraphicBufferProducer.h>
@@ -165,14 +164,6 @@
                 } else {
                     err = -EINVAL;
                 }
-            }
-
-            if (err == OK) {
-                sp<AMessage> notify = new AMessage(kWhatTimeSyncerNotify, id());
-                mTimeSyncer = new TimeSyncer(mNetSession, notify);
-                looper()->registerHandler(mTimeSyncer);
-
-                mTimeSyncer->startServer(8123);
 
                 mState = AWAITING_CLIENT_CONNECTION;
             }
@@ -548,11 +539,6 @@
             break;
         }
 
-        case kWhatTimeSyncerNotify:
-        {
-            break;
-        }
-
         default:
             TRESPASS();
     }
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 3efa0b4..44d3e4d 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -30,7 +30,6 @@
 struct IHDCP;
 struct IRemoteDisplayClient;
 struct ParsedMessage;
-struct TimeSyncer;
 
 // Represents the RTSP server acting as a wifi display source.
 // Manages incoming connections, sets up Playback sessions as necessary.
@@ -83,7 +82,6 @@
         kWhatHDCPNotify,
         kWhatFinishStop2,
         kWhatTeardownTriggerTimedOut,
-        kWhatTimeSyncerNotify,
     };
 
     struct ResponseID {
@@ -120,7 +118,6 @@
     sp<ANetworkSession> mNetSession;
     sp<IRemoteDisplayClient> mClient;
     AString mMediaPath;
-    sp<TimeSyncer> mTimeSyncer;
     struct in_addr mInterfaceAddr;
     int32_t mSessionID;
 
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 9fee4d0..c947765 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -18,7 +18,6 @@
 #define LOG_TAG "wfd"
 #include <utils/Log.h>
 
-#include "sink/WifiDisplaySink.h"
 #include "source/WifiDisplaySource.h"
 
 #include <binder/ProcessState.h>
@@ -39,12 +38,8 @@
 static void usage(const char *me) {
     fprintf(stderr,
             "usage:\n"
-            "           %s -c host[:port]\tconnect to wifi source\n"
-            "               -u uri        \tconnect to an rtsp uri\n"
-            "               -l ip[:port] \tlisten on the specified port "
-            "               -f(ilename)  \tstream media "
-            "(create a sink)\n"
-            "               -s(pecial)   \trun in 'special' mode\n",
+            "           %s -l iface[:port]\tcreate a wifi display source\n"
+            "               -f(ilename)  \tstream media\n",
             me);
 }
 
@@ -214,48 +209,14 @@
 
     DataSource::RegisterDefaultSniffers();
 
-    AString connectToHost;
-    int32_t connectToPort = -1;
-    AString uri;
-
     AString listenOnAddr;
     int32_t listenOnPort = -1;
 
     AString path;
 
-    bool specialMode = false;
-
     int res;
-    while ((res = getopt(argc, argv, "hc:l:u:f:s")) >= 0) {
+    while ((res = getopt(argc, argv, "hl:f:")) >= 0) {
         switch (res) {
-            case 'c':
-            {
-                const char *colonPos = strrchr(optarg, ':');
-
-                if (colonPos == NULL) {
-                    connectToHost = optarg;
-                    connectToPort = WifiDisplaySource::kWifiDisplayDefaultPort;
-                } else {
-                    connectToHost.setTo(optarg, colonPos - optarg);
-
-                    char *end;
-                    connectToPort = strtol(colonPos + 1, &end, 10);
-
-                    if (*end != '\0' || end == colonPos + 1
-                            || connectToPort < 1 || connectToPort > 65535) {
-                        fprintf(stderr, "Illegal port specified.\n");
-                        exit(1);
-                    }
-                }
-                break;
-            }
-
-            case 'u':
-            {
-                uri = optarg;
-                break;
-            }
-
             case 'f':
             {
                 path = optarg;
@@ -284,12 +245,6 @@
                 break;
             }
 
-            case 's':
-            {
-                specialMode = true;
-                break;
-            }
-
             case '?':
             case 'h':
             default:
@@ -298,13 +253,6 @@
         }
     }
 
-    if (connectToPort >= 0 && listenOnPort >= 0) {
-        fprintf(stderr,
-                "You can connect to a source or create one, "
-                "but not both at the same time.\n");
-        exit(1);
-    }
-
     if (listenOnPort >= 0) {
         if (path.empty()) {
             createSource(listenOnAddr, listenOnPort);
@@ -315,72 +263,7 @@
         exit(0);
     }
 
-    if (connectToPort < 0 && uri.empty()) {
-        fprintf(stderr,
-                "You need to select either source host or uri.\n");
-
-        exit(1);
-    }
-
-    if (connectToPort >= 0 && !uri.empty()) {
-        fprintf(stderr,
-                "You need to either connect to a wfd host or an rtsp url, "
-                "not both.\n");
-        exit(1);
-    }
-
-    sp<SurfaceComposerClient> composerClient = new SurfaceComposerClient;
-    CHECK_EQ(composerClient->initCheck(), (status_t)OK);
-
-    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
-            ISurfaceComposer::eDisplayIdMain));
-    DisplayInfo info;
-    SurfaceComposerClient::getDisplayInfo(display, &info);
-    ssize_t displayWidth = info.w;
-    ssize_t displayHeight = info.h;
-
-    ALOGV("display is %d x %d\n", displayWidth, displayHeight);
-
-    sp<SurfaceControl> control =
-        composerClient->createSurface(
-                String8("A Surface"),
-                displayWidth,
-                displayHeight,
-                PIXEL_FORMAT_RGB_565,
-                0);
-
-    CHECK(control != NULL);
-    CHECK(control->isValid());
-
-    SurfaceComposerClient::openGlobalTransaction();
-    CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
-    CHECK_EQ(control->show(), (status_t)OK);
-    SurfaceComposerClient::closeGlobalTransaction();
-
-    sp<Surface> surface = control->getSurface();
-    CHECK(surface != NULL);
-
-    sp<ANetworkSession> session = new ANetworkSession;
-    session->start();
-
-    sp<ALooper> looper = new ALooper;
-
-    sp<WifiDisplaySink> sink = new WifiDisplaySink(
-            specialMode ? WifiDisplaySink::FLAG_SPECIAL_MODE : 0 /* flags */,
-            session,
-            surface->getIGraphicBufferProducer());
-
-    looper->registerHandler(sink);
-
-    if (connectToPort >= 0) {
-        sink->start(connectToHost.c_str(), connectToPort);
-    } else {
-        sink->start(uri.c_str());
-    }
-
-    looper->start(true /* runOnCallingThread */);
-
-    composerClient->dispose();
+    usage(argv[0]);
 
     return 0;
 }
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index a6ab4f8..5ac3129 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1415,6 +1415,9 @@
         // since client and server are in the same process,
         // the buffer has the same virtual address on both sides
         mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize);
+        mClientProxy->setVolumeLR((uint32_t(uint16_t(0x1000)) << 16) | uint16_t(0x1000));
+        mClientProxy->setSendLevel(0.0);
+        mClientProxy->setSampleRate(sampleRate);
     } else {
         ALOGW("Error creating output track on thread %p", playbackThread);
     }
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 9421a77..eae7461 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -135,6 +135,7 @@
 
 Camera2Client::~Camera2Client() {
     ATRACE_CALL();
+    ALOGV("~Camera2Client");
 
     mDestructionStarted = true;
 
@@ -369,6 +370,12 @@
 
     ALOGV("Camera %d: Shutting down", mCameraId);
 
+    /**
+     * disconnect() cannot call any methods that might need to promote a
+     * wp<Camera2Client>, since disconnect can be called from the destructor, at
+     * which point all such promotions will fail.
+     */
+
     stopPreviewL();
 
     {
@@ -538,7 +545,12 @@
             break;
         case Parameters::PREVIEW:
             // Already running preview - need to stop and create a new stream
-            mStreamingProcessor->stopStream();
+            res = stopStream();
+            if (res != OK) {
+                ALOGE("%s: Unable to stop preview to swap windows: %s (%d)",
+                        __FUNCTION__, strerror(-res), res);
+                return res;
+            }
             state = Parameters::WAITING_FOR_PREVIEW_WINDOW;
             break;
     }
@@ -745,7 +757,11 @@
             // no break
         case Parameters::RECORD:
         case Parameters::PREVIEW:
-            mStreamingProcessor->stopStream();
+            res = stopStream();
+            if (res != OK) {
+                ALOGE("%s: Camera %d: Can't stop streaming: %s (%d)",
+                        __FUNCTION__, mCameraId, strerror(-res), res);
+            }
             res = mDevice->waitUntilDrained();
             if (res != OK) {
                 ALOGE("%s: Camera %d: Waiting to stop streaming failed: %s (%d)",
diff --git a/services/camera/libcameraservice/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 946cdba..77df152 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -1133,7 +1133,8 @@
 status_t Camera2Device::StreamAdapter::release() {
     ATRACE_CALL();
     status_t res;
-    ALOGV("%s: Releasing stream %d", __FUNCTION__, mId);
+    ALOGV("%s: Releasing stream %d (%d x %d, format %d)", __FUNCTION__, mId,
+            mWidth, mHeight, mFormat);
     if (mState >= ALLOCATED) {
         res = mHal2Device->ops->release_stream(mHal2Device, mId);
         if (res != OK) {
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 2db5224..cdeb92e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -793,6 +793,7 @@
 
 // tear down the client
 CameraService::Client::~Client() {
+    ALOGV("~Client");
     mDestructionStarted = true;
 
     mCameraService->releaseSound();
@@ -820,10 +821,12 @@
 }
 
 CameraService::BasicClient::~BasicClient() {
+    ALOGV("~BasicClient");
     mDestructionStarted = true;
 }
 
 void CameraService::BasicClient::disconnect() {
+    ALOGV("BasicClient::disconnect");
     mCameraService->removeClientByRemote(mRemoteBinder);
     // client shouldn't be able to call into us anymore
     mClientPid = 0;
@@ -922,6 +925,7 @@
 
 // NOTE: function is idempotent
 void CameraService::Client::disconnect() {
+    ALOGV("Client::disconnect");
     BasicClient::disconnect();
     mCameraService->setCameraFree(mCameraId);
     mCameraService->updateStatus(ICameraServiceListener::STATUS_PRESENT,
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
index 30c14ef..dd37283 100644
--- a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
@@ -30,9 +30,11 @@
 namespace android {
 namespace camera2 {
 
-CallbackProcessor::CallbackProcessor(wp<Camera2Client> client):
+CallbackProcessor::CallbackProcessor(sp<Camera2Client> client):
         Thread(false),
         mClient(client),
+        mDevice(client->getCameraDevice()),
+        mId(client->getCameraId()),
         mCallbackAvailable(false),
         mCallbackStreamId(NO_STREAM) {
 }
@@ -56,9 +58,11 @@
 
     Mutex::Autolock l(mInputMutex);
 
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return OK;
-    sp<CameraDeviceBase> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     if (mCallbackConsumer == 0) {
         // Create CPU buffer queue endpoint
@@ -76,7 +80,7 @@
                 &currentWidth, &currentHeight, &currentFormat);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying callback output stream info: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
@@ -87,11 +91,11 @@
             // assuming that all existing use of old callback stream is
             // completed.
             ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
-                __FUNCTION__, client->getCameraId(), mCallbackStreamId);
+                __FUNCTION__, mId, mCallbackStreamId);
             res = device->deleteStream(mCallbackStreamId);
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to delete old output stream "
-                        "for callbacks: %s (%d)", __FUNCTION__, client->getCameraId(),
+                        "for callbacks: %s (%d)", __FUNCTION__, mId,
                         strerror(-res), res);
                 return res;
             }
@@ -108,7 +112,7 @@
                 params.previewFormat, 0, &mCallbackStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for callbacks: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
@@ -119,15 +123,24 @@
 
 status_t CallbackProcessor::deleteStream() {
     ATRACE_CALL();
+    sp<CameraDeviceBase> device;
 
-    Mutex::Autolock l(mInputMutex);
+    {
+        Mutex::Autolock l(mInputMutex);
 
-    if (mCallbackStreamId != NO_STREAM) {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return OK;
-        sp<CameraDeviceBase> device = client->getCameraDevice();
+        if (mCallbackStreamId == NO_STREAM) {
+            return OK;
+        }
+        device = mDevice.promote();
+        if (device == 0) {
+            ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+            return INVALID_OPERATION;
+        }
+    }
+    device->deleteStream(mCallbackStreamId);
 
-        device->deleteStream(mCallbackStreamId);
+    {
+        Mutex::Autolock l(mInputMutex);
 
         mCallbackHeap.clear();
         mCallbackWindow.clear();
@@ -161,13 +174,32 @@
 
     do {
         sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        res = processNewCallback(client);
+        if (client == 0) {
+            res = discardNewCallback();
+        } else {
+            res = processNewCallback(client);
+        }
     } while (res == OK);
 
     return true;
 }
 
+status_t CallbackProcessor::discardNewCallback() {
+    ATRACE_CALL();
+    status_t res;
+    CpuConsumer::LockedBuffer imgBuffer;
+    res = mCallbackConsumer->lockNextBuffer(&imgBuffer);
+    if (res != OK) {
+        if (res != BAD_VALUE) {
+            ALOGE("%s: Camera %d: Error receiving next callback buffer: "
+                    "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
+        }
+        return res;
+    }
+    mCallbackConsumer->unlockBuffer(imgBuffer);
+    return OK;
+}
+
 status_t CallbackProcessor::processNewCallback(sp<Camera2Client> &client) {
     ATRACE_CALL();
     status_t res;
@@ -181,12 +213,12 @@
     if (res != OK) {
         if (res != BAD_VALUE) {
             ALOGE("%s: Camera %d: Error receiving next callback buffer: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                    "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
         }
         return res;
     }
     ALOGV("%s: Camera %d: Preview callback available", __FUNCTION__,
-            client->getCameraId());
+            mId);
 
     {
         SharedParameters::Lock l(client->getParameters());
@@ -195,7 +227,7 @@
                 && l.mParameters.state != Parameters::RECORD
                 && l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
             ALOGV("%s: Camera %d: No longer streaming",
-                    __FUNCTION__, client->getCameraId());
+                    __FUNCTION__, mId);
             mCallbackConsumer->unlockBuffer(imgBuffer);
             return OK;
         }
@@ -216,7 +248,7 @@
 
         if (imgBuffer.format != l.mParameters.previewFormat) {
             ALOGE("%s: Camera %d: Unexpected format for callback: "
-                    "%x, expected %x", __FUNCTION__, client->getCameraId(),
+                    "%x, expected %x", __FUNCTION__, mId,
                     imgBuffer.format, l.mParameters.previewFormat);
             mCallbackConsumer->unlockBuffer(imgBuffer);
             return INVALID_OPERATION;
@@ -241,7 +273,7 @@
                 "Camera2Client::CallbackHeap");
         if (mCallbackHeap->mHeap->getSize() == 0) {
             ALOGE("%s: Camera %d: Unable to allocate memory for callbacks",
-                    __FUNCTION__, client->getCameraId());
+                    __FUNCTION__, mId);
             mCallbackConsumer->unlockBuffer(imgBuffer);
             return INVALID_OPERATION;
         }
@@ -252,7 +284,7 @@
 
     if (mCallbackHeapFree == 0) {
         ALOGE("%s: Camera %d: No free callback buffers, dropping frame",
-                __FUNCTION__, client->getCameraId());
+                __FUNCTION__, mId);
         mCallbackConsumer->unlockBuffer(imgBuffer);
         return OK;
     }
@@ -282,7 +314,7 @@
             l(client->mSharedCameraCallbacks);
         if (l.mRemoteCallback != 0) {
             ALOGV("%s: Camera %d: Invoking client data callback",
-                    __FUNCTION__, client->getCameraId());
+                    __FUNCTION__, mId);
             l.mRemoteCallback->dataCallback(CAMERA_MSG_PREVIEW_FRAME,
                     mCallbackHeap->mBuffers[heapIdx], NULL);
         }
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.h b/services/camera/libcameraservice/camera2/CallbackProcessor.h
index e68bb75..1c40a03 100644
--- a/services/camera/libcameraservice/camera2/CallbackProcessor.h
+++ b/services/camera/libcameraservice/camera2/CallbackProcessor.h
@@ -30,6 +30,7 @@
 namespace android {
 
 class Camera2Client;
+class CameraDeviceBase;
 
 namespace camera2 {
 
@@ -39,7 +40,7 @@
 class CallbackProcessor:
             public Thread, public CpuConsumer::FrameAvailableListener {
   public:
-    CallbackProcessor(wp<Camera2Client> client);
+    CallbackProcessor(sp<Camera2Client> client);
     ~CallbackProcessor();
 
     void onFrameAvailable();
@@ -52,6 +53,8 @@
   private:
     static const nsecs_t kWaitDuration = 10000000; // 10 ms
     wp<Camera2Client> mClient;
+    wp<CameraDeviceBase> mDevice;
+    int mId;
 
     mutable Mutex mInputMutex;
     bool mCallbackAvailable;
@@ -72,7 +75,8 @@
     virtual bool threadLoop();
 
     status_t processNewCallback(sp<Camera2Client> &client);
-
+    // Used when shutting down
+    status_t discardNewCallback();
 };
 
 
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.cpp b/services/camera/libcameraservice/camera2/JpegProcessor.cpp
index 286fac4..01d7f9c 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/JpegProcessor.cpp
@@ -35,11 +35,12 @@
 namespace camera2 {
 
 JpegProcessor::JpegProcessor(
-    wp<Camera2Client> client,
+    sp<Camera2Client> client,
     wp<CaptureSequencer> sequencer):
         Thread(false),
-        mClient(client),
+        mDevice(client->getCameraDevice()),
         mSequencer(sequencer),
+        mId(client->getCameraId()),
         mCaptureAvailable(false),
         mCaptureStreamId(NO_STREAM) {
 }
@@ -64,16 +65,18 @@
 
     Mutex::Autolock l(mInputMutex);
 
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return OK;
-    sp<CameraDeviceBase> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     // Find out buffer size for JPEG
     camera_metadata_ro_entry_t maxJpegSize =
             params.staticInfo(ANDROID_JPEG_MAX_SIZE);
     if (maxJpegSize.count == 0) {
         ALOGE("%s: Camera %d: Can't find ANDROID_JPEG_MAX_SIZE!",
-                __FUNCTION__, client->getCameraId());
+                __FUNCTION__, mId);
         return INVALID_OPERATION;
     }
 
@@ -89,7 +92,7 @@
                                        "Camera2Client::CaptureHeap");
         if (mCaptureHeap->getSize() == 0) {
             ALOGE("%s: Camera %d: Unable to allocate memory for capture",
-                    __FUNCTION__, client->getCameraId());
+                    __FUNCTION__, mId);
             return NO_MEMORY;
         }
     }
@@ -102,18 +105,18 @@
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying capture output stream info: "
                     "%s (%d)", __FUNCTION__,
-                    client->getCameraId(), strerror(-res), res);
+                    mId, strerror(-res), res);
             return res;
         }
         if (currentWidth != (uint32_t)params.pictureWidth ||
                 currentHeight != (uint32_t)params.pictureHeight) {
             ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
-                __FUNCTION__, client->getCameraId(), mCaptureStreamId);
+                __FUNCTION__, mId, mCaptureStreamId);
             res = device->deleteStream(mCaptureStreamId);
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to delete old output stream "
                         "for capture: %s (%d)", __FUNCTION__,
-                        client->getCameraId(), strerror(-res), res);
+                        mId, strerror(-res), res);
                 return res;
             }
             mCaptureStreamId = NO_STREAM;
@@ -128,7 +131,7 @@
                 &mCaptureStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for capture: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
@@ -143,9 +146,11 @@
     Mutex::Autolock l(mInputMutex);
 
     if (mCaptureStreamId != NO_STREAM) {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return OK;
-        sp<CameraDeviceBase> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = mDevice.promote();
+        if (device == 0) {
+            ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+            return INVALID_OPERATION;
+        }
 
         device->deleteStream(mCaptureStreamId);
 
@@ -180,15 +185,13 @@
     }
 
     do {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        res = processNewCapture(client);
+        res = processNewCapture();
     } while (res == OK);
 
     return true;
 }
 
-status_t JpegProcessor::processNewCapture(sp<Camera2Client> &client) {
+status_t JpegProcessor::processNewCapture() {
     ATRACE_CALL();
     status_t res;
     sp<Camera2Heap> captureHeap;
@@ -200,17 +203,17 @@
         if (res != BAD_VALUE) {
             ALOGE("%s: Camera %d: Error receiving still image buffer: "
                     "%s (%d)", __FUNCTION__,
-                    client->getCameraId(), strerror(-res), res);
+                    mId, strerror(-res), res);
         }
         return res;
     }
 
     ALOGV("%s: Camera %d: Still capture available", __FUNCTION__,
-            client->getCameraId());
+            mId);
 
     if (imgBuffer.format != HAL_PIXEL_FORMAT_BLOB) {
         ALOGE("%s: Camera %d: Unexpected format for still image: "
-                "%x, expected %x", __FUNCTION__, client->getCameraId(),
+                "%x, expected %x", __FUNCTION__, mId,
                 imgBuffer.format,
                 HAL_PIXEL_FORMAT_BLOB);
         mCaptureConsumer->unlockBuffer(imgBuffer);
diff --git a/services/camera/libcameraservice/camera2/JpegProcessor.h b/services/camera/libcameraservice/camera2/JpegProcessor.h
index 74f4738..a38611c 100644
--- a/services/camera/libcameraservice/camera2/JpegProcessor.h
+++ b/services/camera/libcameraservice/camera2/JpegProcessor.h
@@ -29,6 +29,7 @@
 namespace android {
 
 class Camera2Client;
+class CameraDeviceBase;
 class MemoryHeapBase;
 
 namespace camera2 {
@@ -41,7 +42,7 @@
 class JpegProcessor:
             public Thread, public CpuConsumer::FrameAvailableListener {
   public:
-    JpegProcessor(wp<Camera2Client> client, wp<CaptureSequencer> sequencer);
+    JpegProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
     ~JpegProcessor();
 
     // CpuConsumer listener implementation
@@ -54,8 +55,9 @@
     void dump(int fd, const Vector<String16>& args) const;
   private:
     static const nsecs_t kWaitDuration = 10000000; // 10 ms
-    wp<Camera2Client> mClient;
+    wp<CameraDeviceBase> mDevice;
     wp<CaptureSequencer> mSequencer;
+    int mId;
 
     mutable Mutex mInputMutex;
     bool mCaptureAvailable;
@@ -72,7 +74,7 @@
 
     virtual bool threadLoop();
 
-    status_t processNewCapture(sp<Camera2Client> &client);
+    status_t processNewCapture();
     size_t findJpegSize(uint8_t* jpegBuffer, size_t maxSize);
 
 };
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
index fbc5b93..c36cf87 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
@@ -31,8 +31,10 @@
 namespace android {
 namespace camera2 {
 
-StreamingProcessor::StreamingProcessor(wp<Camera2Client> client):
+StreamingProcessor::StreamingProcessor(sp<Camera2Client> client):
         mClient(client),
+        mDevice(client->getCameraDevice()),
+        mId(client->getCameraId()),
         mActiveRequest(NONE),
         mPreviewRequestId(Camera2Client::kPreviewRequestIdStart),
         mPreviewStreamId(NO_STREAM),
@@ -40,7 +42,6 @@
         mRecordingStreamId(NO_STREAM),
         mRecordingHeapCount(kDefaultRecordingHeapCount)
 {
-
 }
 
 StreamingProcessor::~StreamingProcessor() {
@@ -70,16 +71,19 @@
 status_t StreamingProcessor::updatePreviewRequest(const Parameters &params) {
     ATRACE_CALL();
     status_t res;
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return INVALID_OPERATION;
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     Mutex::Autolock m(mMutex);
     if (mPreviewRequest.entryCount() == 0) {
-        res = client->getCameraDevice()->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
+        res = device->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,
                 &mPreviewRequest);
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to create default preview request: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                    "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
             return res;
         }
     }
@@ -87,7 +91,7 @@
     res = params.updateRequest(&mPreviewRequest);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update common entries of preview "
-                "request: %s (%d)", __FUNCTION__, client->getCameraId(),
+                "request: %s (%d)", __FUNCTION__, mId,
                 strerror(-res), res);
         return res;
     }
@@ -96,7 +100,7 @@
             &mPreviewRequestId, 1);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update request id for preview: %s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
 
@@ -108,9 +112,11 @@
     Mutex::Autolock m(mMutex);
 
     status_t res;
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return INVALID_OPERATION;
-    sp<CameraDeviceBase> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     if (mPreviewStreamId != NO_STREAM) {
         // Check if stream parameters have to change
@@ -119,24 +125,24 @@
                 &currentWidth, &currentHeight, 0);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying preview stream info: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                    "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
             return res;
         }
         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__, client->getCameraId(), currentWidth, currentHeight,
+                    __FUNCTION__, mId, currentWidth, currentHeight,
                     params.previewWidth, params.previewHeight);
             res = device->waitUntilDrained();
             if (res != OK) {
                 ALOGE("%s: Camera %d: Error waiting for preview to drain: "
-                        "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                        "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
                 return res;
             }
             res = device->deleteStream(mPreviewStreamId);
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to delete old output stream "
-                        "for preview: %s (%d)", __FUNCTION__, client->getCameraId(),
+                        "for preview: %s (%d)", __FUNCTION__, mId,
                         strerror(-res), res);
                 return res;
             }
@@ -151,7 +157,7 @@
                 &mPreviewStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to create preview stream: %s (%d)",
-                    __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                    __FUNCTION__, mId, strerror(-res), res);
             return res;
         }
     }
@@ -160,7 +166,7 @@
             params.previewTransform);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to set preview stream transform: "
-                "%s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                "%s (%d)", __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
 
@@ -174,12 +180,14 @@
     Mutex::Autolock m(mMutex);
 
     if (mPreviewStreamId != NO_STREAM) {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return INVALID_OPERATION;
-        sp<CameraDeviceBase> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = mDevice.promote();
+        if (device == 0) {
+            ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+            return INVALID_OPERATION;
+        }
 
         ALOGV("%s: for cameraId %d on streamId %d",
-            __FUNCTION__, client->getCameraId(), mPreviewStreamId);
+            __FUNCTION__, mId, mPreviewStreamId);
 
         res = device->waitUntilDrained();
         if (res != OK) {
@@ -206,11 +214,9 @@
 status_t StreamingProcessor::setRecordingBufferCount(size_t count) {
     ATRACE_CALL();
     // 32 is the current upper limit on the video buffer count for BufferQueue
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return INVALID_OPERATION;
     if (count > 32) {
         ALOGE("%s: Camera %d: Error setting %d as video buffer count value",
-                __FUNCTION__, client->getCameraId(), count);
+                __FUNCTION__, mId, count);
         return BAD_VALUE;
     }
 
@@ -233,15 +239,18 @@
     status_t res;
     Mutex::Autolock m(mMutex);
 
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return INVALID_OPERATION;
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     if (mRecordingRequest.entryCount() == 0) {
-        res = client->getCameraDevice()->createDefaultRequest(CAMERA2_TEMPLATE_VIDEO_RECORD,
+        res = device->createDefaultRequest(CAMERA2_TEMPLATE_VIDEO_RECORD,
                 &mRecordingRequest);
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to create default recording request:"
-                    " %s (%d)", __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                    " %s (%d)", __FUNCTION__, mId, strerror(-res), res);
             return res;
         }
     }
@@ -249,7 +258,7 @@
     res = params.updateRequest(&mRecordingRequest);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update common entries of recording "
-                "request: %s (%d)", __FUNCTION__, client->getCameraId(),
+                "request: %s (%d)", __FUNCTION__, mId,
                 strerror(-res), res);
         return res;
     }
@@ -258,7 +267,7 @@
             &mRecordingRequestId, 1);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to update request id for request: %s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
 
@@ -270,9 +279,11 @@
     status_t res;
     Mutex::Autolock m(mMutex);
 
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return INVALID_OPERATION;
-    sp<CameraDeviceBase> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     if (mRecordingConsumer == 0) {
         // Create CPU buffer queue endpoint. We need one more buffer here so that we can
@@ -296,7 +307,7 @@
                 &currentWidth, &currentHeight, 0);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying recording output stream info: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
@@ -307,7 +318,7 @@
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to delete old output stream "
                         "for recording: %s (%d)", __FUNCTION__,
-                        client->getCameraId(), strerror(-res), res);
+                        mId, strerror(-res), res);
                 return res;
             }
             mRecordingStreamId = NO_STREAM;
@@ -321,7 +332,7 @@
                 CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, 0, &mRecordingStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for recording: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
@@ -337,9 +348,11 @@
     Mutex::Autolock m(mMutex);
 
     if (mRecordingStreamId != NO_STREAM) {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return INVALID_OPERATION;
-        sp<CameraDeviceBase> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = mDevice.promote();
+        if (device == 0) {
+            ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+            return INVALID_OPERATION;
+        }
 
         res = device->waitUntilDrained();
         if (res != OK) {
@@ -369,10 +382,13 @@
 
     if (type == NONE) return INVALID_OPERATION;
 
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return INVALID_OPERATION;
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
-    ALOGV("%s: Camera %d: type = %d", __FUNCTION__, client->getCameraId(), type);
+    ALOGV("%s: Camera %d: type = %d", __FUNCTION__, mId, type);
 
     Mutex::Autolock m(mMutex);
 
@@ -384,22 +400,22 @@
         outputStreams);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to set up preview request: %s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
 
     res = request.sort();
     if (res != OK) {
         ALOGE("%s: Camera %d: Error sorting preview request: %s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
 
-    res = client->getCameraDevice()->setStreamingRequest(request);
+    res = device->setStreamingRequest(request);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to set preview request to start preview: "
                 "%s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
     mActiveRequest = type;
@@ -413,16 +429,19 @@
 
     Mutex::Autolock m(mMutex);
 
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return INVALID_OPERATION;
-    sp<CameraDeviceBase> device = client->getCameraDevice();
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     res = device->clearStreamingRequest();
     if (res != OK) {
         ALOGE("%s: Camera %d: Can't clear stream request: %s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                __FUNCTION__, mId, strerror(-res), res);
         return res;
     }
+
     mActiveRequest = NONE;
 
     return OK;
@@ -466,7 +485,18 @@
     nsecs_t timestamp;
 
     sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return;
+    if (client == 0) {
+        // Discard frames during shutdown
+        BufferItemConsumer::BufferItem imgBuffer;
+        res = mRecordingConsumer->acquireBuffer(&imgBuffer);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
+                    __FUNCTION__, mId, strerror(-res), res);
+            return;
+        }
+        mRecordingConsumer->releaseBuffer(imgBuffer);
+        return;
+    }
 
     {
         /* acquire SharedParameters before mMutex so we don't dead lock
@@ -477,7 +507,7 @@
         res = mRecordingConsumer->acquireBuffer(&imgBuffer);
         if (res != OK) {
             ALOGE("%s: Camera %d: Error receiving recording buffer: %s (%d)",
-                    __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                    __FUNCTION__, mId, strerror(-res), res);
             return;
         }
         timestamp = imgBuffer.mTimestamp;
@@ -490,7 +520,7 @@
                 l.mParameters.state != Parameters::VIDEO_SNAPSHOT) {
             ALOGV("%s: Camera %d: Discarding recording image buffers "
                     "received after recording done", __FUNCTION__,
-                    client->getCameraId());
+                    mId);
             mRecordingConsumer->releaseBuffer(imgBuffer);
             return;
         }
@@ -498,14 +528,14 @@
         if (mRecordingHeap == 0) {
             const size_t bufferSize = 4 + sizeof(buffer_handle_t);
             ALOGV("%s: Camera %d: Creating recording heap with %d buffers of "
-                    "size %d bytes", __FUNCTION__, client->getCameraId(),
+                    "size %d bytes", __FUNCTION__, mId,
                     mRecordingHeapCount, bufferSize);
 
             mRecordingHeap = new Camera2Heap(bufferSize, mRecordingHeapCount,
                     "Camera2Client::RecordingHeap");
             if (mRecordingHeap->mHeap->getSize() == 0) {
                 ALOGE("%s: Camera %d: Unable to allocate memory for recording",
-                        __FUNCTION__, client->getCameraId());
+                        __FUNCTION__, mId);
                 mRecordingConsumer->releaseBuffer(imgBuffer);
                 return;
             }
@@ -513,7 +543,7 @@
                 if (mRecordingBuffers[i].mBuf !=
                         BufferItemConsumer::INVALID_BUFFER_SLOT) {
                     ALOGE("%s: Camera %d: Non-empty recording buffers list!",
-                            __FUNCTION__, client->getCameraId());
+                            __FUNCTION__, mId);
                 }
             }
             mRecordingBuffers.clear();
@@ -526,7 +556,7 @@
 
         if ( mRecordingHeapFree == 0) {
             ALOGE("%s: Camera %d: No free recording buffers, dropping frame",
-                    __FUNCTION__, client->getCameraId());
+                    __FUNCTION__, mId);
             mRecordingConsumer->releaseBuffer(imgBuffer);
             return;
         }
@@ -536,7 +566,7 @@
         mRecordingHeapFree--;
 
         ALOGV("%s: Camera %d: Timestamp %lld",
-                __FUNCTION__, client->getCameraId(), timestamp);
+                __FUNCTION__, mId, timestamp);
 
         ssize_t offset;
         size_t size;
@@ -549,7 +579,7 @@
         *((uint32_t*)data) = type;
         *((buffer_handle_t*)(data + 4)) = imgBuffer.mGraphicBuffer->handle;
         ALOGV("%s: Camera %d: Sending out buffer_handle_t %p",
-                __FUNCTION__, client->getCameraId(),
+                __FUNCTION__, mId,
                 imgBuffer.mGraphicBuffer->handle);
         mRecordingBuffers.replaceAt(imgBuffer, heapIdx);
         recordingHeap = mRecordingHeap;
@@ -568,9 +598,6 @@
     ATRACE_CALL();
     status_t res;
 
-    sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return;
-
     Mutex::Autolock m(mMutex);
     // Make sure this is for the current heap
     ssize_t offset;
@@ -578,7 +605,7 @@
     sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
     if (heap->getHeapID() != mRecordingHeap->mHeap->getHeapID()) {
         ALOGW("%s: Camera %d: Mismatched heap ID, ignoring release "
-                "(got %x, expected %x)", __FUNCTION__, client->getCameraId(),
+                "(got %x, expected %x)", __FUNCTION__, mId,
                 heap->getHeapID(), mRecordingHeap->mHeap->getHeapID());
         return;
     }
@@ -586,7 +613,7 @@
     uint32_t type = *(uint32_t*)data;
     if (type != kMetadataBufferTypeGrallocSource) {
         ALOGE("%s: Camera %d: Recording frame type invalid (got %x, expected %x)",
-                __FUNCTION__, client->getCameraId(), type,
+                __FUNCTION__, mId, type,
                 kMetadataBufferTypeGrallocSource);
         return;
     }
@@ -606,19 +633,19 @@
     }
     if (itemIndex == mRecordingBuffers.size()) {
         ALOGE("%s: Camera %d: Can't find buffer_handle_t %p in list of "
-                "outstanding buffers", __FUNCTION__, client->getCameraId(),
+                "outstanding buffers", __FUNCTION__, mId,
                 imgHandle);
         return;
     }
 
     ALOGV("%s: Camera %d: Freeing buffer_handle_t %p", __FUNCTION__,
-            client->getCameraId(), imgHandle);
+            mId, imgHandle);
 
     res = mRecordingConsumer->releaseBuffer(mRecordingBuffers[itemIndex]);
     if (res != OK) {
         ALOGE("%s: Camera %d: Unable to free recording frame "
                 "(buffer_handle_t: %p): %s (%d)", __FUNCTION__,
-                client->getCameraId(), imgHandle, strerror(-res), res);
+                mId, imgHandle, strerror(-res), res);
         return;
     }
     mRecordingBuffers.replaceAt(itemIndex);
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.h b/services/camera/libcameraservice/camera2/StreamingProcessor.h
index e5732ad..643114e 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.h
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.h
@@ -27,6 +27,7 @@
 namespace android {
 
 class Camera2Client;
+class CameraDeviceBase;
 class IMemory;
 
 namespace camera2 {
@@ -38,7 +39,7 @@
  */
 class StreamingProcessor: public BufferItemConsumer::FrameAvailableListener {
   public:
-    StreamingProcessor(wp<Camera2Client> client);
+    StreamingProcessor(sp<Camera2Client> client);
     ~StreamingProcessor();
 
     status_t setPreviewWindow(sp<ANativeWindow> window);
@@ -86,6 +87,8 @@
     };
 
     wp<Camera2Client> mClient;
+    wp<CameraDeviceBase> mDevice;
+    int mId;
 
     StreamType mActiveRequest;
 
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.cpp b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
index 769d9bd..2c12fb0 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ZslProcessor.cpp
@@ -38,12 +38,14 @@
 namespace camera2 {
 
 ZslProcessor::ZslProcessor(
-    wp<Camera2Client> client,
+    sp<Camera2Client> client,
     wp<CaptureSequencer> sequencer):
         Thread(false),
         mState(RUNNING),
         mClient(client),
+        mDevice(client->getCameraDevice()),
         mSequencer(sequencer),
+        mId(client->getCameraId()),
         mZslBufferAvailable(false),
         mZslStreamId(NO_STREAM),
         mZslReprocessStreamId(NO_STREAM),
@@ -69,7 +71,8 @@
     }
 }
 
-void ZslProcessor::onFrameAvailable(int32_t /*frameId*/, const CameraMetadata &frame) {
+void ZslProcessor::onFrameAvailable(int32_t /*frameId*/,
+        const CameraMetadata &frame) {
     Mutex::Autolock l(mInputMutex);
     camera_metadata_ro_entry_t entry;
     entry = frame.find(ANDROID_SENSOR_TIMESTAMP);
@@ -113,8 +116,15 @@
     Mutex::Autolock l(mInputMutex);
 
     sp<Camera2Client> client = mClient.promote();
-    if (client == 0) return OK;
-    sp<CameraDeviceBase> device = client->getCameraDevice();
+    if (client == 0) {
+        ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
+    sp<CameraDeviceBase> device = mDevice.promote();
+    if (device == 0) {
+        ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     if (mZslConsumer == 0) {
         // Create CPU buffer queue endpoint
@@ -136,7 +146,7 @@
         if (res != OK) {
             ALOGE("%s: Camera %d: Error querying capture output stream info: "
                     "%s (%d)", __FUNCTION__,
-                    client->getCameraId(), strerror(-res), res);
+                    mId, strerror(-res), res);
             return res;
         }
         if (currentWidth != (uint32_t)params.fastInfo.arrayWidth ||
@@ -145,16 +155,16 @@
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to delete old reprocess stream "
                         "for ZSL: %s (%d)", __FUNCTION__,
-                        client->getCameraId(), strerror(-res), res);
+                        mId, strerror(-res), res);
                 return res;
             }
             ALOGV("%s: Camera %d: Deleting stream %d since the buffer dimensions changed",
-                __FUNCTION__, client->getCameraId(), mZslStreamId);
+                __FUNCTION__, mId, mZslStreamId);
             res = device->deleteStream(mZslStreamId);
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to delete old output stream "
                         "for ZSL: %s (%d)", __FUNCTION__,
-                        client->getCameraId(), strerror(-res), res);
+                        mId, strerror(-res), res);
                 return res;
             }
             mZslStreamId = NO_STREAM;
@@ -173,7 +183,7 @@
                 &mZslStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create output stream for ZSL: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
@@ -181,7 +191,7 @@
                 &mZslReprocessStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Can't create reprocess stream for ZSL: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     strerror(-res), res);
             return res;
         }
@@ -200,14 +210,18 @@
     Mutex::Autolock l(mInputMutex);
 
     if (mZslStreamId != NO_STREAM) {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return OK;
-        sp<CameraDeviceBase> device = client->getCameraDevice();
+        sp<CameraDeviceBase> device = mDevice.promote();
+        if (device == 0) {
+            ALOGE("%s: Camera %d: Device does not exist", __FUNCTION__, mId);
+            return INVALID_OPERATION;
+        }
+
+        clearZslQueueLocked();
 
         res = device->deleteReprocessStream(mZslReprocessStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Cannot delete ZSL reprocessing stream %d: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     mZslReprocessStreamId, strerror(-res), res);
             return res;
         }
@@ -216,7 +230,7 @@
         res = device->deleteStream(mZslStreamId);
         if (res != OK) {
             ALOGE("%s: Camera %d: Cannot delete ZSL output stream %d: "
-                    "%s (%d)", __FUNCTION__, client->getCameraId(),
+                    "%s (%d)", __FUNCTION__, mId,
                     mZslStreamId, strerror(-res), res);
             return res;
         }
@@ -246,7 +260,10 @@
     status_t res;
     sp<Camera2Client> client = mClient.promote();
 
-    if (client == 0) return INVALID_OPERATION;
+    if (client == 0) {
+        ALOGE("%s: Camera %d: Client does not exist", __FUNCTION__, mId);
+        return INVALID_OPERATION;
+    }
 
     IF_ALOGV() {
         dumpZslQueue(-1);
@@ -309,7 +326,7 @@
         if (res != OK) {
             ALOGE("%s: Camera %d: Unable to stop preview for ZSL capture: "
                 "%s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                __FUNCTION__, mId, strerror(-res), res);
             return INVALID_OPERATION;
         }
         // TODO: have push-and-clear be atomic
@@ -328,7 +345,7 @@
             if (res != OK) {
                 ALOGE("%s: Camera %d: Unable to update JPEG entries of ZSL "
                         "capture request: %s (%d)", __FUNCTION__,
-                        client->getCameraId(),
+                        mId,
                         strerror(-res), res);
                 return res;
             }
@@ -397,26 +414,29 @@
     }
 
     do {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        res = processNewZslBuffer(client);
+        res = processNewZslBuffer();
     } while (res == OK);
 
     return true;
 }
 
-status_t ZslProcessor::processNewZslBuffer(sp<Camera2Client> &client) {
+status_t ZslProcessor::processNewZslBuffer() {
     ATRACE_CALL();
     status_t res;
-
+    sp<BufferItemConsumer> zslConsumer;
+    {
+        Mutex::Autolock l(mInputMutex);
+        if (mZslConsumer == 0) return OK;
+        zslConsumer = mZslConsumer;
+    }
     ALOGVV("Trying to get next buffer");
     BufferItemConsumer::BufferItem item;
-    res = mZslConsumer->acquireBuffer(&item);
+    res = zslConsumer->acquireBuffer(&item);
     if (res != OK) {
         if (res != BufferItemConsumer::NO_BUFFER_AVAILABLE) {
             ALOGE("%s: Camera %d: Error receiving ZSL image buffer: "
                     "%s (%d)", __FUNCTION__,
-                    client->getCameraId(), strerror(-res), res);
+                    mId, strerror(-res), res);
         } else {
             ALOGVV("  No buffer");
         }
@@ -427,7 +447,7 @@
 
     if (mState == LOCKED) {
         ALOGVV("In capture, discarding new ZSL buffers");
-        mZslConsumer->releaseBuffer(item);
+        zslConsumer->releaseBuffer(item);
         return OK;
     }
 
@@ -435,7 +455,7 @@
 
     if ( (mZslQueueHead + 1) % kZslBufferDepth == mZslQueueTail) {
         ALOGVV("Releasing oldest buffer");
-        mZslConsumer->releaseBuffer(mZslQueue[mZslQueueTail].buffer);
+        zslConsumer->releaseBuffer(mZslQueue[mZslQueueTail].buffer);
         mZslQueue.replaceAt(mZslQueueTail);
         mZslQueueTail = (mZslQueueTail + 1) % kZslBufferDepth;
     }
diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.h b/services/camera/libcameraservice/camera2/ZslProcessor.h
index b2cf5b1..ee3bcd6 100644
--- a/services/camera/libcameraservice/camera2/ZslProcessor.h
+++ b/services/camera/libcameraservice/camera2/ZslProcessor.h
@@ -46,7 +46,7 @@
             virtual public FrameProcessor::FilteredListener,
             virtual public CameraDeviceBase::BufferReleasedListener {
   public:
-    ZslProcessor(wp<Camera2Client> client, wp<CaptureSequencer> sequencer);
+    ZslProcessor(sp<Camera2Client> client, wp<CaptureSequencer> sequencer);
     ~ZslProcessor();
 
     // From mZslConsumer
@@ -74,7 +74,9 @@
     } mState;
 
     wp<Camera2Client> mClient;
+    wp<CameraDeviceBase> mDevice;
     wp<CaptureSequencer> mSequencer;
+    int mId;
 
     mutable Mutex mInputMutex;
     bool mZslBufferAvailable;
@@ -109,7 +111,7 @@
 
     virtual bool threadLoop();
 
-    status_t processNewZslBuffer(sp<Camera2Client> &client);
+    status_t processNewZslBuffer();
 
     // Match up entries from frame list to buffers in ZSL queue
     void findMatchesLocked();