Initial implementation of android.hardware.photography.CameraDevice (service)

* Verified preview streaming requests
* Other things *should* work but unverified / unimplemented in client side

Missing:
* CameraService needs to return static camera info metadata

Bug: 9213377
Change-Id: I71568560fcf18d0e2b408ed1c4d0066647314868
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 83d9ccd..0eead1e 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -31,6 +31,7 @@
     camera3/Camera3InputStream.cpp \
     camera3/Camera3OutputStream.cpp \
     camera3/Camera3ZslStream.cpp \
+    photography/CameraDeviceClient.cpp \
     gui/RingBufferConsumer.cpp \
 
 LOCAL_SHARED_LIBRARIES:= \
diff --git a/services/camera/libcameraservice/Camera2ClientBase.cpp b/services/camera/libcameraservice/Camera2ClientBase.cpp
index 0623b89..5e4832c 100644
--- a/services/camera/libcameraservice/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/Camera2ClientBase.cpp
@@ -28,6 +28,8 @@
 #include "Camera2ClientBase.h"
 #include "camera2/ProFrameProcessor.h"
 
+#include "photography/CameraDeviceClient.h"
+
 #include "Camera2Device.h"
 
 namespace android {
@@ -325,5 +327,6 @@
 
 template class Camera2ClientBase<CameraService::ProClient>;
 template class Camera2ClientBase<CameraService::Client>;
+template class Camera2ClientBase<CameraDeviceClientBase>;
 
 } // namespace android
diff --git a/services/camera/libcameraservice/Camera2ClientBase.h b/services/camera/libcameraservice/Camera2ClientBase.h
index 9001efb..c9a24d7 100644
--- a/services/camera/libcameraservice/Camera2ClientBase.h
+++ b/services/camera/libcameraservice/Camera2ClientBase.h
@@ -101,6 +101,10 @@
 
 protected:
 
+    virtual sp<IBinder> asBinderWrapper() {
+        return IInterface::asBinder();
+    }
+
     virtual status_t      dumpDevice(int fd, const Vector<String16>& args);
 
     /** Binder client interface-related private members */
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 757a781..1b2204e 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -41,6 +41,7 @@
 #include "CameraClient.h"
 #include "Camera2Client.h"
 #include "ProCamera2Client.h"
+#include "photography/CameraDeviceClient.h"
 
 namespace android {
 
@@ -164,7 +165,7 @@
            Mutex::Autolock al(mServiceLock);
 
            /* Find all clients that we need to disconnect */
-           sp<Client> client = mClient[cameraId].promote();
+           sp<BasicClient> client = mClient[cameraId].promote();
            if (client.get() != NULL) {
                clientsToDisconnect.push_back(client);
            }
@@ -313,14 +314,14 @@
 bool CameraService::canConnectUnsafe(int cameraId,
                                      const String16& clientPackageName,
                                      const sp<IBinder>& remoteCallback,
-                                     sp<Client> &client) {
+                                     sp<BasicClient> &client) {
     String8 clientName8(clientPackageName);
     int callingPid = getCallingPid();
 
     if (mClient[cameraId] != 0) {
         client = mClient[cameraId].promote();
         if (client != 0) {
-            if (remoteCallback == client->getRemoteCallback()->asBinder()) {
+            if (remoteCallback == client->getRemote()) {
                 LOG1("CameraService::connect X (pid %d) (the same client)",
                      callingPid);
                 return true;
@@ -370,16 +371,17 @@
         return NULL;
     }
 
-    sp<Client> client;
 
+    sp<Client> client;
     {
         Mutex::Autolock lock(mServiceLock);
+        sp<BasicClient> clientTmp;
         if (!canConnectUnsafe(cameraId, clientPackageName,
                               cameraClient->asBinder(),
-                              /*out*/client)) {
+                              /*out*/clientTmp)) {
             return NULL;
         } else if (client.get() != NULL) {
-            return client;
+            return static_cast<Client*>(clientTmp.get());
         }
 
         int facing = -1;
@@ -415,7 +417,8 @@
             return NULL;
         }
 
-        if (!connectFinishUnsafe(client, client->asBinder())) {
+        if (!connectFinishUnsafe(client,
+                                 client->getRemote())) {
             // this is probably not recoverable.. maybe the client can try again
             // OK: we can only get here if we were originally in PRESENT state
             updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
@@ -434,12 +437,12 @@
 }
 
 bool CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
-                                        const sp<IBinder>& clientBinder) {
+                                        const sp<IBinder>& remoteCallback) {
     if (client->initialize(mModule) != OK) {
         return false;
     }
 
-    clientBinder->linkToDeath(this);
+    remoteCallback->linkToDeath(this);
 
     return true;
 }
@@ -464,7 +467,7 @@
     {
         Mutex::Autolock lock(mServiceLock);
         {
-            sp<Client> client;
+            sp<BasicClient> client;
             if (!canConnectUnsafe(cameraId, clientPackageName,
                                   cameraCb->asBinder(),
                                   /*out*/client)) {
@@ -494,7 +497,7 @@
             return NULL;
         }
 
-        if (!connectFinishUnsafe(client, client->asBinder())) {
+        if (!connectFinishUnsafe(client, client->getRemote())) {
             return NULL;
         }
 
@@ -509,6 +512,88 @@
     return client;
 }
 
+sp<ICameraDeviceUser> CameraService::connect(
+        const sp<ICameraDeviceCallbacks>& cameraCb,
+        int cameraId,
+        const String16& clientPackageName,
+        int clientUid)
+{
+    // TODO: this function needs to return status_t
+    // so that we have an error code when things go wrong and the client is NULL
+
+    String8 clientName8(clientPackageName);
+    int callingPid = getCallingPid();
+
+    LOG1("CameraService::connectDevice E (pid %d \"%s\", id %d)", callingPid,
+            clientName8.string(), cameraId);
+
+    if (!validateConnect(cameraId, /*inout*/clientUid)) {
+        return NULL;
+    }
+
+    sp<CameraDeviceClient> client;
+    {
+        Mutex::Autolock lock(mServiceLock);
+        {
+            sp<BasicClient> client;
+            if (!canConnectUnsafe(cameraId, clientPackageName,
+                                  cameraCb->asBinder(),
+                                  /*out*/client)) {
+                return NULL;
+            }
+        }
+
+        int facing = -1;
+        int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+        // If there are other non-exclusive users of the camera,
+        //  this will tear them down before we can reuse the camera
+        if (isValidCameraId(cameraId)) {
+            // transition from PRESENT -> NOT_AVAILABLE
+            updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
+                         cameraId);
+        }
+
+        switch(deviceVersion) {
+          case CAMERA_DEVICE_API_VERSION_1_0:
+            ALOGE("Camera id %d uses old HAL, doesn't support CameraDevice",
+                  cameraId);
+            return NULL;
+            break;
+           // TODO: don't allow 2.0  Only allow 2.1 and higher
+          case CAMERA_DEVICE_API_VERSION_2_0:
+          case CAMERA_DEVICE_API_VERSION_2_1:
+          case CAMERA_DEVICE_API_VERSION_3_0:
+            client = new CameraDeviceClient(this, cameraCb, String16(),
+                    cameraId, facing, callingPid, USE_CALLING_UID, getpid());
+            break;
+          case -1:
+            ALOGE("Invalid camera id %d", cameraId);
+            return NULL;
+          default:
+            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
+            return NULL;
+        }
+
+        if (!connectFinishUnsafe(client, client->getRemote())) {
+            // this is probably not recoverable.. maybe the client can try again
+            // OK: we can only get here if we were originally in PRESENT state
+            updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
+            return NULL;
+        }
+
+        LOG1("CameraService::connectDevice X (id %d, this pid is %d)", cameraId,
+                getpid());
+
+        mClient[cameraId] = client;
+    }
+    // important: release the mutex here so the client can call back
+    //    into the service from its destructor (can be at the end of the call)
+
+    return client;
+}
+
+
 status_t CameraService::addListener(
                                 const sp<ICameraServiceListener>& listener) {
     ALOGV("%s: Add listener %p", __FUNCTION__, listener.get());
@@ -566,14 +651,14 @@
     Mutex::Autolock lock(mServiceLock);
 
     int outIndex;
-    sp<Client> client = findClientUnsafe(remoteBinder, outIndex);
+    sp<BasicClient> client = findClientUnsafe(remoteBinder, outIndex);
 
     if (client != 0) {
         // Found our camera, clear and leave.
         LOG1("removeClient: clear camera %d", outIndex);
         mClient[outIndex].clear();
 
-        client->unlinkToDeath(this);
+        client->getRemote()->unlinkToDeath(this);
     } else {
 
         sp<ProClient> clientPro = findProClientUnsafe(remoteBinder);
@@ -620,9 +705,9 @@
     return clientPro;
 }
 
-sp<CameraService::Client> CameraService::findClientUnsafe(
+sp<CameraService::BasicClient> CameraService::findClientUnsafe(
                         const wp<IBinder>& cameraClient, int& outIndex) {
-    sp<Client> client;
+    sp<BasicClient> client;
 
     for (int i = 0; i < mNumberOfCameras; i++) {
 
@@ -640,7 +725,7 @@
             continue;
         }
 
-        if (cameraClient == client->getRemoteCallback()->asBinder()) {
+        if (cameraClient == client->getRemote()) {
             // Found our camera
             outIndex = i;
             return client;
@@ -651,7 +736,7 @@
     return NULL;
 }
 
-CameraService::Client* CameraService::getClientByIdUnsafe(int cameraId) {
+CameraService::BasicClient* CameraService::getClientByIdUnsafe(int cameraId) {
     if (cameraId < 0 || cameraId >= mNumberOfCameras) return NULL;
     return mClient[cameraId].unsafe_get();
 }
@@ -906,7 +991,9 @@
 // Provide client pointer for callbacks. Client lock returned from getClientLockFromCookie should
 // be acquired for this to be safe
 CameraService::Client* CameraService::Client::getClientFromCookie(void* user) {
-    Client* client = gCameraService->getClientByIdUnsafe((int) user);
+    BasicClient *basicClient = gCameraService->getClientByIdUnsafe((int) user);
+    // OK: only CameraClient calls this, and they already cast anyway.
+    Client* client = static_cast<Client*>(basicClient);
 
     // This could happen if the Client is in the process of shutting down (the
     // last strong reference is gone, but the destructor hasn't finished
@@ -1058,7 +1145,7 @@
                 }
             }
 
-            sp<Client> client = mClient[i].promote();
+            sp<BasicClient> client = mClient[i].promote();
             if (client == 0) {
                 result = String8::format("  Device is closed, no client instance\n");
                 write(fd, result.string(), result.size());
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index eaa316a..cab804e 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -29,6 +29,8 @@
 #include <camera/ICameraClient.h>
 #include <camera/IProCameraUser.h>
 #include <camera/IProCameraCallbacks.h>
+#include <camera/photography/ICameraDeviceUser.h>
+#include <camera/photography/ICameraDeviceCallbacks.h>
 
 #include <camera/ICameraServiceListener.h>
 
@@ -74,6 +76,11 @@
             const String16& clientPackageName, int clientUid);
     virtual sp<IProCameraUser> connect(const sp<IProCameraCallbacks>& cameraCb,
             int cameraId, const String16& clientPackageName, int clientUid);
+    virtual sp<ICameraDeviceUser> connect(
+            const sp<ICameraDeviceCallbacks>& cameraCb,
+            int cameraId,
+            const String16& clientPackageName,
+            int clientUid);
 
     virtual status_t    addListener(const sp<ICameraServiceListener>& listener);
     virtual status_t    removeListener(
@@ -105,7 +112,7 @@
 
     // returns plain pointer of client. Note that mClientLock should be acquired to
     // prevent the client from destruction. The result can be NULL.
-    virtual Client*     getClientByIdUnsafe(int cameraId);
+    virtual BasicClient* getClientByIdUnsafe(int cameraId);
     virtual Mutex*      getClientLockById(int cameraId);
 
     class BasicClient : public virtual RefBase {
@@ -114,11 +121,17 @@
 
         virtual void          disconnect() = 0;
 
+        // because we can't virtually inherit IInterface, which breaks
+        // virtual inheritance
+        virtual sp<IBinder> asBinderWrapper() = 0;
+
         // Return the remote callback binder object (e.g. IProCameraCallbacks)
-        wp<IBinder>     getRemote() {
+        sp<IBinder>     getRemote() {
             return mRemoteBinder;
         }
 
+        virtual status_t      dump(int fd, const Vector<String16>& args) = 0;
+
     protected:
         BasicClient(const sp<CameraService>& cameraService,
                 const sp<IBinder>& remoteCallback,
@@ -147,7 +160,7 @@
         pid_t                           mServicePid;     // immutable after constructor
 
         // - The app-side Binder interface to receive callbacks from us
-        wp<IBinder>                     mRemoteBinder;   // immutable after constructor
+        sp<IBinder>                     mRemoteBinder;   // immutable after constructor
 
         // permissions management
         status_t                        startCameraOps();
@@ -223,6 +236,10 @@
             return mRemoteCallback;
         }
 
+        virtual sp<IBinder> asBinderWrapper() {
+            return asBinder();
+        }
+
     protected:
         static Mutex*        getClientLockFromCookie(void* user);
         // convert client from cookie. Client lock should be acquired before getting Client.
@@ -296,16 +313,17 @@
                                          const String16& clientPackageName,
                                          const sp<IBinder>& remoteCallback,
                                          /*out*/
-                                         sp<Client> &client);
+                                         sp<BasicClient> &client);
 
     // When connection is successful, initialize client and track its death
     bool                connectFinishUnsafe(const sp<BasicClient>& client,
-                                            const sp<IBinder>& clientBinder);
+                                            const sp<IBinder>& remoteCallback);
 
     virtual sp<BasicClient>  getClientByRemote(const wp<IBinder>& cameraClient);
 
     Mutex               mServiceLock;
-    wp<Client>          mClient[MAX_CAMERAS];  // protected by mServiceLock
+    // either a Client or CameraDeviceClient
+    wp<BasicClient>     mClient[MAX_CAMERAS];  // protected by mServiceLock
     Mutex               mClientLock[MAX_CAMERAS]; // prevent Client destruction inside callbacks
     int                 mNumberOfCameras;
 
@@ -313,7 +331,7 @@
     Vector<weak_pro_client_ptr> mProClientList[MAX_CAMERAS];
 
     // needs to be called with mServiceLock held
-    sp<Client>          findClientUnsafe(const wp<IBinder>& cameraClient, int& outIndex);
+    sp<BasicClient>     findClientUnsafe(const wp<IBinder>& cameraClient, int& outIndex);
     sp<ProClient>       findProClientUnsafe(
                                      const wp<IBinder>& cameraCallbacksRemote);
 
diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.cpp b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
new file mode 100644
index 0000000..3209a56
--- /dev/null
+++ b/services/camera/libcameraservice/photography/CameraDeviceClient.cpp
@@ -0,0 +1,517 @@
+/*
+ * 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 "CameraDeviceClient"
+#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 "camera2/Parameters.h"
+#include "CameraDeviceClient.h"
+#include "camera2/ProFrameProcessor.h"
+#include "CameraDeviceBase.h"
+#include <camera/photography/CaptureRequest.h>
+
+namespace android {
+using namespace camera2;
+
+CameraDeviceClientBase::CameraDeviceClientBase(
+        const sp<CameraService>& cameraService,
+        const sp<ICameraDeviceCallbacks>& remoteCallback,
+        const String16& clientPackageName,
+        int cameraId,
+        int cameraFacing,
+        int clientPid,
+        uid_t clientUid,
+        int servicePid) :
+    BasicClient(cameraService, remoteCallback->asBinder(), clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid),
+    mRemoteCallback(remoteCallback) {
+}
+void CameraDeviceClientBase::notifyError() {
+    // Thread safe. Don't bother locking.
+    sp<ICameraDeviceCallbacks> remoteCb = mRemoteCallback;
+
+    if (remoteCb != 0) {
+        remoteCb->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
+    }
+}
+
+// Interface used by CameraService
+
+CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,
+                                   const sp<ICameraDeviceCallbacks>& remoteCallback,
+                                   const String16& clientPackageName,
+                                   int cameraId,
+                                   int cameraFacing,
+                                   int clientPid,
+                                   uid_t clientUid,
+                                   int servicePid) :
+    Camera2ClientBase(cameraService, remoteCallback, clientPackageName,
+                cameraId, cameraFacing, clientPid, clientUid, servicePid),
+    mRequestIdCounter(0) {
+
+    ATRACE_CALL();
+    ALOGI("CameraDeviceClient %d: Opened", cameraId);
+}
+
+status_t CameraDeviceClient::initialize(camera_module_t *module)
+{
+    ATRACE_CALL();
+    status_t res;
+
+    res = Camera2ClientBase::initialize(module);
+    if (res != OK) {
+        return res;
+    }
+
+    String8 threadName;
+    mFrameProcessor = new ProFrameProcessor(mDevice);
+    threadName = String8::format("CDU-%d-FrameProc", mCameraId);
+    mFrameProcessor->run(threadName.string());
+
+    mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
+                                      FRAME_PROCESSOR_LISTENER_MAX_ID,
+                                      /*listener*/this);
+
+    return OK;
+}
+
+CameraDeviceClient::~CameraDeviceClient() {
+}
+
+status_t CameraDeviceClient::submitRequest(sp<CaptureRequest> request,
+                                         bool streaming) {
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+
+    status_t res;
+
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    if (request == 0) {
+        ALOGE("%s: Camera %d: Sent null request. Rejecting request.",
+              __FUNCTION__, mCameraId);
+        return BAD_VALUE;
+    }
+
+    CameraMetadata metadata(request->mMetadata);
+
+    if (metadata.isEmpty()) {
+        ALOGE("%s: Camera %d: Sent empty metadata packet. Rejecting request.",
+               __FUNCTION__, mCameraId);
+        return BAD_VALUE;
+    } else if (request->mSurfaceList.size() == 0) {
+        ALOGE("%s: Camera %d: Requests must have at least one surface target. "
+              "Rejecting request.", __FUNCTION__, mCameraId);
+        return BAD_VALUE;
+    }
+
+    if (!enforceRequestPermissions(metadata)) {
+        // Callee logs
+        return PERMISSION_DENIED;
+    }
+
+    /**
+     * Write in the output stream IDs which we calculate from
+     * the capture request's list of surface targets
+     */
+    Vector<uint8_t> outputStreamIds;
+    outputStreamIds.setCapacity(request->mSurfaceList.size());
+    for (size_t i = 0; i < request->mSurfaceList.size(); ++i) {
+        sp<Surface> surface = request->mSurfaceList[i];
+
+        if (surface == 0) continue;
+
+        sp<IGraphicBufferProducer> gbp = surface->getIGraphicBufferProducer();
+        int idx = mStreamMap.indexOfKey(gbp->asBinder());
+
+        // Trying to submit request with surface that wasn't created
+        if (idx == NAME_NOT_FOUND) {
+            ALOGE("%s: Camera %d: Tried to submit a request with a surface that"
+                  " we have not called createStream on",
+                  __FUNCTION__, mCameraId);
+            return BAD_VALUE;
+        }
+
+        int streamId = mStreamMap.valueAt(idx);
+        outputStreamIds.push_back(streamId);
+        ALOGV("%s: Camera %d: Appending output stream %d to request",
+              __FUNCTION__, mCameraId, streamId);
+    }
+
+    metadata.update(ANDROID_REQUEST_OUTPUT_STREAMS, &outputStreamIds[0],
+                    outputStreamIds.size());
+
+    // TODO: @hide ANDROID_REQUEST_ID, or use another request token
+    int32_t requestId = mRequestIdCounter++;
+    metadata.update(ANDROID_REQUEST_ID, &requestId, /*size*/1);
+    ALOGV("%s: Camera %d: Submitting request with ID %d",
+          __FUNCTION__, mCameraId, requestId);
+
+    if (streaming) {
+        res = mDevice->setStreamingRequest(metadata);
+        if (res != OK) {
+            ALOGE("%s: Camera %d:  Got error %d after trying to set streaming "
+                  "request", __FUNCTION__, mCameraId, res);
+        } else {
+            mStreamingRequestList.push_back(mRequestIdCounter);
+        }
+    } else {
+        res = mDevice->capture(metadata);
+        if (res != OK) {
+            ALOGE("%s: Camera %d: Got error %d after trying to set capture",
+                  __FUNCTION__, mCameraId, res);
+        }
+    }
+
+    ALOGV("%s: Camera %d: End of function", __FUNCTION__, mCameraId);
+    if (res == OK) {
+        return requestId;
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClient::cancelRequest(int requestId) {
+    ATRACE_CALL();
+    ALOGV("%s, requestId = %d", __FUNCTION__, requestId);
+
+    status_t res;
+
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    Vector<int>::iterator it, end;
+    for (it = mStreamingRequestList.begin(), end = mStreamingRequestList.end();
+         it != end; ++it) {
+        if (*it == requestId) {
+            break;
+        }
+    }
+
+    if (it == end) {
+        ALOGE("%s: Camera%d: Did not find request id %d in list of streaming "
+              "requests", __FUNCTION__, mCameraId, requestId);
+        return BAD_VALUE;
+    }
+
+    res = mDevice->clearStreamingRequest();
+
+    if (res == OK) {
+        ALOGV("%s: Camera %d: Successfully cleared streaming request",
+              __FUNCTION__, mCameraId);
+        mStreamingRequestList.erase(it);
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClient::deleteStream(int streamId) {
+    ATRACE_CALL();
+    ALOGV("%s (streamId = 0x%x)", __FUNCTION__, streamId);
+
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    // Guard against trying to delete non-created streams
+    ssize_t index = NAME_NOT_FOUND;
+    for (size_t i = 0; i < mStreamMap.size(); ++i) {
+        if (streamId == mStreamMap.valueAt(i)) {
+            index = i;
+            break;
+        }
+    }
+
+    if (index == NAME_NOT_FOUND) {
+        ALOGW("%s: Camera %d: Invalid stream ID (%d) specified, no stream "
+              "created yet", __FUNCTION__, mCameraId, streamId);
+        return BAD_VALUE;
+    }
+
+    // Also returns BAD_VALUE if stream ID was not valid
+    res = mDevice->deleteStream(streamId);
+
+    if (res == BAD_VALUE) {
+        ALOGE("%s: Camera %d: Unexpected BAD_VALUE when deleting stream, but we"
+              " already checked and the stream ID (%d) should be valid.",
+              __FUNCTION__, mCameraId, streamId);
+    } else if (res == OK) {
+        mStreamMap.removeItemsAt(index);
+
+        ALOGV("%s: Camera %d: Successfully deleted stream ID (%d)",
+              __FUNCTION__, mCameraId, streamId);
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClient::createStream(int width, int height, int format,
+                      const sp<IGraphicBufferProducer>& bufferProducer)
+{
+    ATRACE_CALL();
+    ALOGV("%s (w = %d, h = %d, f = 0x%x)", __FUNCTION__, width, height, format);
+
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    // Don't create multiple streams for the same target surface
+    {
+        ssize_t index = mStreamMap.indexOfKey(bufferProducer->asBinder());
+        if (index != NAME_NOT_FOUND) {
+            ALOGW("%s: Camera %d: Buffer producer already has a stream for it "
+                  "(ID %d)",
+                  __FUNCTION__, mCameraId, index);
+            return ALREADY_EXISTS;
+        }
+    }
+
+    sp<IBinder> binder;
+    sp<ANativeWindow> anw;
+    if (bufferProducer != 0) {
+        binder = bufferProducer->asBinder();
+        anw = new Surface(bufferProducer);
+    }
+
+    // TODO: remove w,h,f since we are ignoring them
+
+    if ((res = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, &width)) != OK) {
+        ALOGE("%s: Camera %d: Failed to query Surface width", __FUNCTION__,
+              mCameraId);
+        return res;
+    }
+    if ((res = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, &height)) != OK) {
+        ALOGE("%s: Camera %d: Failed to query Surface height", __FUNCTION__,
+              mCameraId);
+        return res;
+    }
+    if ((res = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &format)) != OK) {
+        ALOGE("%s: Camera %d: Failed to query Surface format", __FUNCTION__,
+              mCameraId);
+        return res;
+    }
+
+    // FIXME: remove this override since the default format should be
+    //       IMPLEMENTATION_DEFINED. b/9487482
+    if (format != HAL_PIXEL_FORMAT_BLOB &&
+        format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        ALOGW("%s: Camera %d: Overriding format 0x%x to IMPLEMENTATION_DEFINED",
+              __FUNCTION__, mCameraId, format);
+        format = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+    }
+
+    // TODO: add startConfigure/stopConfigure call to CameraDeviceBase
+    // this will make it so Camera3Device doesn't call configure_streams
+    // after each call, but only once we are done with all.
+
+    int streamId = -1;
+    res = mDevice->createStream(anw, width, height, format, /*size*/1,
+                                &streamId);
+
+    if (res == OK) {
+        mStreamMap.add(bufferProducer->asBinder(), streamId);
+
+        ALOGV("%s: Camera %d: Successfully created a new stream ID %d",
+              __FUNCTION__, mCameraId, streamId);
+        return streamId;
+    }
+
+    return res;
+}
+
+// Create a request object from a template.
+status_t CameraDeviceClient::createDefaultRequest(int templateId,
+                                                  /*out*/
+                                                  CameraMetadata* request)
+{
+    ATRACE_CALL();
+    ALOGV("%s (templateId = 0x%x)", __FUNCTION__, templateId);
+
+    status_t res;
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    CameraMetadata metadata;
+    if ( (res = mDevice->createDefaultRequest(templateId, &metadata) ) == OK &&
+        request != NULL) {
+
+        request->swap(metadata);
+    }
+
+    return res;
+}
+
+status_t CameraDeviceClient::getCameraInfo(int cameraId,
+                                         /*out*/
+                                         camera_metadata** info)
+{
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+
+    status_t res = OK;
+
+    // TODO: remove cameraId. this should be device-specific info, not static.
+    if (cameraId != mCameraId) {
+        return INVALID_OPERATION;
+    }
+
+    if ( (res = checkPid(__FUNCTION__) ) != OK) return res;
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+
+    if (!mDevice.get()) return DEAD_OBJECT;
+
+    CameraMetadata deviceInfo = mDevice->info();
+    *info = deviceInfo.release();
+
+    return res;
+}
+
+status_t CameraDeviceClient::dump(int fd, const Vector<String16>& args) {
+    String8 result;
+    result.appendFormat("CameraDeviceClient[%d] (%p) PID: %d, dump:\n",
+            mCameraId,
+            getRemoteCallback()->asBinder().get(),
+            mClientPid);
+    result.append("  State: ");
+
+    // TODO: print dynamic/request section from most recent requests
+    mFrameProcessor->dump(fd, args);
+
+    return dumpDevice(fd, args);
+}
+
+// TODO: refactor the code below this with IProCameraUser.
+// it's 100% copy-pasted, so lets not change it right now to make it easier.
+
+void CameraDeviceClient::detachDevice() {
+    if (mDevice == 0) return;
+
+    ALOGV("Camera %d: Stopping processors", mCameraId);
+
+    mFrameProcessor->removeListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
+                                    FRAME_PROCESSOR_LISTENER_MAX_ID,
+                                    /*listener*/this);
+    mFrameProcessor->requestExit();
+    ALOGV("Camera %d: Waiting for threads", mCameraId);
+    mFrameProcessor->join();
+    ALOGV("Camera %d: Disconnecting device", mCameraId);
+
+    // WORKAROUND: HAL refuses to disconnect while there's streams in flight
+    {
+        mDevice->clearStreamingRequest();
+
+        status_t code;
+        if ((code = mDevice->waitUntilDrained()) != OK) {
+            ALOGE("%s: waitUntilDrained failed with code 0x%x", __FUNCTION__,
+                  code);
+        }
+    }
+
+    Camera2ClientBase::detachDevice();
+}
+
+/** Device-related methods */
+void CameraDeviceClient::onFrameAvailable(int32_t frameId,
+                                        const CameraMetadata& frame) {
+    ATRACE_CALL();
+    ALOGV("%s", __FUNCTION__);
+
+    Mutex::Autolock icl(mBinderSerializationLock);
+    SharedCameraCallbacks::Lock l(mSharedCameraCallbacks);
+
+    if (mRemoteCallback != NULL) {
+        ALOGV("%s: frame = %p ", __FUNCTION__, &frame);
+        mRemoteCallback->onResultReceived(frameId, frame);
+    }
+
+}
+
+// TODO: move to Camera2ClientBase
+bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
+
+    const int pid = IPCThreadState::self()->getCallingPid();
+    const int selfPid = getpid();
+    camera_metadata_entry_t entry;
+
+    /**
+     * Mixin default important security values
+     * - android.led.transmit = defaulted ON
+     */
+    CameraMetadata staticInfo = mDevice->info();
+    entry = staticInfo.find(ANDROID_LED_AVAILABLE_LEDS);
+    for(size_t i = 0; i < entry.count; ++i) {
+        uint8_t led = entry.data.u8[i];
+
+        switch(led) {
+            case ANDROID_LED_AVAILABLE_LEDS_TRANSMIT: {
+                uint8_t transmitDefault = ANDROID_LED_TRANSMIT_ON;
+                if (!metadata.exists(ANDROID_LED_TRANSMIT)) {
+                    metadata.update(ANDROID_LED_TRANSMIT,
+                                    &transmitDefault, 1);
+                }
+                break;
+            }
+        }
+    }
+
+    // We can do anything!
+    if (pid == selfPid) {
+        return true;
+    }
+
+    /**
+     * Permission check special fields in the request
+     * - android.led.transmit = android.permission.CAMERA_DISABLE_TRANSMIT
+     */
+    entry = metadata.find(ANDROID_LED_TRANSMIT);
+    if (entry.count > 0 && entry.data.u8[0] != ANDROID_LED_TRANSMIT_ON) {
+        String16 permissionString =
+            String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
+        if (!checkCallingPermission(permissionString)) {
+            const int uid = IPCThreadState::self()->getCallingUid();
+            ALOGE("Permission Denial: "
+                  "can't disable transmit LED pid=%d, uid=%d", pid, uid);
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace android
diff --git a/services/camera/libcameraservice/photography/CameraDeviceClient.h b/services/camera/libcameraservice/photography/CameraDeviceClient.h
new file mode 100644
index 0000000..806aa15
--- /dev/null
+++ b/services/camera/libcameraservice/photography/CameraDeviceClient.h
@@ -0,0 +1,141 @@
+/*
+ * 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_PHOTOGRAPHY_CAMERADEVICECLIENT_H
+#define ANDROID_SERVERS_CAMERA_PHOTOGRAPHY_CAMERADEVICECLIENT_H
+
+#include "CameraDeviceBase.h"
+#include "CameraService.h"
+#include "camera2/ProFrameProcessor.h"
+#include "Camera2ClientBase.h"
+#include <camera/photography/ICameraDeviceUser.h>
+#include <camera/photography/ICameraDeviceCallbacks.h>
+
+namespace android {
+
+struct CameraDeviceClientBase :
+        public CameraService::BasicClient, public BnCameraDeviceUser
+{
+    typedef ICameraDeviceCallbacks TCamCallbacks;
+
+    const sp<ICameraDeviceCallbacks>& getRemoteCallback() {
+        return mRemoteCallback;
+    }
+
+protected:
+    CameraDeviceClientBase(const sp<CameraService>& cameraService,
+            const sp<ICameraDeviceCallbacks>& remoteCallback,
+            const String16& clientPackageName,
+            int cameraId,
+            int cameraFacing,
+            int clientPid,
+            uid_t clientUid,
+            int servicePid);
+
+    virtual void notifyError();
+
+    sp<ICameraDeviceCallbacks> mRemoteCallback;
+};
+
+/**
+ * Implements the binder ICameraDeviceUser API,
+ * meant for HAL3-public implementation of
+ * android.hardware.photography.CameraDevice
+ */
+class CameraDeviceClient :
+        public Camera2ClientBase<CameraDeviceClientBase>,
+        public camera2::ProFrameProcessor::FilteredListener
+{
+public:
+    /**
+     * ICameraDeviceUser interface (see ICameraDeviceUser for details)
+     */
+
+    // Note that the callee gets a copy of the metadata.
+    virtual int           submitRequest(sp<CaptureRequest> request,
+                                        bool streaming = false);
+    virtual status_t      cancelRequest(int requestId);
+
+    // Returns -EBUSY if device is not idle
+    virtual status_t      deleteStream(int streamId);
+
+    virtual status_t      createStream(
+            int width,
+            int height,
+            int format,
+            const sp<IGraphicBufferProducer>& bufferProducer);
+
+    // Create a request object from a template.
+    virtual status_t      createDefaultRequest(int templateId,
+                                               /*out*/
+                                               CameraMetadata* request);
+
+    // Get the static metadata for the camera
+    // -- Caller owns the newly allocated metadata
+    virtual status_t      getCameraInfo(int cameraId,
+                                        /*out*/
+                                        camera_metadata** info);
+
+    /**
+     * Interface used by CameraService
+     */
+
+    CameraDeviceClient(const sp<CameraService>& cameraService,
+            const sp<ICameraDeviceCallbacks>& remoteCallback,
+            const String16& clientPackageName,
+            int cameraId,
+            int cameraFacing,
+            int clientPid,
+            uid_t clientUid,
+            int servicePid);
+    virtual ~CameraDeviceClient();
+
+    virtual status_t      initialize(camera_module_t *module);
+
+    virtual status_t      dump(int fd, const Vector<String16>& args);
+
+    /**
+     * Interface used by independent components of CameraDeviceClient.
+     */
+protected:
+    /** FilteredListener implementation **/
+    virtual void          onFrameAvailable(int32_t frameId,
+                                           const CameraMetadata& frame);
+    virtual void          detachDevice();
+
+private:
+    /** ICameraDeviceUser interface-related private members */
+
+    /** 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;
+
+    /** Utility members */
+    bool enforceRequestPermissions(CameraMetadata& metadata);
+
+    // IGraphicsBufferProducer binder -> Stream ID
+    KeyedVector<sp<IBinder>, int> mStreamMap;
+
+    // Stream ID
+    Vector<int> mStreamingRequestList;
+
+    int32_t mRequestIdCounter;
+};
+
+}; // namespace android
+
+#endif