CameraService: Refactor Camera2Client to share a base with ProCameraClient

Change-Id: I249e2a0fc47ae84f29c9d9c4a223fba13da3ee66
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index d6ad889..8600735 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -11,6 +11,7 @@
     CameraClient.cpp \
     Camera2Client.cpp \
     ProCamera2Client.cpp \
+    Camera2ClientBase.cpp \
     CameraDeviceBase.cpp \
     Camera2Device.cpp \
     Camera3Device.cpp \
diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp
index 8295905..eb7a8d8 100644
--- a/services/camera/libcameraservice/Camera2Client.cpp
+++ b/services/camera/libcameraservice/Camera2Client.cpp
@@ -49,9 +49,8 @@
         uid_t clientUid,
         int servicePid,
         int deviceVersion):
-        Client(cameraService, cameraClient, clientPackageName,
+        Camera2ClientBase(cameraService, cameraClient, clientPackageName,
                 cameraId, cameraFacing, clientPid, clientUid, servicePid),
-        mSharedCameraClient(cameraClient),
         mParameters(cameraId, cameraFacing)
 {
     ATRACE_CALL();
@@ -76,15 +75,6 @@
     l.mParameters.state = Parameters::DISCONNECTED;
 }
 
-status_t Camera2Client::checkPid(const char* checkLocation) const {
-    int callingPid = getCallingPid();
-    if (callingPid == mClientPid) return NO_ERROR;
-
-    ALOGE("%s: attempt to use a locked camera from a different process"
-            " (old pid %d, new pid %d)", checkLocation, mClientPid, callingPid);
-    return PERMISSION_DENIED;
-}
-
 status_t Camera2Client::initialize(camera_module_t *module)
 {
     ATRACE_CALL();
@@ -173,7 +163,7 @@
     String8 result;
     result.appendFormat("Client2[%d] (%p) PID: %d, dump:\n",
             mCameraId,
-            getCameraClient()->asBinder().get(),
+            getRemoteCallback()->asBinder().get(),
             mClientPid);
     result.append("  State: ");
 #define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break;
@@ -376,25 +366,15 @@
 
     mZslProcessor->dump(fd, args);
 
-    result = "  Device dump:\n";
-    write(fd, result.string(), result.size());
-
-    status_t res = mDevice->dump(fd, args);
-    if (res != OK) {
-        result = String8::format("   Error dumping device: %s (%d)",
-                strerror(-res), res);
-        write(fd, result.string(), result.size());
-    }
-
+    return dumpDevice(fd, args);
 #undef CASE_APPEND_ENUM
-    return NO_ERROR;
 }
 
 // ICamera interface
 
 void Camera2Client::disconnect() {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     // Allow both client and the media server to disconnect at all times
     int callingPid = getCallingPid();
@@ -444,7 +424,7 @@
 status_t Camera2Client::connect(const sp<ICameraClient>& client) {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (mClientPid != 0 && getCallingPid() != mClientPid) {
         ALOGE("%s: Camera %d: Connection attempt from pid %d; "
@@ -455,8 +435,8 @@
 
     mClientPid = getCallingPid();
 
-    mCameraClient = client;
-    mSharedCameraClient = client;
+    mRemoteCallback = client;
+    mSharedCameraCallbacks = client;
 
     return OK;
 }
@@ -464,7 +444,7 @@
 status_t Camera2Client::lock() {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d",
             __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
 
@@ -485,7 +465,7 @@
 status_t Camera2Client::unlock() {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
             __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
 
@@ -497,8 +477,8 @@
             return INVALID_OPERATION;
         }
         mClientPid = 0;
-        mCameraClient.clear();
-        mSharedCameraClient.clear();
+        mRemoteCallback.clear();
+        mSharedCameraCallbacks.clear();
         return OK;
     }
 
@@ -511,7 +491,7 @@
         const sp<Surface>& surface) {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
@@ -529,7 +509,7 @@
         const sp<IGraphicBufferProducer>& bufferProducer) {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
@@ -598,7 +578,7 @@
 void Camera2Client::setPreviewCallbackFlag(int flag) {
     ATRACE_CALL();
     ALOGV("%s: Camera %d: Flag 0x%x", __FUNCTION__, mCameraId, flag);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if ( checkPid(__FUNCTION__) != OK) return;
 
@@ -637,7 +617,7 @@
 status_t Camera2Client::startPreview() {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
     SharedParameters::Lock l(mParameters);
@@ -753,7 +733,7 @@
 void Camera2Client::stopPreview() {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return;
     stopPreviewL();
@@ -801,7 +781,7 @@
 
 bool Camera2Client::previewEnabled() {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return false;
 
@@ -811,7 +791,7 @@
 
 status_t Camera2Client::storeMetaDataInBuffers(bool enabled) {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
@@ -836,7 +816,7 @@
 status_t Camera2Client::startRecording() {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
     SharedParameters::Lock l(mParameters);
@@ -927,7 +907,7 @@
 void Camera2Client::stopRecording() {
     ATRACE_CALL();
     ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     SharedParameters::Lock l(mParameters);
 
     status_t res;
@@ -959,7 +939,7 @@
 
 bool Camera2Client::recordingEnabled() {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if ( checkPid(__FUNCTION__) != OK) return false;
 
@@ -976,7 +956,7 @@
 
 void Camera2Client::releaseRecordingFrame(const sp<IMemory>& mem) {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     if ( checkPid(__FUNCTION__) != OK) return;
 
     mStreamingProcessor->releaseRecordingFrame(mem);
@@ -984,7 +964,7 @@
 
 status_t Camera2Client::autoFocus() {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
@@ -1022,9 +1002,9 @@
          * Send immediate notification back to client
          */
         if (notifyImmediately) {
-            SharedCameraClient::Lock l(mSharedCameraClient);
-            if (l.mCameraClient != 0) {
-                l.mCameraClient->notifyCallback(CAMERA_MSG_FOCUS,
+            SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+            if (l.mRemoteCallback != 0) {
+                l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS,
                         notifySuccess ? 1 : 0, 0);
             }
             return OK;
@@ -1055,7 +1035,7 @@
 
 status_t Camera2Client::cancelAutoFocus() {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
@@ -1087,7 +1067,7 @@
 
 status_t Camera2Client::takePicture(int msgType) {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
@@ -1146,7 +1126,7 @@
 status_t Camera2Client::setParameters(const String8& params) {
     ATRACE_CALL();
     ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
@@ -1163,7 +1143,7 @@
 String8 Camera2Client::getParameters() const {
     ATRACE_CALL();
     ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     if ( checkPid(__FUNCTION__) != OK) return String8();
 
     SharedParameters::ReadLock l(mParameters);
@@ -1173,7 +1153,7 @@
 
 status_t Camera2Client::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
@@ -1348,18 +1328,6 @@
 }
 
 /** Device-related methods */
-
-void Camera2Client::notifyError(int errorCode, int arg1, int arg2) {
-    ALOGE("Error condition %d reported by HAL, arguments %d, %d", errorCode, arg1, arg2);
-}
-
-void Camera2Client::notifyShutter(int frameNumber, nsecs_t timestamp) {
-    (void)frameNumber;
-    (void)timestamp;
-    ALOGV("%s: Shutter notification for frame %d at time %lld", __FUNCTION__,
-            frameNumber, timestamp);
-}
-
 void Camera2Client::notifyAutoFocus(uint8_t newState, int triggerId) {
     ALOGV("%s: Autofocus state now %d, last trigger %d",
             __FUNCTION__, newState, triggerId);
@@ -1455,16 +1423,16 @@
         }
     }
     if (sendMovingMessage) {
-        SharedCameraClient::Lock l(mSharedCameraClient);
-        if (l.mCameraClient != 0) {
-            l.mCameraClient->notifyCallback(CAMERA_MSG_FOCUS_MOVE,
+        SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+        if (l.mRemoteCallback != 0) {
+            l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS_MOVE,
                     afInMotion ? 1 : 0, 0);
         }
     }
     if (sendCompletedMessage) {
-        SharedCameraClient::Lock l(mSharedCameraClient);
-        if (l.mCameraClient != 0) {
-            l.mCameraClient->notifyCallback(CAMERA_MSG_FOCUS,
+        SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+        if (l.mRemoteCallback != 0) {
+            l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS,
                     success ? 1 : 0, 0);
         }
     }
@@ -1476,25 +1444,6 @@
     mCaptureSequencer->notifyAutoExposure(newState, triggerId);
 }
 
-void Camera2Client::notifyAutoWhitebalance(uint8_t newState, int triggerId) {
-    (void)newState;
-    (void)triggerId;
-    ALOGV("%s: Auto-whitebalance state now %d, last trigger %d",
-            __FUNCTION__, newState, triggerId);
-}
-
-int Camera2Client::getCameraId() const {
-    return mCameraId;
-}
-
-const sp<CameraDeviceBase>& Camera2Client::getCameraDevice() {
-    return mDevice;
-}
-
-const sp<CameraService>& Camera2Client::getCameraService() {
-    return mCameraService;
-}
-
 camera2::SharedParameters& Camera2Client::getParameters() {
     return mParameters;
 }
@@ -1533,32 +1482,6 @@
     return mStreamingProcessor->stopStream();
 }
 
-Camera2Client::SharedCameraClient::Lock::Lock(SharedCameraClient &client):
-        mCameraClient(client.mCameraClient),
-        mSharedClient(client) {
-    mSharedClient.mCameraClientLock.lock();
-}
-
-Camera2Client::SharedCameraClient::Lock::~Lock() {
-    mSharedClient.mCameraClientLock.unlock();
-}
-
-Camera2Client::SharedCameraClient::SharedCameraClient(const sp<ICameraClient>&client):
-        mCameraClient(client) {
-}
-
-Camera2Client::SharedCameraClient& Camera2Client::SharedCameraClient::operator=(
-        const sp<ICameraClient>&client) {
-    Mutex::Autolock l(mCameraClientLock);
-    mCameraClient = client;
-    return *this;
-}
-
-void Camera2Client::SharedCameraClient::clear() {
-    Mutex::Autolock l(mCameraClientLock);
-    mCameraClient.clear();
-}
-
 const int32_t Camera2Client::kPreviewRequestIdStart;
 const int32_t Camera2Client::kPreviewRequestIdEnd;
 const int32_t Camera2Client::kRecordingRequestIdStart;
@@ -1660,4 +1583,5 @@
     return res;
 }
 
+
 } // namespace android
diff --git a/services/camera/libcameraservice/Camera2Client.h b/services/camera/libcameraservice/Camera2Client.h
index 80b88f4..713fab3 100644
--- a/services/camera/libcameraservice/Camera2Client.h
+++ b/services/camera/libcameraservice/Camera2Client.h
@@ -26,6 +26,7 @@
 #include "camera2/ZslProcessor.h"
 #include "camera2/CaptureSequencer.h"
 #include "camera2/CallbackProcessor.h"
+#include "Camera2ClientBase.h"
 
 namespace android {
 
@@ -35,8 +36,7 @@
  * CAMERA_DEVICE_API_VERSION_2_0 and 3_0.
  */
 class Camera2Client :
-        public CameraService::Client,
-        public CameraDeviceBase::NotificationListener
+        public Camera2ClientBase<CameraService::Client>
 {
 public:
     /**
@@ -90,19 +90,13 @@
      * Interface used by CameraDeviceBase
      */
 
-    virtual void notifyError(int errorCode, int arg1, int arg2);
-    virtual void notifyShutter(int frameNumber, nsecs_t timestamp);
     virtual void notifyAutoFocus(uint8_t newState, int triggerId);
     virtual void notifyAutoExposure(uint8_t newState, int triggerId);
-    virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId);
 
     /**
      * Interface used by independent components of Camera2Client.
      */
 
-    int getCameraId() const;
-    const sp<CameraDeviceBase>& getCameraDevice();
-    const sp<CameraService>& getCameraService();
     camera2::SharedParameters& getParameters();
 
     int getPreviewStreamId() const;
@@ -118,27 +112,6 @@
 
     status_t stopStream();
 
-    // Simple class to ensure that access to ICameraClient is serialized by
-    // requiring mCameraClientLock to be locked before access to mCameraClient
-    // is possible.
-    class SharedCameraClient {
-      public:
-        class Lock {
-          public:
-            Lock(SharedCameraClient &client);
-            ~Lock();
-            sp<ICameraClient> &mCameraClient;
-          private:
-            SharedCameraClient &mSharedClient;
-        };
-        SharedCameraClient(const sp<ICameraClient>& client);
-        SharedCameraClient& operator=(const sp<ICameraClient>& client);
-        void clear();
-      private:
-        sp<ICameraClient> mCameraClient;
-        mutable Mutex mCameraClientLock;
-    } mSharedCameraClient;
-
     static size_t calculateBufferSize(int width, int height,
             int format, int stride);
 
@@ -153,13 +126,6 @@
 
 private:
     /** ICamera interface-related private members */
-
-    // Mutex that must be locked by methods implementing the ICamera interface.
-    // Ensures serialization between incoming ICamera calls. All methods below
-    // that append 'L' to the name assume that mICameraLock is locked when
-    // they're called
-    mutable Mutex mICameraLock;
-
     typedef camera2::Parameters Parameters;
 
     status_t setPreviewWindowL(const sp<IBinder>& binder,
@@ -213,17 +179,10 @@
 
     bool mAfInMotion;
 
-    /** CameraDevice instance, wraps HAL camera device */
-
-    sp<CameraDeviceBase> mDevice;
-
     /** Utility members */
 
     // Wait until the camera device has received the latest control settings
     status_t syncWithDevice();
-
-    // Verify that caller is the owner of the camera
-    status_t checkPid(const char *checkLocation) const;
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/Camera2ClientBase.cpp b/services/camera/libcameraservice/Camera2ClientBase.cpp
new file mode 100644
index 0000000..e92ad1c
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2ClientBase.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "Camera2ClientBase"
+#define ATRACE_TAG ATRACE_TAG_CAMERA
+//#define LOG_NDEBUG 0
+
+#include <utils/Log.h>
+#include <utils/Trace.h>
+
+#include <cutils/properties.h>
+#include <gui/Surface.h>
+#include <gui/Surface.h>
+#include "camera2/Parameters.h"
+#include "Camera2ClientBase.h"
+#include "camera2/ProFrameProcessor.h"
+
+#include "Camera2Device.h"
+
+namespace android {
+using namespace camera2;
+
+static int getCallingPid() {
+    return IPCThreadState::self()->getCallingPid();
+}
+
+// Interface used by CameraService
+
+template <typename TClientBase>
+Camera2ClientBase<TClientBase>::Camera2ClientBase(
+        const sp<CameraService>& cameraService,
+        const sp<TCamCallbacks>& remoteCallback,
+        const String16& clientPackageName,
+        int cameraId,
+        int cameraFacing,
+        int clientPid,
+        uid_t clientUid,
+        int servicePid):
+        TClientBase(cameraService, remoteCallback, clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid),
+        mSharedCameraCallbacks(remoteCallback)
+{
+    ALOGI("Camera %d: Opened", cameraId);
+    mDevice = new Camera2Device(cameraId);
+}
+
+template <typename TClientBase>
+status_t Camera2ClientBase<TClientBase>::checkPid(const char* checkLocation)
+        const {
+
+    int callingPid = getCallingPid();
+    if (callingPid == TClientBase::mClientPid) return NO_ERROR;
+
+    ALOGE("%s: attempt to use a locked camera from a different process"
+            " (old pid %d, new pid %d)", checkLocation, TClientBase::mClientPid, callingPid);
+    return PERMISSION_DENIED;
+}
+
+template <typename TClientBase>
+status_t Camera2ClientBase<TClientBase>::initialize(camera_module_t *module) {
+    ATRACE_CALL();
+    ALOGV("%s: Initializing client for camera %d", __FUNCTION__,
+          TClientBase::mCameraId);
+    status_t res;
+
+    res = mDevice->initialize(module);
+    if (res != OK) {
+        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
+                __FUNCTION__, TClientBase::mCameraId, strerror(-res), res);
+        return NO_INIT;
+    }
+
+    res = mDevice->setNotifyCallback(this);
+
+    return OK;
+}
+
+template <typename TClientBase>
+Camera2ClientBase<TClientBase>::~Camera2ClientBase() {
+    ATRACE_CALL();
+
+    TClientBase::mDestructionStarted = true;
+
+    disconnect();
+
+    ALOGI("Closed Camera %d", TClientBase::mCameraId);
+}
+
+template <typename TClientBase>
+status_t Camera2ClientBase<TClientBase>::dump(int fd,
+                                              const Vector<String16>& args) {
+    String8 result;
+    result.appendFormat("Camera2ClientBase[%d] (%p) PID: %d, dump:\n",
+            TClientBase::mCameraId,
+            TClientBase::getRemoteCallback()->asBinder().get(),
+            TClientBase::mClientPid);
+    result.append("  State: ");
+
+    write(fd, result.string(), result.size());
+    // TODO: print dynamic/request section from most recent requests
+
+    return dumpDevice(fd, args);
+}
+
+template <typename TClientBase>
+status_t Camera2ClientBase<TClientBase>::dumpDevice(
+                                                int fd,
+                                                const Vector<String16>& args) {
+    String8 result;
+
+    result = "  Device dump:\n";
+    write(fd, result.string(), result.size());
+
+    if (!mDevice.get()) {
+        result = "  *** Device is detached\n";
+        write(fd, result.string(), result.size());
+        return NO_ERROR;
+    }
+
+    status_t res = mDevice->dump(fd, args);
+    if (res != OK) {
+        result = String8::format("   Error dumping device: %s (%d)",
+                strerror(-res), res);
+        write(fd, result.string(), result.size());
+    }
+
+    return NO_ERROR;
+}
+
+// ICameraClient2BaseUser interface
+
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::disconnect() {
+    ATRACE_CALL();
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    // Allow both client and the media server to disconnect at all times
+    int callingPid = getCallingPid();
+    if (callingPid != TClientBase::mClientPid &&
+        callingPid != TClientBase::mServicePid) return;
+
+    ALOGV("Camera %d: Shutting down", TClientBase::mCameraId);
+
+    detachDevice();
+
+    TClientBase::disconnect();
+
+    ALOGV("Camera %d: Shut down complete complete", TClientBase::mCameraId);
+}
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::detachDevice() {
+    if (mDevice == 0) return;
+    mDevice->disconnect();
+
+    mDevice.clear();
+
+    ALOGV("Camera %d: Detach complete", TClientBase::mCameraId);
+}
+
+template <typename TClientBase>
+status_t Camera2ClientBase<TClientBase>::connect(
+        const sp<TCamCallbacks>& client) {
+    ATRACE_CALL();
+    ALOGV("%s: E", __FUNCTION__);
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (TClientBase::mClientPid != 0 &&
+        getCallingPid() != TClientBase::mClientPid) {
+
+        ALOGE("%s: Camera %d: Connection attempt from pid %d; "
+                "current locked to pid %d",
+                __FUNCTION__,
+                TClientBase::mCameraId,
+                getCallingPid(),
+                TClientBase::mClientPid);
+        return BAD_VALUE;
+    }
+
+    TClientBase::mClientPid = getCallingPid();
+
+    TClientBase::mRemoteCallback = client;
+    mSharedCameraCallbacks = client;
+
+    return OK;
+}
+
+/** Device-related methods */
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyError(int errorCode, int arg1,
+                                                 int arg2) {
+    ALOGE("Error condition %d reported by HAL, arguments %d, %d", errorCode,
+          arg1, arg2);
+}
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyShutter(int frameNumber,
+                                                   nsecs_t timestamp) {
+    (void)frameNumber;
+    (void)timestamp;
+
+    ALOGV("%s: Shutter notification for frame %d at time %lld", __FUNCTION__,
+          frameNumber, timestamp);
+}
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyAutoFocus(uint8_t newState,
+                                                     int triggerId) {
+    (void)newState;
+    (void)triggerId;
+
+    ALOGV("%s: Autofocus state now %d, last trigger %d",
+          __FUNCTION__, newState, triggerId);
+
+    typename SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+    if (l.mRemoteCallback != 0) {
+        l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS_MOVE, 1, 0);
+    }
+    if (l.mRemoteCallback != 0) {
+        l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS, 1, 0);
+    }
+}
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyAutoExposure(uint8_t newState,
+                                                        int triggerId) {
+    (void)newState;
+    (void)triggerId;
+
+    ALOGV("%s: Autoexposure state now %d, last trigger %d",
+            __FUNCTION__, newState, triggerId);
+}
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::notifyAutoWhitebalance(uint8_t newState,
+                                                            int triggerId) {
+    (void)newState;
+    (void)triggerId;
+
+    ALOGV("%s: Auto-whitebalance state now %d, last trigger %d",
+            __FUNCTION__, newState, triggerId);
+}
+
+template <typename TClientBase>
+int Camera2ClientBase<TClientBase>::getCameraId() const {
+    return TClientBase::mCameraId;
+}
+
+template <typename TClientBase>
+const sp<CameraDeviceBase>& Camera2ClientBase<TClientBase>::getCameraDevice() {
+    return mDevice;
+}
+
+template <typename TClientBase>
+const sp<CameraService>& Camera2ClientBase<TClientBase>::getCameraService() {
+    return TClientBase::mCameraService;
+}
+
+template <typename TClientBase>
+Camera2ClientBase<TClientBase>::SharedCameraCallbacks::Lock::Lock(
+        SharedCameraCallbacks &client) :
+
+        mRemoteCallback(client.mRemoteCallback),
+        mSharedClient(client) {
+
+    mSharedClient.mRemoteCallbackLock.lock();
+}
+
+template <typename TClientBase>
+Camera2ClientBase<TClientBase>::SharedCameraCallbacks::Lock::~Lock() {
+    mSharedClient.mRemoteCallbackLock.unlock();
+}
+
+template <typename TClientBase>
+Camera2ClientBase<TClientBase>::SharedCameraCallbacks::SharedCameraCallbacks(
+        const sp<TCamCallbacks>&client) :
+
+        mRemoteCallback(client) {
+}
+
+template <typename TClientBase>
+typename Camera2ClientBase<TClientBase>::SharedCameraCallbacks&
+Camera2ClientBase<TClientBase>::SharedCameraCallbacks::operator=(
+        const sp<TCamCallbacks>&client) {
+
+    Mutex::Autolock l(mRemoteCallbackLock);
+    mRemoteCallback = client;
+    return *this;
+}
+
+template <typename TClientBase>
+void Camera2ClientBase<TClientBase>::SharedCameraCallbacks::clear() {
+    Mutex::Autolock l(mRemoteCallbackLock);
+    mRemoteCallback.clear();
+}
+
+template class Camera2ClientBase<CameraService::ProClient>;
+template class Camera2ClientBase<CameraService::Client>;
+
+} // namespace android
diff --git a/services/camera/libcameraservice/Camera2ClientBase.h b/services/camera/libcameraservice/Camera2ClientBase.h
new file mode 100644
index 0000000..9001efb
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2ClientBase.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H
+#define ANDROID_SERVERS_CAMERA_CAMERA2CLIENT_BASE_H
+
+#include "CameraDeviceBase.h"
+#include "CameraService.h"
+
+namespace android {
+
+class IMemory;
+
+template <typename TClientBase>
+class Camera2ClientBase :
+        public TClientBase,
+        public CameraDeviceBase::NotificationListener
+{
+public:
+    typedef typename TClientBase::TCamCallbacks TCamCallbacks;
+
+    /**
+     * Base binder interface (see ICamera/IProCameraUser for details)
+     */
+    virtual status_t      connect(const sp<TCamCallbacks>& callbacks);
+    virtual void          disconnect();
+
+    /**
+     * Interface used by CameraService
+     */
+
+    // TODO: too many params, move into a ClientArgs<T>
+    Camera2ClientBase(const sp<CameraService>& cameraService,
+                      const sp<TCamCallbacks>& remoteCallback,
+                      const String16& clientPackageName,
+                      int cameraId,
+                      int cameraFacing,
+                      int clientPid,
+                      uid_t clientUid,
+                      int servicePid);
+    virtual ~Camera2ClientBase();
+
+    virtual status_t      initialize(camera_module_t *module);
+    virtual status_t      dump(int fd, const Vector<String16>& args);
+
+    /**
+     * CameraDeviceBase::NotificationListener implementation
+     */
+
+    virtual void          notifyError(int errorCode, int arg1, int arg2);
+    virtual void          notifyShutter(int frameNumber, nsecs_t timestamp);
+    virtual void          notifyAutoFocus(uint8_t newState, int triggerId);
+    virtual void          notifyAutoExposure(uint8_t newState, int triggerId);
+    virtual void          notifyAutoWhitebalance(uint8_t newState,
+                                                 int triggerId);
+
+
+    int                   getCameraId() const;
+    const sp<CameraDeviceBase>&
+                          getCameraDevice();
+    const sp<CameraService>&
+                          getCameraService();
+
+    /**
+     * Interface used by independent components of CameraClient2Base.
+     */
+
+    // Simple class to ensure that access to TCamCallbacks is serialized
+    // by requiring mRemoteCallbackLock to be locked before access to
+    // mRemoteCallback is possible.
+    class SharedCameraCallbacks {
+      public:
+        class Lock {
+          public:
+            Lock(SharedCameraCallbacks &client);
+            ~Lock();
+            sp<TCamCallbacks> &mRemoteCallback;
+          private:
+            SharedCameraCallbacks &mSharedClient;
+        };
+        SharedCameraCallbacks(const sp<TCamCallbacks>& client);
+        SharedCameraCallbacks& operator=(const sp<TCamCallbacks>& client);
+        void clear();
+      private:
+        sp<TCamCallbacks> mRemoteCallback;
+        mutable Mutex mRemoteCallbackLock;
+    } mSharedCameraCallbacks;
+
+protected:
+
+    virtual status_t      dumpDevice(int fd, const Vector<String16>& args);
+
+    /** Binder client interface-related private members */
+
+    // Mutex that must be locked by methods implementing the binder client
+    // interface. Ensures serialization between incoming client calls.
+    // All methods in this class hierarchy that append 'L' to the name assume
+    // that mBinderSerializationLock is locked when they're called
+    mutable Mutex         mBinderSerializationLock;
+
+    /** CameraDeviceBase instance wrapping HAL2+ entry */
+
+    sp<CameraDeviceBase>  mDevice;
+
+    /** Utility members */
+
+    // Verify that caller is the owner of the camera
+    status_t              checkPid(const char *checkLocation) const;
+
+    virtual void          detachDevice();
+};
+
+}; // namespace android
+
+#endif
diff --git a/services/camera/libcameraservice/CameraClient.cpp b/services/camera/libcameraservice/CameraClient.cpp
index 90f8f40..e577fa3 100644
--- a/services/camera/libcameraservice/CameraClient.cpp
+++ b/services/camera/libcameraservice/CameraClient.cpp
@@ -117,7 +117,7 @@
 
     size_t len = snprintf(buffer, SIZE, "Client[%d] (%p) PID: %d\n",
             mCameraId,
-            getCameraClient()->asBinder().get(),
+            getRemoteCallback()->asBinder().get(),
             mClientPid);
     len = (len > SIZE - 1) ? SIZE - 1 : len;
     write(fd, buffer, len);
@@ -173,10 +173,10 @@
             return INVALID_OPERATION;
         }
         mClientPid = 0;
-        LOG1("clear mCameraClient (pid %d)", callingPid);
+        LOG1("clear mRemoteCallback (pid %d)", callingPid);
         // we need to remove the reference to ICameraClient so that when the app
         // goes away, the reference count goes to 0.
-        mCameraClient.clear();
+        mRemoteCallback.clear();
     }
     return result;
 }
@@ -193,14 +193,15 @@
         return EBUSY;
     }
 
-    if (mCameraClient != 0 && (client->asBinder() == mCameraClient->asBinder())) {
+    if (mRemoteCallback != 0 &&
+        (client->asBinder() == mRemoteCallback->asBinder())) {
         LOG1("Connect to the same client");
         return NO_ERROR;
     }
 
     mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
     mClientPid = callingPid;
-    mCameraClient = client;
+    mRemoteCallback = client;
 
     LOG1("connect X (pid %d)", callingPid);
     return NO_ERROR;
@@ -780,7 +781,7 @@
         mCameraService->playSound(CameraService::SOUND_SHUTTER);
     }
 
-    sp<ICameraClient> c = mCameraClient;
+    sp<ICameraClient> c = mRemoteCallback;
     if (c != 0) {
         mLock.unlock();
         c->notifyCallback(CAMERA_MSG_SHUTTER, 0, 0);
@@ -811,7 +812,7 @@
     }
 
     // hold a strong pointer to the client
-    sp<ICameraClient> c = mCameraClient;
+    sp<ICameraClient> c = mRemoteCallback;
 
     // clear callback flags if no client or one-shot mode
     if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
@@ -841,7 +842,7 @@
 void CameraClient::handlePostview(const sp<IMemory>& mem) {
     disableMsgType(CAMERA_MSG_POSTVIEW_FRAME);
 
-    sp<ICameraClient> c = mCameraClient;
+    sp<ICameraClient> c = mRemoteCallback;
     mLock.unlock();
     if (c != 0) {
         c->dataCallback(CAMERA_MSG_POSTVIEW_FRAME, mem, NULL);
@@ -856,7 +857,7 @@
     size_t size;
     sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
 
-    sp<ICameraClient> c = mCameraClient;
+    sp<ICameraClient> c = mRemoteCallback;
     mLock.unlock();
     if (c != 0) {
         c->dataCallback(CAMERA_MSG_RAW_IMAGE, mem, NULL);
@@ -867,7 +868,7 @@
 void CameraClient::handleCompressedPicture(const sp<IMemory>& mem) {
     disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE);
 
-    sp<ICameraClient> c = mCameraClient;
+    sp<ICameraClient> c = mRemoteCallback;
     mLock.unlock();
     if (c != 0) {
         c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE, mem, NULL);
@@ -877,7 +878,7 @@
 
 void CameraClient::handleGenericNotify(int32_t msgType,
     int32_t ext1, int32_t ext2) {
-    sp<ICameraClient> c = mCameraClient;
+    sp<ICameraClient> c = mRemoteCallback;
     mLock.unlock();
     if (c != 0) {
         c->notifyCallback(msgType, ext1, ext2);
@@ -886,7 +887,7 @@
 
 void CameraClient::handleGenericData(int32_t msgType,
     const sp<IMemory>& dataPtr, camera_frame_metadata_t *metadata) {
-    sp<ICameraClient> c = mCameraClient;
+    sp<ICameraClient> c = mRemoteCallback;
     mLock.unlock();
     if (c != 0) {
         c->dataCallback(msgType, dataPtr, metadata);
@@ -895,7 +896,7 @@
 
 void CameraClient::handleGenericDataTimestamp(nsecs_t timestamp,
     int32_t msgType, const sp<IMemory>& dataPtr) {
-    sp<ICameraClient> c = mCameraClient;
+    sp<ICameraClient> c = mRemoteCallback;
     mLock.unlock();
     if (c != 0) {
         c->dataCallbackTimestamp(timestamp, msgType, dataPtr);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 8c4f619..d46ca88 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -223,7 +223,9 @@
     if (mClient[cameraId] != 0) {
         client = mClient[cameraId].promote();
         if (client != 0) {
-            if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
+            if (cameraClient->asBinder() ==
+                client->getRemoteCallback()->asBinder()) {
+
                 LOG1("CameraService::connect X (pid %d) (the same client)",
                      callingPid);
                 return client;
@@ -496,7 +498,7 @@
             continue;
         }
 
-        if (cameraClient == client->getCameraClient()->asBinder()) {
+        if (cameraClient == client->getRemoteCallback()->asBinder()) {
             // Found our camera
             outIndex = i;
             return client;
@@ -639,7 +641,7 @@
     int callingPid = getCallingPid();
     LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
 
-    mCameraClient = cameraClient;
+    mRemoteCallback = cameraClient;
 
     cameraService->setCameraBusy(cameraId);
     cameraService->loadSound();
@@ -666,7 +668,7 @@
         mClientPackageName(clientPackageName)
 {
     mCameraService = cameraService;
-    mRemoteCallback = remoteCallback;
+    mRemoteBinder = remoteCallback;
     mCameraId = cameraId;
     mCameraFacing = cameraFacing;
     mClientPid = clientPid;
@@ -681,7 +683,7 @@
 }
 
 void CameraService::BasicClient::disconnect() {
-    mCameraService->removeClientByRemote(mRemoteCallback);
+    mCameraService->removeClientByRemote(mRemoteBinder);
 }
 
 status_t CameraService::BasicClient::startCameraOps() {
@@ -767,7 +769,7 @@
 }
 
 void CameraService::Client::notifyError() {
-    mCameraClient->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
+    mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
 }
 
 // NOTE: function is idempotent
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8acc63f..d7a336c 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -109,7 +109,7 @@
         virtual void          disconnect() = 0;
 
         wp<IBinder>     getRemote() {
-            return mRemoteCallback;
+            return mRemoteBinder;
         }
 
     protected:
@@ -140,7 +140,7 @@
         pid_t                           mServicePid;     // immutable after constructor
 
         // - The app-side Binder interface to receive callbacks from us
-        wp<IBinder>                     mRemoteCallback; // immutable after constructor
+        wp<IBinder>                     mRemoteBinder;   // immutable after constructor
 
         // permissions management
         status_t                        startCameraOps();
@@ -173,6 +173,8 @@
     class Client : public BnCamera, public BasicClient
     {
     public:
+        typedef ICameraClient TCamCallbacks;
+
         // ICamera interface (see ICamera for details)
         virtual void          disconnect();
         virtual status_t      connect(const sp<ICameraClient>& client) = 0;
@@ -208,8 +210,8 @@
         ~Client();
 
         // return our camera client
-        const sp<ICameraClient>&    getCameraClient() {
-            return mCameraClient;
+        const sp<ICameraClient>&    getRemoteCallback() {
+            return mRemoteCallback;
         }
 
     protected:
@@ -222,12 +224,14 @@
         // Initialized in constructor
 
         // - The app-side Binder interface to receive callbacks from us
-        sp<ICameraClient>               mCameraClient;
+        sp<ICameraClient>               mRemoteCallback;
 
     }; // class Client
 
     class ProClient : public BnProCameraUser, public BasicClient {
     public:
+        typedef IProCameraCallbacks TCamCallbacks;
+
         ProClient(const sp<CameraService>& cameraService,
                 const sp<IProCameraCallbacks>& remoteCallback,
                 const String16& clientPackageName,
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index 6fed8b4..4a5a3d5 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/ProCamera2Client.cpp
@@ -31,64 +31,38 @@
 namespace android {
 using namespace camera2;
 
-static int getCallingPid() {
-    return IPCThreadState::self()->getCallingPid();
-}
-
-static int getCallingUid() {
-    return IPCThreadState::self()->getCallingUid();
-}
-
 // Interface used by CameraService
 
 ProCamera2Client::ProCamera2Client(const sp<CameraService>& cameraService,
-        const sp<IProCameraCallbacks>& remoteCallback,
-        const String16& clientPackageName,
-        int cameraId,
-        int cameraFacing,
-        int clientPid,
-        uid_t clientUid,
-        int servicePid):
-        ProClient(cameraService, remoteCallback, clientPackageName,
-                cameraId, cameraFacing, clientPid, clientUid, servicePid),
-        mSharedCameraCallbacks(remoteCallback)
+                                   const sp<IProCameraCallbacks>& remoteCallback,
+                                   const String16& clientPackageName,
+                                   int cameraId,
+                                   int cameraFacing,
+                                   int clientPid,
+                                   uid_t clientUid,
+                                   int servicePid) :
+    Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid)
 {
     ATRACE_CALL();
     ALOGI("ProCamera %d: Opened", cameraId);
 
-    mDevice = new Camera2Device(cameraId);
-
     mExclusiveLock = false;
 }
 
-status_t ProCamera2Client::checkPid(const char* checkLocation) const {
-    int callingPid = getCallingPid();
-    if (callingPid == mClientPid) return NO_ERROR;
-
-    ALOGE("%s: attempt to use a locked camera from a different process"
-            " (old pid %d, new pid %d)", checkLocation, mClientPid, callingPid);
-    return PERMISSION_DENIED;
-}
-
 status_t ProCamera2Client::initialize(camera_module_t *module)
 {
     ATRACE_CALL();
-    ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
-    res = mDevice->initialize(module);
+    res = Camera2ClientBase::initialize(module);
     if (res != OK) {
-        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
-                __FUNCTION__, mCameraId, strerror(-res), res);
-        return NO_INIT;
+        return res;
     }
 
-    res = mDevice->setNotifyCallback(this);
-
     String8 threadName;
     mFrameProcessor = new ProFrameProcessor(this);
-    threadName = String8::format("PC2-%d-FrameProc",
-            mCameraId);
+    threadName = String8::format("PC2-%d-FrameProc", mCameraId);
     mFrameProcessor->run(threadName.string());
 
     mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
@@ -99,20 +73,13 @@
 }
 
 ProCamera2Client::~ProCamera2Client() {
-    ATRACE_CALL();
-
-    mDestructionStarted = true;
-
-    disconnect();
-
-    ALOGI("ProCamera %d: Closed", mCameraId);
 }
 
 status_t ProCamera2Client::exclusiveTryLock() {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
     if (!mDevice.get()) return PERMISSION_DENIED;
@@ -143,7 +110,7 @@
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
     if (!mDevice.get()) return PERMISSION_DENIED;
@@ -177,7 +144,7 @@
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
     // don't allow unlocking if we have no lock
@@ -198,6 +165,7 @@
 }
 
 bool ProCamera2Client::hasExclusiveLock() {
+    Mutex::Autolock icl(mBinderSerializationLock);
     return mExclusiveLock;
 }
 
@@ -205,7 +173,7 @@
     ALOGV("%s: ProClient lost exclusivity (id %d)",
           __FUNCTION__, mCameraId);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
     if (mExclusiveLock && mRemoteCallback.get() != NULL) {
@@ -224,7 +192,7 @@
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
@@ -248,7 +216,7 @@
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
@@ -256,10 +224,12 @@
         return PERMISSION_DENIED;
     }
 
+    // TODO: implement
     ALOGE("%s: not fully implemented yet", __FUNCTION__);
     return INVALID_OPERATION;
 }
 
+//TODO: Remove
 status_t ProCamera2Client::requestStream(int streamId) {
     ALOGE("%s: not implemented yet", __FUNCTION__);
 
@@ -273,7 +243,7 @@
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
     mDevice->clearStreamingRequest();
@@ -301,7 +271,7 @@
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
@@ -332,7 +302,7 @@
     status_t res;
     if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
@@ -352,7 +322,7 @@
         return INVALID_OPERATION;
     }
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
@@ -373,47 +343,11 @@
     // TODO: print dynamic/request section from most recent requests
     mFrameProcessor->dump(fd, args);
 
-#define CASE_APPEND_ENUM(x) case x: result.append(#x "\n"); break;
-
-    result = "  Device dump:\n";
-    write(fd, result.string(), result.size());
-
-    if (!mDevice.get()) {
-        result = "  *** Device is detached\n";
-        write(fd, result.string(), result.size());
-        return NO_ERROR;
-    }
-
-    status_t res = mDevice->dump(fd, args);
-    if (res != OK) {
-        result = String8::format("   Error dumping device: %s (%d)",
-                strerror(-res), res);
-        write(fd, result.string(), result.size());
-    }
-
-#undef CASE_APPEND_ENUM
-    return NO_ERROR;
+    return dumpDevice(fd, args);
 }
 
 // IProCameraUser interface
 
-void ProCamera2Client::disconnect() {
-    ATRACE_CALL();
-    Mutex::Autolock icl(mIProCameraUserLock);
-    status_t res;
-
-    // Allow both client and the media server to disconnect at all times
-    int callingPid = getCallingPid();
-    if (callingPid != mClientPid && callingPid != mServicePid) return;
-
-    ALOGV("Camera %d: Shutting down", mCameraId);
-
-    detachDevice();
-    ProClient::disconnect();
-
-    ALOGV("Camera %d: Shut down complete complete", mCameraId);
-}
-
 void ProCamera2Client::detachDevice() {
     if (mDevice == 0) return;
 
@@ -438,117 +372,16 @@
         }
     }
 
-    mDevice->disconnect();
-
-    mDevice.clear();
-
-    ALOGV("Camera %d: Detach complete", mCameraId);
-}
-
-status_t ProCamera2Client::connect(const sp<IProCameraCallbacks>& client) {
-    ATRACE_CALL();
-    ALOGV("%s: E", __FUNCTION__);
-    Mutex::Autolock icl(mIProCameraUserLock);
-
-    if (mClientPid != 0 && getCallingPid() != mClientPid) {
-        ALOGE("%s: Camera %d: Connection attempt from pid %d; "
-                "current locked to pid %d", __FUNCTION__,
-                mCameraId, getCallingPid(), mClientPid);
-        return BAD_VALUE;
-    }
-
-    mClientPid = getCallingPid();
-
-    mRemoteCallback = client;
-    mSharedCameraCallbacks = client;
-
-    return OK;
+    Camera2ClientBase::detachDevice();
 }
 
 /** Device-related methods */
-
-void ProCamera2Client::notifyError(int errorCode, int arg1, int arg2) {
-    ALOGE("Error condition %d reported by HAL, arguments %d, %d", errorCode,
-                                                                    arg1, arg2);
-}
-
-void ProCamera2Client::notifyShutter(int frameNumber, nsecs_t timestamp) {
-    ALOGV("%s: Shutter notification for frame %d at time %lld", __FUNCTION__,
-            frameNumber, timestamp);
-}
-
-void ProCamera2Client::notifyAutoFocus(uint8_t newState, int triggerId) {
-    ALOGV("%s: Autofocus state now %d, last trigger %d",
-            __FUNCTION__, newState, triggerId);
-
-    SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
-    if (l.mRemoteCallback != 0) {
-        l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS_MOVE,
-                1, 0);
-    }
-    if (l.mRemoteCallback != 0) {
-        l.mRemoteCallback->notifyCallback(CAMERA_MSG_FOCUS,
-                1, 0);
-    }
-}
-
-void ProCamera2Client::notifyAutoExposure(uint8_t newState, int triggerId) {
-    ALOGV("%s: Autoexposure state now %d, last trigger %d",
-            __FUNCTION__, newState, triggerId);
-}
-
-void ProCamera2Client::notifyAutoWhitebalance(uint8_t newState, int triggerId) {
-    ALOGV("%s: Auto-whitebalance state now %d, last trigger %d",
-            __FUNCTION__, newState, triggerId);
-}
-
-int ProCamera2Client::getCameraId() const {
-    return mCameraId;
-}
-
-const sp<Camera2Device>& ProCamera2Client::getCameraDevice() {
-    return mDevice;
-}
-
-const sp<CameraService>& ProCamera2Client::getCameraService() {
-    return mCameraService;
-}
-
-ProCamera2Client::SharedCameraCallbacks::Lock::Lock(
-                                                 SharedCameraCallbacks &client):
-        mRemoteCallback(client.mRemoteCallback),
-        mSharedClient(client) {
-    mSharedClient.mRemoteCallbackLock.lock();
-}
-
-ProCamera2Client::SharedCameraCallbacks::Lock::~Lock() {
-    mSharedClient.mRemoteCallbackLock.unlock();
-}
-
-ProCamera2Client::SharedCameraCallbacks::SharedCameraCallbacks
-                                         (const sp<IProCameraCallbacks>&client):
-        mRemoteCallback(client) {
-}
-
-ProCamera2Client::SharedCameraCallbacks&
-                             ProCamera2Client::SharedCameraCallbacks::operator=(
-        const sp<IProCameraCallbacks>&client) {
-    Mutex::Autolock l(mRemoteCallbackLock);
-    mRemoteCallback = client;
-    return *this;
-}
-
-void ProCamera2Client::SharedCameraCallbacks::clear() {
-    Mutex::Autolock l(mRemoteCallbackLock);
-    mRemoteCallback.clear();
-}
-
 void ProCamera2Client::onFrameAvailable(int32_t frameId,
                                         const CameraMetadata& frame) {
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
     SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
 
     if (mRemoteCallback != NULL) {
diff --git a/services/camera/libcameraservice/ProCamera2Client.h b/services/camera/libcameraservice/ProCamera2Client.h
index ff6f4e2..f69021e 100644
--- a/services/camera/libcameraservice/ProCamera2Client.h
+++ b/services/camera/libcameraservice/ProCamera2Client.h
@@ -20,6 +20,7 @@
 #include "Camera2Device.h"
 #include "CameraService.h"
 #include "camera2/ProFrameProcessor.h"
+#include "Camera2ClientBase.h"
 
 namespace android {
 
@@ -29,17 +30,13 @@
  * meant for HAL2-level private API access.
  */
 class ProCamera2Client :
-        public CameraService::ProClient,
-        public Camera2Device::NotificationListener,
+        public Camera2ClientBase<CameraService::ProClient>,
         public camera2::ProFrameProcessor::FilteredListener
 {
 public:
     /**
      * IProCameraUser interface (see IProCameraUser for details)
      */
-    virtual status_t      connect(const sp<IProCameraCallbacks>& callbacks);
-    virtual void          disconnect();
-
     virtual status_t      exclusiveTryLock();
     virtual status_t      exclusiveLock();
     virtual status_t      exclusiveUnlock();
@@ -54,10 +51,13 @@
     virtual status_t      requestStream(int streamId);
     virtual status_t      cancelStream(int streamId);
 
-    virtual status_t      createStream(int width, int height, int format,
-                                      const sp<IGraphicBufferProducer>& bufferProducer,
-                                      /*out*/
-                                      int* streamId);
+    virtual status_t      createStream(
+            int width,
+            int height,
+            int format,
+            const sp<IGraphicBufferProducer>& bufferProducer,
+            /*out*/
+            int* streamId);
 
     // Create a request object from a template.
     // -- Caller owns the newly allocated metadata
@@ -85,24 +85,9 @@
             int servicePid);
     virtual ~ProCamera2Client();
 
-    status_t initialize(camera_module_t *module);
+    virtual status_t      initialize(camera_module_t *module);
 
-    virtual status_t dump(int fd, const Vector<String16>& args);
-
-    /**
-     * Interface used by Camera2Device
-     */
-
-    virtual void notifyError(int errorCode, int arg1, int arg2);
-    virtual void notifyShutter(int frameNumber, nsecs_t timestamp);
-    virtual void notifyAutoFocus(uint8_t newState, int triggerId);
-    virtual void notifyAutoExposure(uint8_t newState, int triggerId);
-    virtual void notifyAutoWhitebalance(uint8_t newState, int triggerId);
-
-
-    int getCameraId() const;
-    const sp<Camera2Device>& getCameraDevice();
-    const sp<CameraService>& getCameraService();
+    virtual status_t      dump(int fd, const Vector<String16>& args);
 
     // Callbacks from camera service
     virtual void onExclusiveLockStolen();
@@ -111,67 +96,26 @@
      * Interface used by independent components of ProCamera2Client.
      */
 
-    // Simple class to ensure that access to IProCameraCallbacks is serialized
-    // by requiring mRemoteCallbackLock to be locked before access to
-    // mCameraClient is possible.
-    class SharedCameraCallbacks {
-      public:
-        class Lock {
-          public:
-            Lock(SharedCameraCallbacks &client);
-            ~Lock();
-            sp<IProCameraCallbacks> &mRemoteCallback;
-          private:
-            SharedCameraCallbacks &mSharedClient;
-        };
-        SharedCameraCallbacks(const sp<IProCameraCallbacks>& client);
-        SharedCameraCallbacks& operator=(const sp<IProCameraCallbacks>& client);
-        void clear();
-      private:
-        sp<IProCameraCallbacks> mRemoteCallback;
-        mutable Mutex mRemoteCallbackLock;
-    } mSharedCameraCallbacks;
-
 protected:
     /** FilteredListener implementation **/
-    virtual void onFrameAvailable(int32_t frameId, const CameraMetadata& frame);
+    virtual void          onFrameAvailable(int32_t frameId,
+                                           const CameraMetadata& frame);
+    virtual void          detachDevice();
 
 private:
     /** IProCameraUser interface-related private members */
 
-    // Mutex that must be locked by methods implementing the IProCameraUser
-    // interface. Ensures serialization between incoming IProCameraUser calls.
-    // All methods below that append 'L' to the name assume that
-    // mIProCameraUserLock is locked when they're called
-    mutable Mutex mIProCameraUserLock;
-
-    // Used with stream IDs
-    static const int NO_STREAM = -1;
-
-    /* Preview/Recording related members */
-
-    sp<IBinder> mPreviewSurface;
-
     /** Preview callback related members */
     sp<camera2::ProFrameProcessor> mFrameProcessor;
     static const int32_t FRAME_PROCESSOR_LISTENER_MIN_ID = 0;
     static const int32_t FRAME_PROCESSOR_LISTENER_MAX_ID = 0x7fffffffL;
 
-    /** Camera2Device instance wrapping HAL2 entry */
-
-    sp<Camera2Device> mDevice;
-
     /** Utility members */
 
-    // Verify that caller is the owner of the camera
-    status_t checkPid(const char *checkLocation) const;
-
     // Whether or not we have an exclusive lock on the device
     // - if no we can't modify the request queue.
     // note that creating/deleting streams we own is still OK
     bool mExclusiveLock;
-
-    void detachDevice();
 };
 
 }; // namespace android
diff --git a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
index 9a14758..30c14ef 100644
--- a/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/CallbackProcessor.cpp
@@ -278,11 +278,12 @@
 
     // Call outside parameter lock to allow re-entrancy from notification
     {
-        Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
-        if (l.mCameraClient != 0) {
+        Camera2Client::SharedCameraCallbacks::Lock
+            l(client->mSharedCameraCallbacks);
+        if (l.mRemoteCallback != 0) {
             ALOGV("%s: Camera %d: Invoking client data callback",
                     __FUNCTION__, client->getCameraId());
-            l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_FRAME,
+            l.mRemoteCallback->dataCallback(CAMERA_MSG_PREVIEW_FRAME,
                     mCallbackHeap->mBuffers[heapIdx], NULL);
         }
     }
diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp
index 513a47e..1880912 100644
--- a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp
@@ -271,10 +271,11 @@
     }
 
     if (mCaptureBuffer != 0 && res == OK) {
-        Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
+        Camera2Client::SharedCameraCallbacks::Lock
+            l(client->mSharedCameraCallbacks);
         ALOGV("%s: Sending still image to client", __FUNCTION__);
-        if (l.mCameraClient != 0) {
-            l.mCameraClient->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
+        if (l.mRemoteCallback != 0) {
+            l.mRemoteCallback->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
                     mCaptureBuffer, NULL);
         } else {
             ALOGV("%s: No client!", __FUNCTION__);
@@ -344,7 +345,7 @@
     }
 
     SharedParameters::Lock l(client->getParameters());
-    /* warning: this also locks a SharedCameraClient */
+    /* warning: this also locks a SharedCameraCallbacks */
     shutterNotifyLocked(l.mParameters, client, mMsgType);
     mShutterNotified = true;
     mTimeoutCount = kMaxTimeoutsForCaptureEnd;
@@ -496,7 +497,7 @@
     }
     if (mNewFrameReceived && !mShutterNotified) {
         SharedParameters::Lock l(client->getParameters());
-        /* warning: this also locks a SharedCameraClient */
+        /* warning: this also locks a SharedCameraCallbacks */
         shutterNotifyLocked(l.mParameters, client, mMsgType);
         mShutterNotified = true;
     }
@@ -651,16 +652,17 @@
     }
 
     {
-        Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
+        Camera2Client::SharedCameraCallbacks::Lock
+            l(client->mSharedCameraCallbacks);
 
         ALOGV("%s: Notifying of shutter close to client", __FUNCTION__);
-        if (l.mCameraClient != 0) {
+        if (l.mRemoteCallback != 0) {
             // ShutterCallback
-            l.mCameraClient->notifyCallback(CAMERA_MSG_SHUTTER,
+            l.mRemoteCallback->notifyCallback(CAMERA_MSG_SHUTTER,
                                             /*ext1*/0, /*ext2*/0);
 
             // RawCallback with null buffer
-            l.mCameraClient->notifyCallback(CAMERA_MSG_RAW_IMAGE_NOTIFY,
+            l.mRemoteCallback->notifyCallback(CAMERA_MSG_RAW_IMAGE_NOTIFY,
                                             /*ext1*/0, /*ext2*/0);
         } else {
             ALOGV("%s: No client!", __FUNCTION__);
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.cpp b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
index 1f2659c..09b4b27 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
@@ -195,7 +195,7 @@
         entry = frame.find(ANDROID_STATISTICS_FACE_RECTANGLES);
         if (entry.count == 0) {
             // No faces this frame
-            /* warning: locks SharedCameraClient */
+            /* warning: locks SharedCameraCallbacks */
             callbackFaceDetection(client, metadata);
             return OK;
         }
@@ -286,7 +286,7 @@
         metadata.faces = faces.editArray();
     }
 
-    /* warning: locks SharedCameraClient */
+    /* warning: locks SharedCameraCallbacks */
     callbackFaceDetection(client, metadata);
 
     return OK;
@@ -297,9 +297,9 @@
 
     /* Filter out repeated 0-face callbacks, but not when the last frame was >0 */
     if (metadata.number_of_faces != 0 || mLastFrameNumberOfFaces != metadata.number_of_faces) {
-        Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
-        if (l.mCameraClient != NULL) {
-            l.mCameraClient->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
+        Camera2Client::SharedCameraCallbacks::Lock l(client->mSharedCameraCallbacks);
+        if (l.mRemoteCallback != NULL) {
+            l.mRemoteCallback->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
                     NULL, &metadata);
         }
     }
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
index 8d4933c..742577a 100644
--- a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
@@ -22,7 +22,7 @@
 #include <utils/Trace.h>
 
 #include "ProFrameProcessor.h"
-#include "../Camera2Device.h"
+#include "../CameraDeviceBase.h"
 #include "../ProCamera2Client.h"
 
 namespace android {
@@ -62,7 +62,7 @@
     return OK;
 }
 
-void ProFrameProcessor::dump(int fd, const Vector<String16>& args) {
+void ProFrameProcessor::dump(int fd, const Vector<String16>& /*args*/) {
     String8 result("    Latest received frame:\n");
     write(fd, result.string(), result.size());
     mLastFrame.dump(fd, 2, 6);
@@ -71,7 +71,7 @@
 bool ProFrameProcessor::threadLoop() {
     status_t res;
 
-    sp<Camera2Device> device;
+    sp<CameraDeviceBase> device;
     {
         sp<ProCamera2Client> client = mClient.promote();
         if (client == 0) return false;
@@ -125,7 +125,6 @@
 
 status_t ProFrameProcessor::processListeners(const CameraMetadata &frame,
         sp<ProCamera2Client> &client) {
-    status_t res;
     ATRACE_CALL();
     camera_metadata_ro_entry_t entry;
 
diff --git a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
index 6a4b95d..fbc5b93 100644
--- a/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/StreamingProcessor.cpp
@@ -556,9 +556,9 @@
     }
 
     // Call outside locked parameters to allow re-entrancy from notification
-    Camera2Client::SharedCameraClient::Lock l(client->mSharedCameraClient);
-    if (l.mCameraClient != 0) {
-        l.mCameraClient->dataCallbackTimestamp(timestamp,
+    Camera2Client::SharedCameraCallbacks::Lock l(client->mSharedCameraCallbacks);
+    if (l.mRemoteCallback != 0) {
+        l.mRemoteCallback->dataCallbackTimestamp(timestamp,
                 CAMERA_MSG_VIDEO_FRAME,
                 recordingHeap->mBuffers[heapIdx]);
     }