Merge "Make limitations of MPEG4Writer explicit" into jb-mr2-dev
diff --git a/camera/Camera.cpp b/camera/Camera.cpp
index f417c90..1b136de 100644
--- a/camera/Camera.cpp
+++ b/camera/Camera.cpp
@@ -96,32 +96,14 @@
     return c->unlock();
 }
 
-// pass the buffered Surface to the camera service
-status_t Camera::setPreviewDisplay(const sp<Surface>& surface)
-{
-    ALOGV("setPreviewDisplay(%p)", surface.get());
-    sp <ICamera> c = mCamera;
-    if (c == 0) return NO_INIT;
-    if (surface != 0) {
-        return c->setPreviewDisplay(surface);
-    } else {
-        ALOGD("app passed NULL surface");
-        return c->setPreviewDisplay(0);
-    }
-}
-
 // pass the buffered IGraphicBufferProducer to the camera service
 status_t Camera::setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer)
 {
     ALOGV("setPreviewTexture(%p)", bufferProducer.get());
     sp <ICamera> c = mCamera;
     if (c == 0) return NO_INIT;
-    if (bufferProducer != 0) {
-        return c->setPreviewTexture(bufferProducer);
-    } else {
-        ALOGD("app passed NULL surface");
-        return c->setPreviewTexture(0);
-    }
+    ALOGD_IF(bufferProducer == 0, "app passed NULL surface");
+    return c->setPreviewTexture(bufferProducer);
 }
 
 // start preview mode
@@ -283,7 +265,14 @@
 void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
                           camera_frame_metadata_t *metadata)
 {
-    return CameraBaseT::dataCallback(msgType, dataPtr, metadata);
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+    if (listener != NULL) {
+        listener->postData(msgType, dataPtr, metadata);
+    }
 }
 
 // callback from camera service when timestamped frame is ready
@@ -302,7 +291,15 @@
         return;
     }
 
-    if (!CameraBaseT::dataCallbackTimestamp(timestamp, msgType, dataPtr)) {
+    sp<CameraListener> listener;
+    {
+        Mutex::Autolock _l(mLock);
+        listener = mListener;
+    }
+
+    if (listener != NULL) {
+        listener->postDataTimestamp(timestamp, msgType, dataPtr);
+    } else {
         ALOGW("No listener was set. Drop a recording frame.");
         releaseRecordingFrame(dataPtr);
     }
diff --git a/camera/CameraBase.cpp b/camera/CameraBase.cpp
index 29096da..c25c5fd 100644
--- a/camera/CameraBase.cpp
+++ b/camera/CameraBase.cpp
@@ -176,41 +176,6 @@
     }
 }
 
-// callback from camera service when frame or image is ready
-template <typename TCam, typename TCamTraits>
-void CameraBase<TCam, TCamTraits>::dataCallback(int32_t msgType,
-                                                const sp<IMemory>& dataPtr,
-                                                camera_frame_metadata *metadata)
-{
-    sp<TCamListener> listener;
-    {
-        Mutex::Autolock _l(mLock);
-        listener = mListener;
-    }
-    if (listener != NULL) {
-        listener->postData(msgType, dataPtr, metadata);
-    }
-}
-
-// callback from camera service when timestamped frame is ready
-template <typename TCam, typename TCamTraits>
-bool CameraBase<TCam, TCamTraits>::dataCallbackTimestamp(nsecs_t timestamp,
-                                                         int32_t msgType,
-                                                   const sp<IMemory>& dataPtr)
-{
-    sp<TCamListener> listener;
-    {
-        Mutex::Autolock _l(mLock);
-        listener = mListener;
-    }
-    if (listener != NULL) {
-        listener->postDataTimestamp(timestamp, msgType, dataPtr);
-        return true;
-    }
-
-    return false;
-}
-
 template <typename TCam, typename TCamTraits>
 int CameraBase<TCam, TCamTraits>::getNumberOfCameras() {
     const sp<ICameraService> cs = getCameraService();
diff --git a/camera/ICamera.cpp b/camera/ICamera.cpp
index 5d210e7..8900867 100644
--- a/camera/ICamera.cpp
+++ b/camera/ICamera.cpp
@@ -29,7 +29,6 @@
 
 enum {
     DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
-    SET_PREVIEW_DISPLAY,
     SET_PREVIEW_TEXTURE,
     SET_PREVIEW_CALLBACK_FLAG,
     START_PREVIEW,
@@ -68,17 +67,6 @@
         remote()->transact(DISCONNECT, data, &reply);
     }
 
-    // pass the buffered Surface to the camera service
-    status_t setPreviewDisplay(const sp<Surface>& surface)
-    {
-        ALOGV("setPreviewDisplay");
-        Parcel data, reply;
-        data.writeInterfaceToken(ICamera::getInterfaceDescriptor());
-        Surface::writeToParcel(surface, &data);
-        remote()->transact(SET_PREVIEW_DISPLAY, data, &reply);
-        return reply.readInt32();
-    }
-
     // pass the buffered IGraphicBufferProducer to the camera service
     status_t setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer)
     {
@@ -282,13 +270,6 @@
             disconnect();
             return NO_ERROR;
         } break;
-        case SET_PREVIEW_DISPLAY: {
-            ALOGV("SET_PREVIEW_DISPLAY");
-            CHECK_INTERFACE(ICamera, data, reply);
-            sp<Surface> surface = Surface::readFromParcel(data);
-            reply->writeInt32(setPreviewDisplay(surface));
-            return NO_ERROR;
-        } break;
         case SET_PREVIEW_TEXTURE: {
             ALOGV("SET_PREVIEW_TEXTURE");
             CHECK_INTERFACE(ICamera, data, reply);
diff --git a/camera/IProCameraCallbacks.cpp b/camera/IProCameraCallbacks.cpp
index 6cd36bf..b9cd14d 100644
--- a/camera/IProCameraCallbacks.cpp
+++ b/camera/IProCameraCallbacks.cpp
@@ -34,8 +34,6 @@
 
 enum {
     NOTIFY_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
-    DATA_CALLBACK,
-    DATA_CALLBACK_TIMESTAMP,
     LOCK_STATUS_CHANGED,
     RESULT_RECEIVED,
 };
@@ -63,37 +61,6 @@
         remote()->transact(NOTIFY_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
-    // generic data callback from camera service to app with image data
-    void dataCallback(int32_t msgType, const sp<IMemory>& imageData,
-                      camera_frame_metadata_t *metadata)
-    {
-        ALOGV("dataCallback");
-        Parcel data, reply;
-        data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor());
-        data.writeInt32(msgType);
-        data.writeStrongBinder(imageData->asBinder());
-        if (metadata) {
-            data.writeInt32(metadata->number_of_faces);
-            data.write(metadata->faces,
-                            sizeof(camera_face_t) * metadata->number_of_faces);
-        }
-        remote()->transact(DATA_CALLBACK, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
-    // generic data callback from camera service to app with image data
-    void dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
-                                                  const sp<IMemory>& imageData)
-    {
-        ALOGV("dataCallback");
-        Parcel data, reply;
-        data.writeInterfaceToken(IProCameraCallbacks::getInterfaceDescriptor());
-        data.writeInt64(timestamp);
-        data.writeInt32(msgType);
-        data.writeStrongBinder(imageData->asBinder());
-        remote()->transact(DATA_CALLBACK_TIMESTAMP, data, &reply,
-                                                          IBinder::FLAG_ONEWAY);
-    }
-
     void onLockStatusChanged(LockStatus newLockStatus) {
         ALOGV("onLockStatusChanged");
         Parcel data, reply;
@@ -132,33 +99,6 @@
             notifyCallback(msgType, ext1, ext2);
             return NO_ERROR;
         } break;
-        case DATA_CALLBACK: {
-            ALOGV("DATA_CALLBACK");
-            CHECK_INTERFACE(IProCameraCallbacks, data, reply);
-            int32_t msgType = data.readInt32();
-            sp<IMemory> imageData = interface_cast<IMemory>(
-                                                       data.readStrongBinder());
-            camera_frame_metadata_t *metadata = NULL;
-            if (data.dataAvail() > 0) {
-                metadata = new camera_frame_metadata_t;
-                metadata->number_of_faces = data.readInt32();
-                metadata->faces = (camera_face_t *) data.readInplace(
-                        sizeof(camera_face_t) * metadata->number_of_faces);
-            }
-            dataCallback(msgType, imageData, metadata);
-            if (metadata) delete metadata;
-            return NO_ERROR;
-        } break;
-        case DATA_CALLBACK_TIMESTAMP: {
-            ALOGV("DATA_CALLBACK_TIMESTAMP");
-            CHECK_INTERFACE(IProCameraCallbacks, data, reply);
-            nsecs_t timestamp = data.readInt64();
-            int32_t msgType = data.readInt32();
-            sp<IMemory> imageData = interface_cast<IMemory>(
-                                                       data.readStrongBinder());
-            dataCallbackTimestamp(timestamp, msgType, imageData);
-            return NO_ERROR;
-        } break;
         case LOCK_STATUS_CHANGED: {
             ALOGV("LOCK_STATUS_CHANGED");
             CHECK_INTERFACE(IProCameraCallbacks, data, reply);
diff --git a/camera/IProCameraUser.cpp b/camera/IProCameraUser.cpp
index c9d98aa..0c94bd4 100644
--- a/camera/IProCameraUser.cpp
+++ b/camera/IProCameraUser.cpp
@@ -40,8 +40,7 @@
     HAS_EXCLUSIVE_LOCK,
     SUBMIT_REQUEST,
     CANCEL_REQUEST,
-    REQUEST_STREAM,
-    CANCEL_STREAM,
+    DELETE_STREAM,
     CREATE_STREAM,
     CREATE_DEFAULT_REQUEST,
     GET_CAMERA_INFO,
@@ -200,22 +199,13 @@
         return reply.readInt32();
     }
 
-    virtual status_t requestStream(int streamId)
+    virtual status_t deleteStream(int streamId)
     {
         Parcel data, reply;
         data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
         data.writeInt32(streamId);
 
-        remote()->transact(REQUEST_STREAM, data, &reply);
-        return reply.readInt32();
-    }
-    virtual status_t cancelStream(int streamId)
-    {
-        Parcel data, reply;
-        data.writeInterfaceToken(IProCameraUser::getInterfaceDescriptor());
-        data.writeInt32(streamId);
-
-        remote()->transact(CANCEL_STREAM, data, &reply);
+        remote()->transact(DELETE_STREAM, data, &reply);
         return reply.readInt32();
     }
 
@@ -334,16 +324,10 @@
             reply->writeInt32(cancelRequest(requestId));
             return NO_ERROR;
         } break;
-        case REQUEST_STREAM: {
+        case DELETE_STREAM: {
             CHECK_INTERFACE(IProCameraUser, data, reply);
             int streamId = data.readInt32();
-            reply->writeInt32(requestStream(streamId));
-            return NO_ERROR;
-        } break;
-        case CANCEL_STREAM: {
-            CHECK_INTERFACE(IProCameraUser, data, reply);
-            int streamId = data.readInt32();
-            reply->writeInt32(cancelStream(streamId));
+            reply->writeInt32(deleteStream(streamId));
             return NO_ERROR;
         } break;
         case CREATE_STREAM: {
diff --git a/camera/ProCamera.cpp b/camera/ProCamera.cpp
index 3cfabf6..396b009 100644
--- a/camera/ProCamera.cpp
+++ b/camera/ProCamera.cpp
@@ -60,21 +60,6 @@
     return CameraBaseT::notifyCallback(msgType, ext1, ext2);
 }
 
-// callback from camera service when frame or image is ready
-void ProCamera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr,
-                          camera_frame_metadata_t *metadata)
-{
-    return CameraBaseT::dataCallback(msgType, dataPtr, metadata);
-}
-
-// callback from camera service when timestamped frame is ready
-void ProCamera::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
-                                   const sp<IMemory>& dataPtr)
-{
-    CameraBaseT::dataCallbackTimestamp(timestamp, msgType, dataPtr);
-}
-
-
 void ProCamera::onLockStatusChanged(
                                  IProCameraCallbacks::LockStatus newLockStatus)
 {
@@ -185,7 +170,7 @@
     sp <IProCameraUser> c = mCamera;
     if (c == 0) return NO_INIT;
 
-    status_t s = c->cancelStream(streamId);
+    status_t s = c->deleteStream(streamId);
 
     mStreams.removeItem(streamId);
 
@@ -330,10 +315,7 @@
     CpuConsumer::LockedBuffer buf;
 
     if (listener.get() != NULL) {
-        if (listener->useOnFrameAvailable()) {
-            listener->onFrameAvailable(streamId, stream.cpuConsumer);
-            return;
-        }
+        listener->onFrameAvailable(streamId, stream.cpuConsumer);
     }
 
     // Unblock waitForFrame(id) callers
diff --git a/camera/tests/ProCameraTests.cpp b/camera/tests/ProCameraTests.cpp
index 1a8564e..71813ae 100644
--- a/camera/tests/ProCameraTests.cpp
+++ b/camera/tests/ProCameraTests.cpp
@@ -271,13 +271,11 @@
         free_camera_metadata(request);
     }
 
-    // TODO: remove
-
-    virtual void notify(int32_t , int32_t , int32_t ) {}
-    virtual void postData(int32_t , const sp<IMemory>& ,
-                          camera_frame_metadata_t *) {}
-    virtual void postDataTimestamp(nsecs_t , int32_t , const sp<IMemory>& ) {}
-
+    virtual void notify(int32_t msg, int32_t ext1, int32_t ext2) {
+        dout << "Notify received: msg " << std::hex << msg
+             << ", ext1: " << std::hex << ext1 << ", ext2: " << std::hex << ext2
+             << std::endl;
+    }
 
     Vector<ProEvent> mProEventList;
     Mutex             mListenerMutex;
@@ -717,6 +715,7 @@
         return;
     }
 
+    // FIXME: Note this test is broken because onBufferReceived was removed
     mListener->SetEventMask(ProEvent_Mask(BUFFER_RECEIVED));
 
     int streamId = -1;
@@ -783,6 +782,7 @@
         return;
     }
 
+    // FIXME: Note this test is broken because onBufferReceived was removed
     mListener->SetEventMask(ProEvent_Mask(BUFFER_RECEIVED));
 
     int streamId = -1;
diff --git a/include/camera/Camera.h b/include/camera/Camera.h
index 71c66ce..37626a4 100644
--- a/include/camera/Camera.h
+++ b/include/camera/Camera.h
@@ -74,9 +74,6 @@
             status_t    lock();
             status_t    unlock();
 
-            // pass the buffered Surface to the camera service
-            status_t    setPreviewDisplay(const sp<Surface>& surface);
-
             // pass the buffered IGraphicBufferProducer to the camera service
             status_t    setPreviewTexture(const sp<IGraphicBufferProducer>& bufferProducer);
 
diff --git a/include/camera/CameraBase.h b/include/camera/CameraBase.h
index 2735a86..9b08c0f 100644
--- a/include/camera/CameraBase.h
+++ b/include/camera/CameraBase.h
@@ -91,12 +91,6 @@
     ////////////////////////////////////////////////////////
     virtual void         notifyCallback(int32_t msgType, int32_t ext,
                                         int32_t ext2);
-    virtual void         dataCallback(int32_t msgType,
-                                      const sp<IMemory>& dataPtr,
-                                      camera_frame_metadata *metadata);
-    bool                 dataCallbackTimestamp(nsecs_t timestamp,
-                                               int32_t msgType,
-                                               const sp<IMemory>& dataPtr);
 
     ////////////////////////////////////////////////////////
     // Common instance variables
@@ -115,7 +109,7 @@
 
     const int                        mCameraId;
 
-    typedef CameraBase<TCam>        CameraBaseT;
+    typedef CameraBase<TCam>         CameraBaseT;
 };
 
 }; // namespace android
diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h
index eccaa41..2236c1f 100644
--- a/include/camera/ICamera.h
+++ b/include/camera/ICamera.h
@@ -46,9 +46,6 @@
     // allow other processes to use this ICamera interface
     virtual status_t        unlock() = 0;
 
-    // pass the buffered Surface to the camera service
-    virtual status_t        setPreviewDisplay(const sp<Surface>& surface) = 0;
-
     // pass the buffered IGraphicBufferProducer to the camera service
     virtual status_t        setPreviewTexture(
             const sp<IGraphicBufferProducer>& bufferProducer) = 0;
diff --git a/include/camera/IProCameraCallbacks.h b/include/camera/IProCameraCallbacks.h
index fc24026..563ec17 100644
--- a/include/camera/IProCameraCallbacks.h
+++ b/include/camera/IProCameraCallbacks.h
@@ -28,19 +28,14 @@
 
 namespace android {
 
-class IProCameraCallbacks: public IInterface
+class IProCameraCallbacks : public IInterface
 {
 public:
     DECLARE_META_INTERFACE(ProCameraCallbacks);
 
-    virtual void            notifyCallback(int32_t msgType, int32_t ext1,
-                                                              int32_t ext2) = 0;
-    virtual void            dataCallback(int32_t msgType,
-                                         const sp<IMemory>& data,
-                                         camera_frame_metadata_t *metadata) = 0;
-    virtual void            dataCallbackTimestamp(nsecs_t timestamp,
-                                                  int32_t msgType,
-                                                  const sp<IMemory>& data) = 0;
+    virtual void            notifyCallback(int32_t msgType,
+                                           int32_t ext1,
+                                           int32_t ext2) = 0;
 
     enum LockStatus {
         LOCK_ACQUIRED,
@@ -53,12 +48,13 @@
     /** Missing by design: implementation is client-side in ProCamera.cpp **/
     // virtual void onBufferReceived(int streamId,
     //                               const CpuConsumer::LockedBufer& buf);
-    virtual void onResultReceived(int32_t frameId, camera_metadata* result) = 0;
+    virtual void            onResultReceived(int32_t frameId,
+                                             camera_metadata* result) = 0;
 };
 
 // ----------------------------------------------------------------------------
 
-class BnProCameraCallbacks: public BnInterface<IProCameraCallbacks>
+class BnProCameraCallbacks : public BnInterface<IProCameraCallbacks>
 {
 public:
     virtual status_t    onTransact( uint32_t code,
diff --git a/include/camera/IProCameraUser.h b/include/camera/IProCameraUser.h
index 7bddb0c..45b818c 100644
--- a/include/camera/IProCameraUser.h
+++ b/include/camera/IProCameraUser.h
@@ -61,8 +61,7 @@
                                           bool streaming = false) = 0;
     virtual status_t        cancelRequest(int requestId) = 0;
 
-    virtual status_t        requestStream(int streamId) = 0;
-    virtual status_t        cancelStream(int streamId) = 0;
+    virtual status_t        deleteStream(int streamId) = 0;
     virtual status_t        createStream(
                                       int width, int height, int format,
                                       const sp<IGraphicBufferProducer>& bufferProducer,
diff --git a/include/camera/ProCamera.h b/include/camera/ProCamera.h
index 5d6cfaa..3d1652f 100644
--- a/include/camera/ProCamera.h
+++ b/include/camera/ProCamera.h
@@ -40,9 +40,11 @@
 
 // All callbacks on this class are concurrent
 // (they come from separate threads)
-class ProCameraListener : public CameraListener
+class ProCameraListener : virtual public RefBase
 {
 public:
+    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
+
     // Lock has been acquired. Write operations now available.
     virtual void onLockAcquired() = 0;
     // Lock has been released with exclusiveUnlock.
@@ -53,19 +55,9 @@
     // Lock free.
     virtual void onTriggerNotify(int32_t msgType, int32_t ext1, int32_t ext2)
                                                                             = 0;
-
-    // OnBufferReceived and OnRequestReceived can come in with any order,
+    // onFrameAvailable and OnResultReceived can come in with any order,
     // use android.sensor.timestamp and LockedBuffer.timestamp to correlate them
 
-    // TODO: remove onBufferReceived
-
-    // A new frame buffer has been received for this stream.
-    // -- This callback only fires for createStreamCpu streams
-    // -- Use buf.timestamp to correlate with metadata's
-    //    android.sensor.timestamp
-    // -- The buffer must not be accessed after this function call completes
-    virtual void onBufferReceived(int streamId,
-                                  const CpuConsumer::LockedBuffer& buf) = 0;
     /**
       * A new metadata buffer has been received.
       * -- Ownership of request passes on to the callee, free with
@@ -77,17 +69,14 @@
 
     // A new frame buffer has been received for this stream.
     // -- This callback only fires for createStreamCpu streams
-    // -- Use buf.timestamp to correlate with metadata's android.sensor.timestamp
+    // -- A buffer may be obtained by calling cpuConsumer->lockNextBuffer
+    // -- Use buf.timestamp to correlate with result's android.sensor.timestamp
     // -- The buffer should be accessed with CpuConsumer::lockNextBuffer
     //      and CpuConsumer::unlockBuffer
     virtual void onFrameAvailable(int /*streamId*/,
                                   const sp<CpuConsumer>& /*cpuConsumer*/) {
     }
 
-    // TODO: Remove useOnFrameAvailable
-    virtual bool useOnFrameAvailable() {
-        return false;
-    }
 };
 
 class ProCamera;
@@ -249,14 +238,10 @@
     ////////////////////////////////////////////////////////
     // IProCameraCallbacks implementation
     ////////////////////////////////////////////////////////
-    virtual void        notifyCallback(int32_t msgType, int32_t ext,
+    virtual void        notifyCallback(int32_t msgType,
+                                       int32_t ext,
                                        int32_t ext2);
-    virtual void        dataCallback(int32_t msgType,
-                                     const sp<IMemory>& dataPtr,
-                                     camera_frame_metadata_t *metadata);
-    virtual void        dataCallbackTimestamp(nsecs_t timestamp,
-                                              int32_t msgType,
-                                              const sp<IMemory>& dataPtr);
+
     virtual void        onLockStatusChanged(
                                 IProCameraCallbacks::LockStatus newLockStatus);
 
diff --git a/include/media/IMediaRecorder.h b/include/media/IMediaRecorder.h
index 8d7f11d..3e67550 100644
--- a/include/media/IMediaRecorder.h
+++ b/include/media/IMediaRecorder.h
@@ -35,7 +35,7 @@
 
     virtual status_t setCamera(const sp<ICamera>& camera,
                                const sp<ICameraRecordingProxy>& proxy) = 0;
-    virtual status_t setPreviewSurface(const sp<Surface>& surface) = 0;
+    virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0;
     virtual status_t setVideoSource(int vs) = 0;
     virtual status_t setAudioSource(int as) = 0;
     virtual status_t setOutputFormat(int of) = 0;
diff --git a/include/media/IStreamSource.h b/include/media/IStreamSource.h
index 39e0a9e..677119b 100644
--- a/include/media/IStreamSource.h
+++ b/include/media/IStreamSource.h
@@ -37,6 +37,9 @@
     enum {
         // Video PES packets contain exactly one (aligned) access unit.
         kFlagAlignedVideoData = 1,
+
+        // Timestamps are in ALooper::GetNowUs() units.
+        kFlagIsRealTimeData   = 2,
     };
     virtual uint32_t flags() const { return 0; }
 };
diff --git a/include/media/MediaRecorderBase.h b/include/media/MediaRecorderBase.h
index 8dd40d2..d7ac302 100644
--- a/include/media/MediaRecorderBase.h
+++ b/include/media/MediaRecorderBase.h
@@ -42,7 +42,7 @@
     virtual status_t setVideoFrameRate(int frames_per_second) = 0;
     virtual status_t setCamera(const sp<ICamera>& camera,
                                const sp<ICameraRecordingProxy>& proxy) = 0;
-    virtual status_t setPreviewSurface(const sp<Surface>& surface) = 0;
+    virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface) = 0;
     virtual status_t setOutputFile(const char *path) = 0;
     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length) = 0;
     virtual status_t setOutputFileAuxiliary(int fd) {return INVALID_OPERATION;}
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 3b33479..88a42a0 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -207,7 +207,7 @@
     void        died();
     status_t    initCheck();
     status_t    setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
-    status_t    setPreviewSurface(const sp<Surface>& surface);
+    status_t    setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
     status_t    setVideoSource(int vs);
     status_t    setAudioSource(int as);
     status_t    setOutputFormat(int of);
diff --git a/include/media/stagefright/CameraSource.h b/include/media/stagefright/CameraSource.h
index cf38b14..a829916 100644
--- a/include/media/stagefright/CameraSource.h
+++ b/include/media/stagefright/CameraSource.h
@@ -82,7 +82,7 @@
                                           uid_t clientUid,
                                           Size videoSize,
                                           int32_t frameRate,
-                                          const sp<Surface>& surface,
+                                          const sp<IGraphicBufferProducer>& surface,
                                           bool storeMetaDataInVideoBuffers = false);
 
     virtual ~CameraSource();
@@ -154,7 +154,7 @@
     sp<Camera>   mCamera;
     sp<ICameraRecordingProxy>   mCameraRecordingProxy;
     sp<DeathNotifier> mDeathNotifier;
-    sp<Surface>  mSurface;
+    sp<IGraphicBufferProducer>  mSurface;
     sp<MetaData> mMeta;
 
     int64_t mStartTimeUs;
@@ -169,7 +169,7 @@
     CameraSource(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy,
                  int32_t cameraId, const String16& clientName, uid_t clientUid,
                  Size videoSize, int32_t frameRate,
-                 const sp<Surface>& surface,
+                 const sp<IGraphicBufferProducer>& surface,
                  bool storeMetaDataInVideoBuffers);
 
     virtual void startCameraRecording();
diff --git a/include/media/stagefright/CameraSourceTimeLapse.h b/include/media/stagefright/CameraSourceTimeLapse.h
index 774772b..6b7a63c 100644
--- a/include/media/stagefright/CameraSourceTimeLapse.h
+++ b/include/media/stagefright/CameraSourceTimeLapse.h
@@ -40,7 +40,7 @@
         uid_t clientUid,
         Size videoSize,
         int32_t videoFrameRate,
-        const sp<Surface>& surface,
+        const sp<IGraphicBufferProducer>& surface,
         int64_t timeBetweenTimeLapseFrameCaptureUs);
 
     virtual ~CameraSourceTimeLapse();
@@ -115,7 +115,7 @@
         uid_t clientUid,
         Size videoSize,
         int32_t videoFrameRate,
-        const sp<Surface>& surface,
+        const sp<IGraphicBufferProducer>& surface,
         int64_t timeBetweenTimeLapseFrameCaptureUs);
 
     // Wrapper over CameraSource::signalBufferReturned() to implement quick stop.
diff --git a/media/libmedia/IMediaRecorder.cpp b/media/libmedia/IMediaRecorder.cpp
index c935d97..8e58162 100644
--- a/media/libmedia/IMediaRecorder.cpp
+++ b/media/libmedia/IMediaRecorder.cpp
@@ -87,12 +87,12 @@
         return interface_cast<IGraphicBufferProducer>(reply.readStrongBinder());
     }
 
-    status_t setPreviewSurface(const sp<Surface>& surface)
+    status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface)
     {
         ALOGV("setPreviewSurface(%p)", surface.get());
         Parcel data, reply;
         data.writeInterfaceToken(IMediaRecorder::getInterfaceDescriptor());
-        Surface::writeToParcel(surface, &data);
+        data.writeStrongBinder(surface->asBinder());
         remote()->transact(SET_PREVIEW_SURFACE, data, &reply);
         return reply.readInt32();
     }
@@ -443,7 +443,7 @@
         case SET_PREVIEW_SURFACE: {
             ALOGV("SET_PREVIEW_SURFACE");
             CHECK_INTERFACE(IMediaRecorder, data, reply);
-            sp<Surface> surface = Surface::readFromParcel(data);
+            sp<IGraphicBufferProducer> surface = interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
             reply->writeInt32(setPreviewSurface(surface));
             return NO_ERROR;
         } break;
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 3ac98cc..3710e46 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -49,7 +49,7 @@
     return ret;
 }
 
-status_t MediaRecorder::setPreviewSurface(const sp<Surface>& surface)
+status_t MediaRecorder::setPreviewSurface(const sp<IGraphicBufferProducer>& surface)
 {
     ALOGV("setPreviewSurface(%p)", surface.get());
     if (mMediaRecorder == NULL) {
diff --git a/media/libmediaplayerservice/MediaRecorderClient.cpp b/media/libmediaplayerservice/MediaRecorderClient.cpp
index a52b238..a9820e0 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.cpp
+++ b/media/libmediaplayerservice/MediaRecorderClient.cpp
@@ -81,7 +81,7 @@
     return mRecorder->setCamera(camera, proxy);
 }
 
-status_t MediaRecorderClient::setPreviewSurface(const sp<Surface>& surface)
+status_t MediaRecorderClient::setPreviewSurface(const sp<IGraphicBufferProducer>& surface)
 {
     ALOGV("setPreviewSurface");
     Mutex::Autolock lock(mLock);
diff --git a/media/libmediaplayerservice/MediaRecorderClient.h b/media/libmediaplayerservice/MediaRecorderClient.h
index bd0eaf1..a65ec9f 100644
--- a/media/libmediaplayerservice/MediaRecorderClient.h
+++ b/media/libmediaplayerservice/MediaRecorderClient.h
@@ -32,7 +32,7 @@
 public:
     virtual     status_t   setCamera(const sp<ICamera>& camera,
                                     const sp<ICameraRecordingProxy>& proxy);
-    virtual     status_t   setPreviewSurface(const sp<Surface>& surface);
+    virtual     status_t   setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
     virtual     status_t   setVideoSource(int vs);
     virtual     status_t   setAudioSource(int as);
     virtual     status_t   setOutputFormat(int of);
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f570856..c2c9985 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -224,7 +224,7 @@
     return OK;
 }
 
-status_t StagefrightRecorder::setPreviewSurface(const sp<Surface> &surface) {
+status_t StagefrightRecorder::setPreviewSurface(const sp<IGraphicBufferProducer> &surface) {
     ALOGV("setPreviewSurface: %p", surface.get());
     mPreviewSurface = surface;
 
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index fbe6fa6..c864207 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -51,7 +51,7 @@
     virtual status_t setVideoSize(int width, int height);
     virtual status_t setVideoFrameRate(int frames_per_second);
     virtual status_t setCamera(const sp<ICamera>& camera, const sp<ICameraRecordingProxy>& proxy);
-    virtual status_t setPreviewSurface(const sp<Surface>& surface);
+    virtual status_t setPreviewSurface(const sp<IGraphicBufferProducer>& surface);
     virtual status_t setOutputFile(const char *path);
     virtual status_t setOutputFile(int fd, int64_t offset, int64_t length);
     virtual status_t setParameters(const String8& params);
@@ -71,7 +71,7 @@
 private:
     sp<ICamera> mCamera;
     sp<ICameraRecordingProxy> mCameraProxy;
-    sp<Surface> mPreviewSurface;
+    sp<IGraphicBufferProducer> mPreviewSurface;
     sp<IMediaRecorderClient> mListener;
     String16 mClientName;
     uid_t mClientUid;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 2ba6c22..5387e1a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -381,9 +381,16 @@
 
             mSource->start();
 
+            uint32_t flags = 0;
+
+            if (mSource->isRealTime()) {
+                flags |= Renderer::FLAG_REAL_TIME;
+            }
+
             mRenderer = new Renderer(
                     mAudioSink,
-                    new AMessage(kWhatRendererNotify, id()));
+                    new AMessage(kWhatRendererNotify, id()),
+                    flags);
 
             looper()->registerHandler(mRenderer);
 
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index 3c63e80..723af09 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -378,6 +378,7 @@
             int mode = request.readInt32();
             return mPlayer->setVideoScalingMode(mode);
         }
+
         default:
         {
             return INVALID_OPERATION;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 1ba76a5..404b56f 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -31,9 +31,11 @@
 
 NuPlayer::Renderer::Renderer(
         const sp<MediaPlayerBase::AudioSink> &sink,
-        const sp<AMessage> &notify)
+        const sp<AMessage> &notify,
+        uint32_t flags)
     : mAudioSink(sink),
       mNotify(notify),
+      mFlags(flags),
       mNumFramesWritten(0),
       mDrainAudioQueuePending(false),
       mDrainVideoQueuePending(false),
@@ -323,6 +325,11 @@
     if (entry.mBuffer == NULL) {
         // EOS doesn't carry a timestamp.
         delayUs = 0;
+    } else if (mFlags & FLAG_REAL_TIME) {
+        int64_t mediaTimeUs;
+        CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
+
+        delayUs = mediaTimeUs - ALooper::GetNowUs();
     } else {
         int64_t mediaTimeUs;
         CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
@@ -368,12 +375,17 @@
         return;
     }
 
-    int64_t mediaTimeUs;
-    CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
+    int64_t realTimeUs;
+    if (mFlags & FLAG_REAL_TIME) {
+        CHECK(entry->mBuffer->meta()->findInt64("timeUs", &realTimeUs));
+    } else {
+        int64_t mediaTimeUs;
+        CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
 
-    int64_t realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
+        realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs;
+    }
+
     mVideoLateByUs = ALooper::GetNowUs() - realTimeUs;
-
     bool tooLate = (mVideoLateByUs > 40000);
 
     if (tooLate) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
index e4368c7..c9796e2 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.h
@@ -25,8 +25,12 @@
 struct ABuffer;
 
 struct NuPlayer::Renderer : public AHandler {
+    enum Flags {
+        FLAG_REAL_TIME = 1,
+    };
     Renderer(const sp<MediaPlayerBase::AudioSink> &sink,
-             const sp<AMessage> &notify);
+             const sp<AMessage> &notify,
+             uint32_t flags = 0);
 
     void queueBuffer(
             bool audio,
@@ -79,6 +83,7 @@
 
     sp<MediaPlayerBase::AudioSink> mAudioSink;
     sp<AMessage> mNotify;
+    uint32_t mFlags;
     List<QueueEntry> mAudioQueue;
     List<QueueEntry> mVideoQueue;
     uint32_t mNumFramesWritten;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
index 8622abe..1cbf575 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerSource.h
@@ -74,6 +74,10 @@
         return INVALID_OPERATION;
     }
 
+    virtual bool isRealTime() const {
+        return false;
+    }
+
 protected:
     virtual ~Source() {}
 
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
index df03f86..28f0d50 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.cpp
@@ -182,5 +182,9 @@
     return err;
 }
 
+bool NuPlayer::StreamingSource::isRealTime() const {
+    return mSource->flags() & IStreamSource::kFlagIsRealTimeData;
+}
+
 }  // namespace android
 
diff --git a/media/libmediaplayerservice/nuplayer/StreamingSource.h b/media/libmediaplayerservice/nuplayer/StreamingSource.h
index 80b061c..412b6c4 100644
--- a/media/libmediaplayerservice/nuplayer/StreamingSource.h
+++ b/media/libmediaplayerservice/nuplayer/StreamingSource.h
@@ -38,6 +38,8 @@
 
     virtual status_t dequeueAccessUnit(bool audio, sp<ABuffer> *accessUnit);
 
+    virtual bool isRealTime() const;
+
 protected:
     virtual ~StreamingSource();
 
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index f8557d0..5a26b06 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -140,7 +140,7 @@
     uid_t clientUid,
     Size videoSize,
     int32_t frameRate,
-    const sp<Surface>& surface,
+    const sp<IGraphicBufferProducer>& surface,
     bool storeMetaDataInVideoBuffers) {
 
     CameraSource *source = new CameraSource(camera, proxy, cameraId,
@@ -157,7 +157,7 @@
     uid_t clientUid,
     Size videoSize,
     int32_t frameRate,
-    const sp<Surface>& surface,
+    const sp<IGraphicBufferProducer>& surface,
     bool storeMetaDataInVideoBuffers)
     : mCameraFlags(0),
       mNumInputBuffers(0),
@@ -536,7 +536,7 @@
     if (mSurface != NULL) {
         // This CHECK is good, since we just passed the lock/unlock
         // check earlier by calling mCamera->setParameters().
-        CHECK_EQ((status_t)OK, mCamera->setPreviewDisplay(mSurface));
+        CHECK_EQ((status_t)OK, mCamera->setPreviewTexture(mSurface));
     }
 
     // By default, do not store metadata in video buffers
diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp
index 2ed2223..20214e8 100644
--- a/media/libstagefright/CameraSourceTimeLapse.cpp
+++ b/media/libstagefright/CameraSourceTimeLapse.cpp
@@ -40,7 +40,7 @@
         uid_t clientUid,
         Size videoSize,
         int32_t videoFrameRate,
-        const sp<Surface>& surface,
+        const sp<IGraphicBufferProducer>& surface,
         int64_t timeBetweenFrameCaptureUs) {
 
     CameraSourceTimeLapse *source = new
@@ -66,7 +66,7 @@
         uid_t clientUid,
         Size videoSize,
         int32_t videoFrameRate,
-        const sp<Surface>& surface,
+        const sp<IGraphicBufferProducer>& surface,
         int64_t timeBetweenFrameCaptureUs)
       : CameraSource(camera, proxy, cameraId, clientName, clientUid,
                 videoSize, videoFrameRate, surface, true),
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index b2e60be..56fad60 100644
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -2067,17 +2067,30 @@
         sampleRate = br.getBits(24);
         numChannels = br.getBits(4);
     } else {
-        static uint32_t kSamplingRate[] = {
-            96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
-            16000, 12000, 11025, 8000, 7350
-        };
-
-        if (freqIndex == 13 || freqIndex == 14) {
-            return ERROR_MALFORMED;
+        numChannels = br.getBits(4);
+        if (objectType == 5) {
+            // SBR specific config per 14496-3 table 1.13
+            freqIndex = br.getBits(4);
+            if (freqIndex == 15) {
+                if (csd_size < 8) {
+                    return ERROR_MALFORMED;
+                }
+                sampleRate = br.getBits(24);
+            }
         }
 
-        sampleRate = kSamplingRate[freqIndex];
-        numChannels = br.getBits(4);
+        if (sampleRate == 0) {
+            static uint32_t kSamplingRate[] = {
+                96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+                16000, 12000, 11025, 8000, 7350
+            };
+
+            if (freqIndex == 13 || freqIndex == 14) {
+                return ERROR_MALFORMED;
+            }
+
+            sampleRate = kSamplingRate[freqIndex];
+        }
     }
 
     if (numChannels == 0) {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index a167b5a..c12572f 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -452,6 +452,10 @@
         timeUs += mParser->mAbsoluteTimeAnchorUs;
     }
 
+    if (mParser->mTimeOffsetValid) {
+        timeUs += mParser->mTimeOffsetUs;
+    }
+
     return timeUs;
 }
 
@@ -930,6 +934,8 @@
 ATSParser::ATSParser(uint32_t flags)
     : mFlags(flags),
       mAbsoluteTimeAnchorUs(-1ll),
+      mTimeOffsetValid(false),
+      mTimeOffsetUs(0ll),
       mNumTSPacketsParsed(0),
       mNumPCRs(0) {
     mPSISections.add(0 /* PID */, new PSISection);
@@ -960,6 +966,13 @@
         CHECK(mPrograms.empty());
         mAbsoluteTimeAnchorUs = timeUs;
         return;
+    } else if (type == DISCONTINUITY_TIME_OFFSET) {
+        int64_t offset;
+        CHECK(extra->findInt64("offset", &offset));
+
+        mTimeOffsetValid = true;
+        mTimeOffsetUs = offset;
+        return;
     }
 
     for (size_t i = 0; i < mPrograms.size(); ++i) {
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index 46edc45..a10edc9 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -39,6 +39,7 @@
         DISCONTINUITY_AUDIO_FORMAT      = 2,
         DISCONTINUITY_VIDEO_FORMAT      = 4,
         DISCONTINUITY_ABSOLUTE_TIME     = 8,
+        DISCONTINUITY_TIME_OFFSET       = 16,
 
         DISCONTINUITY_SEEK              = DISCONTINUITY_TIME,
 
@@ -106,6 +107,9 @@
 
     int64_t mAbsoluteTimeAnchorUs;
 
+    bool mTimeOffsetValid;
+    int64_t mTimeOffsetUs;
+
     size_t mNumTSPacketsParsed;
 
     void parseProgramAssociationTable(ABitReader *br);
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 211e1d1..3854e52 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -32,7 +32,7 @@
 
 
 GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance,
-        uint32_t bufferWidth, uint32_t bufferHeight) :
+        uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount) :
     mInitCheck(UNKNOWN_ERROR),
     mNodeInstance(nodeInstance),
     mExecuting(false),
@@ -40,20 +40,31 @@
     mEndOfStream(false),
     mEndOfStreamSent(false) {
 
-    ALOGV("GraphicBufferSource w=%u h=%u", bufferWidth, bufferHeight);
+    ALOGV("GraphicBufferSource w=%u h=%u c=%u",
+            bufferWidth, bufferHeight, bufferCount);
 
     if (bufferWidth == 0 || bufferHeight == 0) {
-        ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight);
+        ALOGE("Invalid dimensions %ux%u", bufferWidth, bufferHeight);
         mInitCheck = BAD_VALUE;
         return;
     }
 
+    String8 name("GraphicBufferSource");
+
     mBufferQueue = new BufferQueue(true);
+    mBufferQueue->setConsumerName(name);
     mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
     mBufferQueue->setSynchronousMode(true);
     mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
             GRALLOC_USAGE_HW_TEXTURE);
 
+    mInitCheck = mBufferQueue->setMaxAcquiredBufferCount(bufferCount);
+    if (mInitCheck != NO_ERROR) {
+        ALOGE("Unable to set BQ max acquired buffer count to %u: %d",
+                bufferCount, mInitCheck);
+        return;
+    }
+
     // Note that we can't create an sp<...>(this) in a ctor that will not keep a
     // reference once the ctor ends, as that would cause the refcount of 'this'
     // dropping to 0 at the end of the ctor.  Since all we need is a wp<...>
@@ -64,21 +75,23 @@
     sp<BufferQueue::ConsumerListener> proxy;
     proxy = new BufferQueue::ProxyConsumerListener(listener);
 
-    status_t err = mBufferQueue->consumerConnect(proxy);
-    if (err != NO_ERROR) {
+    mInitCheck = mBufferQueue->consumerConnect(proxy);
+    if (mInitCheck != NO_ERROR) {
         ALOGE("Error connecting to BufferQueue: %s (%d)",
-                strerror(-err), err);
+                strerror(-mInitCheck), mInitCheck);
         return;
     }
 
-    mInitCheck = OK;
+    CHECK(mInitCheck == NO_ERROR);
 }
 
 GraphicBufferSource::~GraphicBufferSource() {
     ALOGV("~GraphicBufferSource");
-    status_t err = mBufferQueue->consumerDisconnect();
-    if (err != NO_ERROR) {
-        ALOGW("consumerDisconnect failed: %d", err);
+    if (mBufferQueue != NULL) {
+        status_t err = mBufferQueue->consumerDisconnect();
+        if (err != NO_ERROR) {
+            ALOGW("consumerDisconnect failed: %d", err);
+        }
     }
 }
 
@@ -98,8 +111,12 @@
     // one codec buffer simultaneously.  (We could instead try to submit
     // all BQ buffers whenever any codec buffer is freed, but if we get the
     // initial conditions right that will never be useful.)
-    while (mNumFramesAvailable && isCodecBufferAvailable_l()) {
-        fillCodecBuffer_l();
+    while (mNumFramesAvailable) {
+        if (!fillCodecBuffer_l()) {
+            ALOGV("stop load with frames available (codecAvail=%d)",
+                    isCodecBufferAvailable_l());
+            break;
+        }
     }
 
     ALOGV("done loading initial frames, avail=%d", mNumFramesAvailable);
@@ -166,7 +183,7 @@
     // see if the GraphicBuffer reference was null, which should only ever
     // happen for EOS.
     if (codecBuffer.mGraphicBuffer == NULL) {
-        CHECK(mEndOfStream);
+        CHECK(mEndOfStream && mEndOfStreamSent);
         // No GraphicBuffer to deal with, no additional input or output is
         // expected, so just return.
         return;
@@ -216,8 +233,9 @@
 
     if (mNumFramesAvailable) {
         // Fill this codec buffer.
-        CHECK(!mEndOfStream);
-        ALOGV("buffer freed, %d frames avail", mNumFramesAvailable);
+        CHECK(!mEndOfStreamSent);
+        ALOGV("buffer freed, %d frames avail (eos=%d)",
+                mNumFramesAvailable, mEndOfStream);
         fillCodecBuffer_l();
     } else if (mEndOfStream) {
         // No frames available, but EOS is pending, so use this buffer to
@@ -228,56 +246,58 @@
     return;
 }
 
-status_t GraphicBufferSource::fillCodecBuffer_l() {
+bool GraphicBufferSource::fillCodecBuffer_l() {
     CHECK(mExecuting && mNumFramesAvailable > 0);
+
     int cbi = findAvailableCodecBuffer_l();
     if (cbi < 0) {
         // No buffers available, bail.
         ALOGV("fillCodecBuffer_l: no codec buffers, avail now %d",
                 mNumFramesAvailable);
-    } else {
-        ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d",
-                mNumFramesAvailable);
-        BufferQueue::BufferItem item;
-        status_t err = mBufferQueue->acquireBuffer(&item);
-        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-            // shouldn't happen
-            ALOGW("fillCodecBuffer_l: frame was not available");
-            return err;
-        } else if (err != OK) {
-            // now what? fake end-of-stream?
-            ALOGW("fillCodecBuffer_l: acquireBuffer returned err=%d", err);
-            return err;
-        }
-
-        mNumFramesAvailable--;
-
-        // Wait for it to become available.
-        err = item.mFence->waitForever(1000,
-                "GraphicBufferSource::fillCodecBuffer_l");
-        if (err != OK) {
-            ALOGW("failed to wait for buffer fence: %d", err);
-            // keep going
-        }
-
-        // If this is the first time we're seeing this buffer, add it to our
-        // slot table.
-        if (item.mGraphicBuffer != NULL) {
-            ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
-            mBufferSlot[item.mBuf] = item.mGraphicBuffer;
-        }
-
-        err = submitBuffer_l(mBufferSlot[item.mBuf], item.mTimestamp, cbi);
-        if (err != OK) {
-            ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
-            mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY,
-                EGL_NO_SYNC_KHR, Fence::NO_FENCE);
-        } else {
-            ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
-        }
+        return false;
     }
 
-    return OK;
+    ALOGV("fillCodecBuffer_l: acquiring buffer, avail=%d",
+            mNumFramesAvailable);
+    BufferQueue::BufferItem item;
+    status_t err = mBufferQueue->acquireBuffer(&item);
+    if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+        // shouldn't happen
+        ALOGW("fillCodecBuffer_l: frame was not available");
+        return false;
+    } else if (err != OK) {
+        // now what? fake end-of-stream?
+        ALOGW("fillCodecBuffer_l: acquireBuffer returned err=%d", err);
+        return false;
+    }
+
+    mNumFramesAvailable--;
+
+    // Wait for it to become available.
+    err = item.mFence->waitForever(1000,
+            "GraphicBufferSource::fillCodecBuffer_l");
+    if (err != OK) {
+        ALOGW("failed to wait for buffer fence: %d", err);
+        // keep going
+    }
+
+    // If this is the first time we're seeing this buffer, add it to our
+    // slot table.
+    if (item.mGraphicBuffer != NULL) {
+        ALOGV("fillCodecBuffer_l: setting mBufferSlot %d", item.mBuf);
+        mBufferSlot[item.mBuf] = item.mGraphicBuffer;
+    }
+
+    err = submitBuffer_l(mBufferSlot[item.mBuf], item.mTimestamp, cbi);
+    if (err != OK) {
+        ALOGV("submitBuffer_l failed, releasing bq buf %d", item.mBuf);
+        mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY,
+                EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+    } else {
+        ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
+    }
+
+    return true;
 }
 
 status_t GraphicBufferSource::signalEndOfInputStream() {
@@ -372,6 +392,7 @@
     } else {
         ALOGV("submitEndOfInputStream_l: buffer submitted, header=%p cbi=%d",
                 header, cbi);
+        mEndOfStreamSent = true;
     }
 }
 
@@ -400,7 +421,8 @@
 void GraphicBufferSource::onFrameAvailable() {
     Mutex::Autolock autoLock(mMutex);
 
-    ALOGV("onFrameAvailable exec=%d avail=%d", mExecuting, mNumFramesAvailable);
+    ALOGV("onFrameAvailable exec=%d avail=%d",
+            mExecuting, mNumFramesAvailable);
 
     if (mEndOfStream) {
         // This should only be possible if a new buffer was queued after
diff --git a/media/libstagefright/omx/GraphicBufferSource.h b/media/libstagefright/omx/GraphicBufferSource.h
index 6a34bc5..7f1f22e 100644
--- a/media/libstagefright/omx/GraphicBufferSource.h
+++ b/media/libstagefright/omx/GraphicBufferSource.h
@@ -47,7 +47,7 @@
 class GraphicBufferSource : public BufferQueue::ConsumerListener {
 public:
     GraphicBufferSource(OMXNodeInstance* nodeInstance,
-            uint32_t bufferWidth, uint32_t bufferHeight);
+            uint32_t bufferWidth, uint32_t bufferHeight, uint32_t bufferCount);
     virtual ~GraphicBufferSource();
 
     // We can't throw an exception if the constructor fails, so we just set
@@ -124,7 +124,9 @@
     // in the onFrameAvailable callback, or if we're in codecBufferEmptied
     // and mNumFramesAvailable is nonzero).  Returns without doing anything if
     // we don't have a codec buffer available.
-    status_t fillCodecBuffer_l();
+    //
+    // Returns true if we successfully filled a codec buffer with a BQ buffer.
+    bool fillCodecBuffer_l();
 
     // Marks the mCodecBuffers entry as in-use, copies the GraphicBuffer
     // reference into the codec buffer, and submits the data to the codec.
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index f3d8d14..46ff22f 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -590,7 +590,8 @@
     }
 
     GraphicBufferSource* bufferSource = new GraphicBufferSource(
-            this, def.format.video.nFrameWidth, def.format.video.nFrameHeight);
+            this, def.format.video.nFrameWidth, def.format.video.nFrameHeight,
+            def.nBufferCountActual);
     if ((err = bufferSource->initCheck()) != OK) {
         delete bufferSource;
         return err;
diff --git a/media/libstagefright/wifi-display/ANetworkSession.cpp b/media/libstagefright/wifi-display/ANetworkSession.cpp
index cb6011c..23bb04e 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.cpp
+++ b/media/libstagefright/wifi-display/ANetworkSession.cpp
@@ -27,6 +27,7 @@
 #include <net/if.h>
 #include <netdb.h>
 #include <netinet/in.h>
+#include <sys/ioctl.h>
 #include <sys/socket.h>
 
 #include <media/stagefright/foundation/ABuffer.h>
@@ -103,6 +104,8 @@
 
     AString mInBuffer;
 
+    int64_t mLastStallReportUs;
+
     void notifyError(bool send, status_t err, const char *detail);
     void notify(NotificationReason reason);
 
@@ -136,7 +139,8 @@
       mSocket(s),
       mNotify(notify),
       mSawReceiveFailure(false),
-      mSawSendFailure(false) {
+      mSawSendFailure(false),
+      mLastStallReportUs(-1ll) {
     if (mState == CONNECTED) {
         struct sockaddr_in localAddr;
         socklen_t localAddrLen = sizeof(localAddr);
@@ -507,6 +511,29 @@
         mSawSendFailure = true;
     }
 
+#if 1
+    int numBytesQueued;
+    int res = ioctl(mSocket, SIOCOUTQ, &numBytesQueued);
+    if (res == 0 && numBytesQueued > 50 * 1024) {
+        if (numBytesQueued > 409600) {
+            ALOGW("!!! numBytesQueued = %d", numBytesQueued);
+        }
+
+        int64_t nowUs = ALooper::GetNowUs();
+
+        if (mLastStallReportUs < 0ll
+                || nowUs > mLastStallReportUs + 500000ll) {
+            sp<AMessage> msg = mNotify->dup();
+            msg->setInt32("sessionID", mSessionID);
+            msg->setInt32("reason", kWhatNetworkStall);
+            msg->setSize("numBytesQueued", numBytesQueued);
+            msg->post();
+
+            mLastStallReportUs = nowUs;
+        }
+    }
+#endif
+
     return err;
 }
 
diff --git a/media/libstagefright/wifi-display/ANetworkSession.h b/media/libstagefright/wifi-display/ANetworkSession.h
index c1acdcc..0d7cbd6 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.h
+++ b/media/libstagefright/wifi-display/ANetworkSession.h
@@ -83,6 +83,7 @@
         kWhatData,
         kWhatDatagram,
         kWhatBinaryData,
+        kWhatNetworkStall,
     };
 
 protected:
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index 19f560c..f81929c 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -15,6 +15,7 @@
         sink/TunnelRenderer.cpp         \
         sink/WifiDisplaySink.cpp        \
         SNTPClient.cpp                  \
+        TimeSyncer.cpp                  \
         source/Converter.cpp            \
         source/MediaPuller.cpp          \
         source/PlaybackSession.cpp      \
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
index 105c642..e1e957a 100644
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ b/media/libstagefright/wifi-display/MediaSender.cpp
@@ -325,6 +325,15 @@
             break;
         }
 
+        case kWhatNetworkStall:
+        {
+            size_t numBytesQueued;
+            CHECK(msg->findSize("numBytesQueued", &numBytesQueued));
+
+            notifyNetworkStall(numBytesQueued);
+            break;
+        }
+
         default:
             TRESPASS();
     }
@@ -344,6 +353,13 @@
     notify->post();
 }
 
+void MediaSender::notifyNetworkStall(size_t numBytesQueued) {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatNetworkStall);
+    notify->setSize("numBytesQueued", numBytesQueued);
+    notify->post();
+}
+
 status_t MediaSender::packetizeAccessUnit(
         size_t trackIndex,
         sp<ABuffer> accessUnit,
diff --git a/media/libstagefright/wifi-display/MediaSender.h b/media/libstagefright/wifi-display/MediaSender.h
index 9a50f9a..447abf7 100644
--- a/media/libstagefright/wifi-display/MediaSender.h
+++ b/media/libstagefright/wifi-display/MediaSender.h
@@ -42,6 +42,7 @@
     enum {
         kWhatInitDone,
         kWhatError,
+        kWhatNetworkStall,
     };
 
     MediaSender(
@@ -113,6 +114,7 @@
 
     void notifyInitDone(status_t err);
     void notifyError(status_t err);
+    void notifyNetworkStall(size_t numBytesQueued);
 
     status_t packetizeAccessUnit(
             size_t trackIndex,
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 85c5933..8cd712d 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -530,6 +530,18 @@
             }
             break;
         }
+
+        case ANetworkSession::kWhatNetworkStall:
+        {
+            size_t numBytesQueued;
+            CHECK(msg->findSize("numBytesQueued", &numBytesQueued));
+
+            notifyNetworkStall(numBytesQueued);
+            break;
+        }
+
+        default:
+            TRESPASS();
     }
 }
 
@@ -577,6 +589,8 @@
 
             case 202:  // SDES
             case 203:
+                break;
+
             case 204:  // APP
                 break;
 
@@ -697,5 +711,12 @@
     notify->post();
 }
 
+void RTPSender::notifyNetworkStall(size_t numBytesQueued) {
+    sp<AMessage> notify = mNotify->dup();
+    notify->setInt32("what", kWhatNetworkStall);
+    notify->setSize("numBytesQueued", numBytesQueued);
+    notify->post();
+}
+
 }  // namespace android
 
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
index 2b683a4..83c6223 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.h
@@ -36,6 +36,7 @@
     enum {
         kWhatInitDone,
         kWhatError,
+        kWhatNetworkStall,
     };
     RTPSender(
             const sp<ANetworkSession> &netSession,
@@ -103,6 +104,7 @@
 
     void notifyInitDone(status_t err);
     void notifyError(status_t err);
+    void notifyNetworkStall(size_t numBytesQueued);
 
     DISALLOW_EVIL_CONSTRUCTORS(RTPSender);
 };
diff --git a/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp b/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
index d9d8a76..6b185db 100644
--- a/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
+++ b/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
@@ -27,6 +27,7 @@
 #include <gui/SurfaceComposerClient.h>
 #include <media/IMediaPlayerService.h>
 #include <media/IStreamSource.h>
+#include <media/mediaplayer.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -60,6 +61,8 @@
 
     void doSomeWork();
 
+    void setTimeOffset(int64_t offset);
+
 protected:
     virtual ~StreamSource();
 
@@ -75,6 +78,9 @@
 
     size_t mNumDeqeued;
 
+    int64_t mTimeOffsetUs;
+    bool mTimeOffsetChanged;
+
     DISALLOW_EVIL_CONSTRUCTORS(StreamSource);
 };
 
@@ -82,7 +88,9 @@
 
 TunnelRenderer::StreamSource::StreamSource(TunnelRenderer *owner)
     : mOwner(owner),
-      mNumDeqeued(0) {
+      mNumDeqeued(0),
+      mTimeOffsetUs(0ll),
+      mTimeOffsetChanged(false) {
 }
 
 TunnelRenderer::StreamSource::~StreamSource() {
@@ -110,7 +118,7 @@
 }
 
 uint32_t TunnelRenderer::StreamSource::flags() const {
-    return kFlagAlignedVideoData;
+    return kFlagAlignedVideoData | kFlagIsRealTimeData;
 }
 
 void TunnelRenderer::StreamSource::doSomeWork() {
@@ -124,21 +132,21 @@
 
         ++mNumDeqeued;
 
-        if (mNumDeqeued == 1) {
-            ALOGI("fixing real time now.");
-
+        if (mTimeOffsetChanged) {
             sp<AMessage> extra = new AMessage;
 
             extra->setInt32(
                     IStreamListener::kKeyDiscontinuityMask,
-                    ATSParser::DISCONTINUITY_ABSOLUTE_TIME);
+                    ATSParser::DISCONTINUITY_TIME_OFFSET);
 
-            extra->setInt64("timeUs", ALooper::GetNowUs());
+            extra->setInt64("offset", mTimeOffsetUs);
 
             mListener->issueCommand(
                     IStreamListener::DISCONTINUITY,
                     false /* synchronous */,
                     extra);
+
+            mTimeOffsetChanged = false;
         }
 
         ALOGV("dequeue TS packet of size %d", srcBuffer->size());
@@ -155,18 +163,32 @@
     }
 }
 
+void TunnelRenderer::StreamSource::setTimeOffset(int64_t offset) {
+    Mutex::Autolock autoLock(mLock);
+
+    if (offset != mTimeOffsetUs) {
+        mTimeOffsetUs = offset;
+        mTimeOffsetChanged = true;
+    }
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 
 TunnelRenderer::TunnelRenderer(
         const sp<IGraphicBufferProducer> &bufferProducer)
     : mSurfaceTex(bufferProducer),
       mStartup(true) {
+    mStreamSource = new StreamSource(this);
 }
 
 TunnelRenderer::~TunnelRenderer() {
     destroyPlayer();
 }
 
+void TunnelRenderer::setTimeOffset(int64_t offset) {
+    mStreamSource->setTimeOffset(offset);
+}
+
 void TunnelRenderer::onMessageReceived(const sp<AMessage> &msg) {
     switch (msg->what()) {
         default:
@@ -209,8 +231,6 @@
     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
     CHECK(service.get() != NULL);
 
-    mStreamSource = new StreamSource(this);
-
     mPlayerClient = new PlayerClient;
 
     mPlayer = service->create(mPlayerClient, 0);
@@ -226,6 +246,8 @@
 void TunnelRenderer::destroyPlayer() {
     mStreamSource.clear();
 
+    mPlayer->setVideoSurfaceTexture(NULL);
+
     mPlayer->stop();
     mPlayer.clear();
 
diff --git a/media/libstagefright/wifi-display/sink/TunnelRenderer.h b/media/libstagefright/wifi-display/sink/TunnelRenderer.h
index 8e96665..479e73c 100644
--- a/media/libstagefright/wifi-display/sink/TunnelRenderer.h
+++ b/media/libstagefright/wifi-display/sink/TunnelRenderer.h
@@ -39,6 +39,12 @@
     void queueBuffer(const sp<ABuffer> &buffer);
     sp<ABuffer> dequeueBuffer();
 
+    void setTimeOffset(int64_t offset);
+
+    int64_t getAvgLatenessUs() {
+        return 0ll;
+    }
+
 protected:
     virtual void onMessageReceived(const sp<AMessage> &msg);
     virtual ~TunnelRenderer();
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index 2861aa9..bb8c387 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -55,6 +55,7 @@
       ,mInSilentMode(false)
 #endif
       ,mPrevVideoBitrate(-1)
+      ,mNumFramesToDrop(0)
     {
     AString mime;
     CHECK(mInputFormat->findString("mime", &mime));
@@ -327,6 +328,13 @@
                 sp<ABuffer> accessUnit;
                 CHECK(msg->findBuffer("accessUnit", &accessUnit));
 
+                if (mIsVideo && mNumFramesToDrop) {
+                    --mNumFramesToDrop;
+                    ALOGI("dropping frame.");
+                    ReleaseMediaBufferReference(accessUnit);
+                    break;
+                }
+
 #if 0
                 void *mbuf;
                 if (accessUnit->meta()->findPointer("mediaBuffer", &mbuf)
@@ -422,6 +430,12 @@
             break;
         }
 
+        case kWhatDropAFrame:
+        {
+            ++mNumFramesToDrop;
+            break;
+        }
+
         default:
             TRESPASS();
     }
@@ -690,4 +704,8 @@
     (new AMessage(kWhatRequestIDRFrame, id()))->post();
 }
 
+void Converter::dropAFrame() {
+    (new AMessage(kWhatDropAFrame, id()))->post();
+}
+
 }  // namespace android
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index 57802bd..a418f69 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -51,6 +51,8 @@
 
     void requestIDRFrame();
 
+    void dropAFrame();
+
     enum {
         kWhatAccessUnit,
         kWhatEOS,
@@ -63,6 +65,7 @@
         kWhatShutdown,
         kWhatMediaPullerNotify,
         kWhatEncoderActivity,
+        kWhatDropAFrame,
     };
 
     void shutdownAsync();
@@ -102,6 +105,8 @@
 
     int32_t mPrevVideoBitrate;
 
+    int32_t mNumFramesToDrop;
+
     status_t initEncoder();
     void releaseEncoder();
 
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index ea195b3..94cb2a4 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -515,6 +515,16 @@
                 }
             } else if (what == MediaSender::kWhatError) {
                 notifySessionDead();
+            } else if (what == MediaSender::kWhatNetworkStall) {
+                size_t numBytesQueued;
+                CHECK(msg->findSize("numBytesQueued", &numBytesQueued));
+
+                if (mVideoTrackIndex >= 0) {
+                    const sp<Track> &videoTrack =
+                        mTracks.valueFor(mVideoTrackIndex);
+
+                    videoTrack->converter()->dropAFrame();
+                }
             } else {
                 TRESPASS();
             }
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index b8524f6..c8798c6 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -23,6 +23,7 @@
 #include "Parameters.h"
 #include "ParsedMessage.h"
 #include "rtp/RTPSender.h"
+#include "TimeSyncer.h"
 
 #include <binder/IServiceManager.h>
 #include <gui/IGraphicBufferProducer.h>
@@ -157,6 +158,12 @@
             }
 
             if (err == OK) {
+                sp<AMessage> notify = new AMessage(kWhatTimeSyncerNotify, id());
+                mTimeSyncer = new TimeSyncer(mNetSession, notify);
+                looper()->registerHandler(mTimeSyncer);
+
+                mTimeSyncer->startServer(8123);
+
                 mState = AWAITING_CLIENT_CONNECTION;
             }
 
@@ -265,6 +272,11 @@
                     break;
                 }
 
+                case ANetworkSession::kWhatNetworkStall:
+                {
+                    break;
+                }
+
                 default:
                     TRESPASS();
             }
@@ -520,6 +532,11 @@
             break;
         }
 
+        case kWhatTimeSyncerNotify:
+        {
+            break;
+        }
+
         default:
             TRESPASS();
     }
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 724462c..9e72682 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -30,6 +30,7 @@
 struct IHDCP;
 struct IRemoteDisplayClient;
 struct ParsedMessage;
+struct TimeSyncer;
 
 // Represents the RTSP server acting as a wifi display source.
 // Manages incoming connections, sets up Playback sessions as necessary.
@@ -81,6 +82,7 @@
         kWhatHDCPNotify,
         kWhatFinishStop2,
         kWhatTeardownTriggerTimedOut,
+        kWhatTimeSyncerNotify,
     };
 
     struct ResponseID {
@@ -114,6 +116,7 @@
     VideoFormats mSupportedSourceVideoFormats;
     sp<ANetworkSession> mNetSession;
     sp<IRemoteDisplayClient> mClient;
+    sp<TimeSyncer> mTimeSyncer;
     struct in_addr mInterfaceAddr;
     int32_t mSessionID;
 
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 3f4216a..0b18484 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -321,7 +321,10 @@
     sp<ALooper> looper = new ALooper;
 
     sp<WifiDisplaySink> sink = new WifiDisplaySink(
-            session, surface->getIGraphicBufferProducer());
+            0 /* flags */,
+            session,
+            surface->getIGraphicBufferProducer());
+
     looper->registerHandler(sink);
 
     if (connectToPort >= 0) {
diff --git a/services/audioflinger/FastMixer.h b/services/audioflinger/FastMixer.h
index 462739b..2ab1d04 100644
--- a/services/audioflinger/FastMixer.h
+++ b/services/audioflinger/FastMixer.h
@@ -107,7 +107,7 @@
 #ifdef FAST_MIXER_STATISTICS
     // Recently collected samples of per-cycle monotonic time, thread CPU time, and CPU frequency.
     // kSamplingN is the size of the sampling frame, and must be a power of 2 <= 0x8000.
-    static const uint32_t kSamplingN = 0x1000;
+    static const uint32_t kSamplingN = 0x8000;
     // The bounds define the interval of valid samples, and are represented as follows:
     //      newest open (excluded) endpoint   = lower 16 bits of bounds, modulo N
     //      oldest closed (included) endpoint = upper 16 bits of bounds, modulo N
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..056271d 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,42 +75,17 @@
     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();
     ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
     status_t res;
 
-    // Verify ops permissions
-    res = startCameraOps();
+    res = Camera2ClientBase::initialize(module);
     if (res != OK) {
         return res;
     }
 
-    if (mDevice == NULL) {
-        ALOGE("%s: Camera %d: No device connected",
-                __FUNCTION__, mCameraId);
-        return NO_INIT;
-    }
-
-    res = mDevice->initialize(module);
-    if (res != OK) {
-        ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
-                __FUNCTION__, mCameraId, strerror(-res), res);
-        return NO_INIT;
-    }
-
-    res = mDevice->setNotifyCallback(this);
-
     SharedParameters::Lock l(mParameters);
 
     res = l.mParameters.initialize(&(mDevice->info()));
@@ -125,7 +99,7 @@
 
     mStreamingProcessor = new StreamingProcessor(this);
 
-    mFrameProcessor = new FrameProcessor(this);
+    mFrameProcessor = new FrameProcessor(mDevice, this);
     threadName = String8::format("C2-%d-FrameProc",
             mCameraId);
     mFrameProcessor->run(threadName.string());
@@ -173,7 +147,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 +350,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 +408,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 +419,8 @@
 
     mClientPid = getCallingPid();
 
-    mCameraClient = client;
-    mSharedCameraClient = client;
+    mRemoteCallback = client;
+    mSharedCameraCallbacks = client;
 
     return OK;
 }
@@ -464,7 +428,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 +449,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 +461,8 @@
             return INVALID_OPERATION;
         }
         mClientPid = 0;
-        mCameraClient.clear();
-        mSharedCameraClient.clear();
+        mRemoteCallback.clear();
+        mSharedCameraCallbacks.clear();
         return OK;
     }
 
@@ -511,7 +475,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 +493,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 +562,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 +601,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 +717,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 +765,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 +775,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 +800,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 +891,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 +923,7 @@
 
 bool Camera2Client::recordingEnabled() {
     ATRACE_CALL();
-    Mutex::Autolock icl(mICameraLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if ( checkPid(__FUNCTION__) != OK) return false;
 
@@ -976,7 +940,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 +948,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 +986,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 +1019,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 +1051,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 +1110,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 +1127,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 +1137,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 +1312,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 +1407,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 +1428,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 +1466,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 +1567,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..0623b89
--- /dev/null
+++ b/services/camera/libcameraservice/Camera2ClientBase.cpp
@@ -0,0 +1,329 @@
+/*
+ * 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;
+
+    // Verify ops permissions
+    res = TClientBase::startCameraOps();
+    if (res != OK) {
+        return res;
+    }
+
+    if (mDevice == NULL) {
+        ALOGE("%s: Camera %d: No device connected",
+                __FUNCTION__, TClientBase::mCameraId);
+        return NO_INIT;
+    }
+
+    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;
+
+    TClientBase::finishCameraOps();
+
+    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();
+
+    CameraService::BasicClient::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/Camera2Device.cpp b/services/camera/libcameraservice/Camera2Device.cpp
index 81e58ca..37ba5ae 100644
--- a/services/camera/libcameraservice/Camera2Device.cpp
+++ b/services/camera/libcameraservice/Camera2Device.cpp
@@ -47,6 +47,10 @@
     disconnect();
 }
 
+int Camera2Device::getId() const {
+    return mId;
+}
+
 status_t Camera2Device::initialize(camera_module_t *module)
 {
     ATRACE_CALL();
diff --git a/services/camera/libcameraservice/Camera2Device.h b/services/camera/libcameraservice/Camera2Device.h
index 1adb7a9..3034a1d 100644
--- a/services/camera/libcameraservice/Camera2Device.h
+++ b/services/camera/libcameraservice/Camera2Device.h
@@ -38,6 +38,7 @@
     /**
      * CameraDevice interface
      */
+    virtual int      getId() const;
     virtual status_t initialize(camera_module_t *module);
     virtual status_t disconnect();
     virtual status_t dump(int fd, const Vector<String16>& args);
diff --git a/services/camera/libcameraservice/Camera3Device.cpp b/services/camera/libcameraservice/Camera3Device.cpp
index 2a1be09..04a6e6a 100644
--- a/services/camera/libcameraservice/Camera3Device.cpp
+++ b/services/camera/libcameraservice/Camera3Device.cpp
@@ -50,6 +50,10 @@
     disconnect();
 }
 
+int Camera3Device::getId() const {
+    return mId;
+}
+
 status_t Camera3Device::initialize(camera_module_t *module)
 {
     ATRACE_CALL();
diff --git a/services/camera/libcameraservice/Camera3Device.h b/services/camera/libcameraservice/Camera3Device.h
index 2bc7cf0..df7352c 100644
--- a/services/camera/libcameraservice/Camera3Device.h
+++ b/services/camera/libcameraservice/Camera3Device.h
@@ -57,6 +57,7 @@
     /**
      * CameraDevice interface
      */
+    virtual int      getId() const;
     virtual status_t initialize(camera_module_t *module);
     virtual status_t disconnect();
     virtual status_t dump(int fd, const Vector<String16> &args);
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/CameraDeviceBase.h b/services/camera/libcameraservice/CameraDeviceBase.h
index 8252af7..8c457d9 100644
--- a/services/camera/libcameraservice/CameraDeviceBase.h
+++ b/services/camera/libcameraservice/CameraDeviceBase.h
@@ -36,6 +36,11 @@
   public:
     virtual ~CameraDeviceBase();
 
+    /**
+     * The device's camera ID
+     */
+    virtual int      getId() const = 0;
+
     virtual status_t initialize(camera_module_t *module) = 0;
     virtual status_t disconnect() = 0;
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 8c4f619..5a6a3c8 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -176,18 +176,12 @@
     return false;
 }
 
-sp<ICamera> CameraService::connect(
-        const sp<ICameraClient>& cameraClient,
-        int cameraId,
-        const String16& clientPackageName,
-        int clientUid) {
+bool CameraService::validateConnect(int cameraId,
+                                    /*inout*/
+                                    int& clientUid) const {
 
-    String8 clientName8(clientPackageName);
     int callingPid = getCallingPid();
 
-    LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,
-            clientName8.string(), cameraId);
-
     if (clientUid == USE_CALLING_UID) {
         clientUid = getCallingUid();
     } else {
@@ -195,20 +189,19 @@
         if (callingPid != getpid()) {
             ALOGE("CameraService::connect X (pid %d) rejected (don't trust clientUid)",
                     callingPid);
-            return NULL;
+            return false;
         }
     }
 
     if (!mModule) {
         ALOGE("Camera HAL module not loaded");
-        return NULL;
+        return false;
     }
 
-    sp<Client> client;
     if (cameraId < 0 || cameraId >= mNumberOfCameras) {
         ALOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
             callingPid, cameraId);
-        return NULL;
+        return false;
     }
 
     char value[PROPERTY_VALUE_MAX];
@@ -216,22 +209,32 @@
     if (strcmp(value, "1") == 0) {
         // Camera is disabled by DevicePolicyManager.
         ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
-        return NULL;
+        return false;
     }
 
-    Mutex::Autolock lock(mServiceLock);
+    return true;
+}
+
+bool CameraService::canConnectUnsafe(int cameraId,
+                                     const String16& clientPackageName,
+                                     const sp<IBinder>& remoteCallback,
+                                     sp<Client> &client) {
+    String8 clientName8(clientPackageName);
+    int callingPid = getCallingPid();
+
     if (mClient[cameraId] != 0) {
         client = mClient[cameraId].promote();
         if (client != 0) {
-            if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
+            if (remoteCallback == client->getRemoteCallback()->asBinder()) {
                 LOG1("CameraService::connect X (pid %d) (the same client)",
                      callingPid);
-                return client;
+                return true;
             } else {
-                // TODOSC: need to support 1 regular client, multiple shared clients here
-                ALOGW("CameraService::connect X (pid %d) rejected (existing client).",
-                      callingPid);
-                return NULL;
+                // TODOSC: need to support 1 regular client,
+                // multiple shared clients here
+                ALOGW("CameraService::connect X (pid %d) rejected"
+                      " (existing client).", callingPid);
+                return false;
             }
         }
         mClient[cameraId].clear();
@@ -247,57 +250,103 @@
     would be fine
     */
     if (mBusy[cameraId]) {
-
         ALOGW("CameraService::connect X (pid %d, \"%s\") rejected"
                 " (camera %d is still busy).", callingPid,
                 clientName8.string(), cameraId);
+        return false;
+    }
+
+    return true;
+}
+
+sp<ICamera> CameraService::connect(
+        const sp<ICameraClient>& cameraClient,
+        int cameraId,
+        const String16& clientPackageName,
+        int clientUid) {
+
+    String8 clientName8(clientPackageName);
+    int callingPid = getCallingPid();
+
+    LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,
+            clientName8.string(), cameraId);
+
+    if (!validateConnect(cameraId, /*inout*/clientUid)) {
         return NULL;
     }
 
-    int facing = -1;
-    int deviceVersion = getDeviceVersion(cameraId, &facing);
+    sp<Client> client;
 
-    if (isValidCameraId(cameraId)) {
-        updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE, cameraId);
+    {
+        Mutex::Autolock lock(mServiceLock);
+        if (!canConnectUnsafe(cameraId, clientPackageName,
+                              cameraClient->asBinder(),
+                              /*out*/client)) {
+            return NULL;
+        } else if (client.get() != NULL) {
+            return client;
+        }
+
+        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)) {
+            updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
+                         cameraId);
+        }
+
+        switch(deviceVersion) {
+          case CAMERA_DEVICE_API_VERSION_1_0:
+            client = new CameraClient(this, cameraClient,
+                    clientPackageName, cameraId,
+                    facing, callingPid, clientUid, getpid());
+            break;
+          case CAMERA_DEVICE_API_VERSION_2_0:
+          case CAMERA_DEVICE_API_VERSION_2_1:
+          case CAMERA_DEVICE_API_VERSION_3_0:
+            client = new Camera2Client(this, cameraClient,
+                    clientPackageName, cameraId,
+                    facing, callingPid, clientUid, getpid(),
+                    deviceVersion);
+            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->asBinder())) {
+            // this is probably not recoverable.. maybe the client can try again
+            updateStatus(ICameraServiceListener::STATUS_AVAILABLE, cameraId);
+
+            return NULL;
+        }
+
+        mClient[cameraId] = client;
+        LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
+             getpid());
     }
-
-    switch(deviceVersion) {
-      case CAMERA_DEVICE_API_VERSION_1_0:
-        client = new CameraClient(this, cameraClient,
-                clientPackageName, cameraId,
-                facing, callingPid, clientUid, getpid());
-        break;
-      case CAMERA_DEVICE_API_VERSION_2_0:
-      case CAMERA_DEVICE_API_VERSION_2_1:
-      case CAMERA_DEVICE_API_VERSION_3_0:
-        client = new Camera2Client(this, cameraClient,
-                clientPackageName, cameraId,
-                facing, callingPid, clientUid, getpid(),
-                deviceVersion);
-        break;
-      case -1:
-        ALOGE("Invalid camera id %d", cameraId);
-        return NULL;
-      default:
-        ALOGE("Unknown camera device HAL version: %d", deviceVersion);
-        return NULL;
-    }
-
-    if (client->initialize(mModule) != OK) {
-        // this is probably not recoverable.. but maybe the client can try again
-        updateStatus(ICameraServiceListener::STATUS_AVAILABLE, cameraId);
-
-        return NULL;
-    }
-
-    cameraClient->asBinder()->linkToDeath(this);
-
-    mClient[cameraId] = client;
-    LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());
+    // 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;
 }
 
+bool CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
+                                        const sp<IBinder>& clientBinder) {
+    if (client->initialize(mModule) != OK) {
+        return false;
+    }
+
+    clientBinder->linkToDeath(this);
+
+    return true;
+}
+
 sp<IProCameraUser> CameraService::connect(
                                         const sp<IProCameraCallbacks>& cameraCb,
                                         int cameraId,
@@ -307,70 +356,59 @@
     String8 clientName8(clientPackageName);
     int callingPid = getCallingPid();
 
-    // TODO: use clientPackageName and clientUid with appOpsMangr
+    LOG1("CameraService::connectPro E (pid %d \"%s\", id %d)", callingPid,
+            clientName8.string(), cameraId);
 
-    LOG1("CameraService::connectPro E (pid %d, id %d)", callingPid, cameraId);
-
-    if (!mModule) {
-        ALOGE("Camera HAL module not loaded");
+    if (!validateConnect(cameraId, /*inout*/clientUid)) {
         return NULL;
     }
 
     sp<ProClient> client;
-    if (cameraId < 0 || cameraId >= mNumberOfCameras) {
-        ALOGE("CameraService::connectPro X (pid %d) rejected (invalid cameraId %d).",
-            callingPid, cameraId);
-        return NULL;
+    {
+        Mutex::Autolock lock(mServiceLock);
+        {
+            sp<Client> client;
+            if (!canConnectUnsafe(cameraId, clientPackageName,
+                                  cameraCb->asBinder(),
+                                  /*out*/client)) {
+                return NULL;
+            }
+        }
+
+        int facing = -1;
+        int deviceVersion = getDeviceVersion(cameraId, &facing);
+
+        switch(deviceVersion) {
+          case CAMERA_DEVICE_API_VERSION_1_0:
+            ALOGE("Camera id %d uses HALv1, doesn't support ProCamera",
+                  cameraId);
+            return NULL;
+            break;
+          case CAMERA_DEVICE_API_VERSION_2_0:
+          case CAMERA_DEVICE_API_VERSION_2_1:
+            client = new ProCamera2Client(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->asBinder())) {
+            return NULL;
+        }
+
+        mProClientList[cameraId].push(client);
+
+        LOG1("CameraService::connectPro X (id %d, this pid is %d)", cameraId,
+                getpid());
     }
+    // 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)
 
-    char value[PROPERTY_VALUE_MAX];
-    property_get("sys.secpolicy.camera.disabled", value, "0");
-    if (strcmp(value, "1") == 0) {
-        // Camera is disabled by DevicePolicyManager.
-        ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
-        return NULL;
-    }
-
-    // TODO: allow concurrent connections with a ProCamera
-    if (mBusy[cameraId]) {
-
-        ALOGW("CameraService::connectPro X (pid %d, \"%s\") rejected"
-                " (camera %d is still busy).", callingPid,
-                clientName8.string(), cameraId);
-        return NULL;
-    }
-
-    int facing = -1;
-    int deviceVersion = getDeviceVersion(cameraId, &facing);
-
-    switch(deviceVersion) {
-      case CAMERA_DEVICE_API_VERSION_1_0:
-        ALOGE("Camera id %d uses HALv1, doesn't support ProCamera", cameraId);
-        return NULL;
-        break;
-      case CAMERA_DEVICE_API_VERSION_2_0:
-      case CAMERA_DEVICE_API_VERSION_2_1:
-        client = new ProCamera2Client(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 (client->initialize(mModule) != OK) {
-        return NULL;
-    }
-
-    mProClientList[cameraId].push(client);
-
-    cameraCb->asBinder()->linkToDeath(this);
-
-    LOG1("CameraService::connectPro X (id %d, this pid is %d)", cameraId,
-            getpid());
     return client;
 }
 
@@ -496,7 +534,7 @@
             continue;
         }
 
-        if (cameraClient == client->getCameraClient()->asBinder()) {
+        if (cameraClient == client->getRemoteCallback()->asBinder()) {
             // Found our camera
             outIndex = i;
             return client;
@@ -639,7 +677,7 @@
     int callingPid = getCallingPid();
     LOG1("Client::Client E (pid %d, id %d)", callingPid, cameraId);
 
-    mCameraClient = cameraClient;
+    mRemoteCallback = cameraClient;
 
     cameraService->setCameraBusy(cameraId);
     cameraService->loadSound();
@@ -652,7 +690,6 @@
     mDestructionStarted = true;
 
     mCameraService->releaseSound();
-    finishCameraOps();
     // unconditionally disconnect. function is idempotent
     Client::disconnect();
 }
@@ -666,7 +703,7 @@
         mClientPackageName(clientPackageName)
 {
     mCameraService = cameraService;
-    mRemoteCallback = remoteCallback;
+    mRemoteBinder = remoteCallback;
     mCameraId = cameraId;
     mCameraFacing = cameraFacing;
     mClientPid = clientPid;
@@ -681,7 +718,7 @@
 }
 
 void CameraService::BasicClient::disconnect() {
-    mCameraService->removeClientByRemote(mRemoteCallback);
+    mCameraService->removeClientByRemote(mRemoteBinder);
 }
 
 status_t CameraService::BasicClient::startCameraOps() {
@@ -689,6 +726,11 @@
 
     mOpsCallback = new OpsCallback(this);
 
+    {
+        ALOGV("%s: Start camera ops, package name = %s, client UID = %d",
+              __FUNCTION__, String8(mClientPackageName).string(), mClientUid);
+    }
+
     mAppOpsManager.startWatchingMode(AppOpsManager::OP_CAMERA,
             mClientPackageName, mOpsCallback);
     res = mAppOpsManager.startOp(AppOpsManager::OP_CAMERA,
@@ -767,7 +809,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
@@ -810,79 +852,10 @@
 }
 
 CameraService::ProClient::~ProClient() {
-    mDestructionStarted = true;
-
-    ProClient::disconnect();
-}
-
-status_t CameraService::ProClient::connect(const sp<IProCameraCallbacks>& callbacks) {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-
-    return INVALID_OPERATION;
-}
-
-void CameraService::ProClient::disconnect() {
-    BasicClient::disconnect();
-}
-
-status_t CameraService::ProClient::initialize(camera_module_t* module)
-{
-    ALOGW("%s: not implemented yet", __FUNCTION__);
-    return OK;
-}
-
-status_t CameraService::ProClient::exclusiveTryLock() {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
-status_t CameraService::ProClient::exclusiveLock() {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
-status_t CameraService::ProClient::exclusiveUnlock() {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-    return INVALID_OPERATION;
-}
-
-bool CameraService::ProClient::hasExclusiveLock() {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-    return false;
-}
-
-void CameraService::ProClient::onExclusiveLockStolen() {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-}
-
-status_t CameraService::ProClient::submitRequest(camera_metadata_t* request, bool streaming) {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-
-    free_camera_metadata(request);
-
-    return INVALID_OPERATION;
-}
-
-status_t CameraService::ProClient::cancelRequest(int requestId) {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-
-    return INVALID_OPERATION;
-}
-
-status_t CameraService::ProClient::requestStream(int streamId) {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-
-    return INVALID_OPERATION;
-}
-
-status_t CameraService::ProClient::cancelStream(int streamId) {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-
-    return INVALID_OPERATION;
 }
 
 void CameraService::ProClient::notifyError() {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
+    mRemoteCallback->notifyCallback(CAMERA_MSG_ERROR, CAMERA_ERROR_RELEASED, 0);
 }
 
 // ----------------------------------------------------------------------------
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8acc63f..c5e495f 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -108,8 +108,9 @@
 
         virtual void          disconnect() = 0;
 
+        // Return the remote callback binder object (e.g. IProCameraCallbacks)
         wp<IBinder>     getRemote() {
-            return mRemoteCallback;
+            return mRemoteBinder;
         }
 
     protected:
@@ -140,7 +141,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 +174,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 +211,8 @@
         ~Client();
 
         // return our camera client
-        const sp<ICameraClient>&    getCameraClient() {
-            return mCameraClient;
+        const sp<ICameraClient>&    getRemoteCallback() {
+            return mRemoteCallback;
         }
 
     protected:
@@ -222,12 +225,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,
@@ -243,34 +248,24 @@
             return mRemoteCallback;
         }
 
-        // BasicClient implementation
-        virtual status_t initialize(camera_module_t *module);
-
         /***
             IProCamera implementation
          ***/
+        virtual status_t      connect(const sp<IProCameraCallbacks>& callbacks)
+                                                                            = 0;
+        virtual status_t      exclusiveTryLock() = 0;
+        virtual status_t      exclusiveLock() = 0;
+        virtual status_t      exclusiveUnlock() = 0;
 
-
-        virtual status_t      connect(
-                                     const sp<IProCameraCallbacks>& callbacks);
-        virtual void          disconnect();
-
-        virtual status_t      exclusiveTryLock();
-        virtual status_t      exclusiveLock();
-        virtual status_t      exclusiveUnlock();
-
-        virtual bool          hasExclusiveLock();
+        virtual bool          hasExclusiveLock() = 0;
 
         // Note that the callee gets a copy of the metadata.
         virtual int           submitRequest(camera_metadata_t* metadata,
-                                            bool streaming = false);
-        virtual status_t      cancelRequest(int requestId);
-
-        virtual status_t      requestStream(int streamId);
-        virtual status_t      cancelStream(int streamId);
+                                            bool streaming = false) = 0;
+        virtual status_t      cancelRequest(int requestId) = 0;
 
         // Callbacks from camera service
-        virtual void          onExclusiveLockStolen();
+        virtual void          onExclusiveLockStolen() = 0;
 
     protected:
         virtual void          notifyError();
@@ -283,6 +278,22 @@
     // Delay-load the Camera HAL module
     virtual void onFirstRef();
 
+    // Step 1. Check if we can connect, before we acquire the service lock.
+    bool                validateConnect(int cameraId,
+                                        /*inout*/
+                                        int& clientUid) const;
+
+    // Step 2. Check if we can connect, after we acquire the service lock.
+    bool                canConnectUnsafe(int cameraId,
+                                         const String16& clientPackageName,
+                                         const sp<IBinder>& remoteCallback,
+                                         /*out*/
+                                         sp<Client> &client);
+
+    // When connection is successful, initialize client and track its death
+    bool                connectFinishUnsafe(const sp<BasicClient>& client,
+                                            const sp<IBinder>& clientBinder);
+
     virtual sp<BasicClient>  getClientByRemote(const wp<IBinder>& cameraClient);
 
     Mutex               mServiceLock;
diff --git a/services/camera/libcameraservice/ProCamera2Client.cpp b/services/camera/libcameraservice/ProCamera2Client.cpp
index 6fed8b4..575b075 100644
--- a/services/camera/libcameraservice/ProCamera2Client.cpp
+++ b/services/camera/libcameraservice/ProCamera2Client.cpp
@@ -27,68 +27,43 @@
 #include "camera2/Parameters.h"
 #include "ProCamera2Client.h"
 #include "camera2/ProFrameProcessor.h"
+#include "CameraDeviceBase.h"
 
 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);
+    mFrameProcessor = new ProFrameProcessor(mDevice);
+    threadName = String8::format("PC2-%d-FrameProc", mCameraId);
     mFrameProcessor->run(threadName.string());
 
     mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,
@@ -99,20 +74,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 +111,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 +145,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 +166,7 @@
 }
 
 bool ProCamera2Client::hasExclusiveLock() {
+    Mutex::Autolock icl(mBinderSerializationLock);
     return mExclusiveLock;
 }
 
@@ -205,7 +174,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 +193,7 @@
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
@@ -248,7 +217,7 @@
     ATRACE_CALL();
     ALOGV("%s", __FUNCTION__);
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
@@ -256,24 +225,19 @@
         return PERMISSION_DENIED;
     }
 
+    // TODO: implement
     ALOGE("%s: not fully implemented yet", __FUNCTION__);
     return INVALID_OPERATION;
 }
 
-status_t ProCamera2Client::requestStream(int streamId) {
-    ALOGE("%s: not implemented yet", __FUNCTION__);
-
-    return INVALID_OPERATION;
-}
-
-status_t ProCamera2Client::cancelStream(int streamId) {
+status_t ProCamera2Client::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(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
     mDevice->clearStreamingRequest();
@@ -301,7 +265,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 +296,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 +316,7 @@
         return INVALID_OPERATION;
     }
 
-    Mutex::Autolock icl(mIProCameraUserLock);
+    Mutex::Autolock icl(mBinderSerializationLock);
 
     if (!mDevice.get()) return DEAD_OBJECT;
 
@@ -373,47 +337,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 +366,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..1dec263 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();
@@ -51,13 +48,15 @@
                                         bool streaming = false);
     virtual status_t      cancelRequest(int requestId);
 
-    virtual status_t      requestStream(int streamId);
-    virtual status_t      cancelStream(int streamId);
+    virtual status_t      deleteStream(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 +84,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 +95,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..d13d398 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.cpp
@@ -28,146 +28,37 @@
 namespace android {
 namespace camera2 {
 
-FrameProcessor::FrameProcessor(wp<Camera2Client> client):
-        Thread(false), mClient(client), mLastFrameNumberOfFaces(0) {
+FrameProcessor::FrameProcessor(wp<CameraDeviceBase> device,
+                               wp<Camera2Client> client) :
+    ProFrameProcessor(device),
+    mClient(client),
+    mLastFrameNumberOfFaces(0) {
 }
 
 FrameProcessor::~FrameProcessor() {
-    ALOGV("%s: Exit", __FUNCTION__);
 }
 
-status_t FrameProcessor::registerListener(int32_t minId,
-        int32_t maxId, wp<FilteredListener> listener) {
-    Mutex::Autolock l(mInputMutex);
-    ALOGV("%s: Registering listener for frame id range %d - %d",
-            __FUNCTION__, minId, maxId);
-    RangeListener rListener = { minId, maxId, listener };
-    mRangeListeners.push_back(rListener);
-    return OK;
-}
+bool FrameProcessor::processSingleFrame(CameraMetadata &frame,
+                                        const sp<CameraDeviceBase> &device) {
 
-status_t FrameProcessor::removeListener(int32_t minId,
-        int32_t maxId, wp<FilteredListener> listener) {
-    Mutex::Autolock l(mInputMutex);
-    List<RangeListener>::iterator item = mRangeListeners.begin();
-    while (item != mRangeListeners.end()) {
-        if (item->minId == minId &&
-                item->maxId == maxId &&
-                item->listener == listener) {
-            item = mRangeListeners.erase(item);
-        } else {
-            item++;
-        }
-    }
-    return OK;
-}
-
-void FrameProcessor::dump(int fd, const Vector<String16>& /*args*/) {
-    String8 result("    Latest received frame:\n");
-    write(fd, result.string(), result.size());
-    mLastFrame.dump(fd, 2, 6);
-}
-
-bool FrameProcessor::threadLoop() {
-    status_t res;
-
-    sp<CameraDeviceBase> device;
-    {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        device = client->getCameraDevice();
-        if (device == 0) return false;
+    sp<Camera2Client> client = mClient.promote();
+    if (!client.get()) {
+        return false;
     }
 
-    res = device->waitForNextFrame(kWaitDuration);
-    if (res == OK) {
-        sp<Camera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        processNewFrames(client);
-    } else if (res != TIMED_OUT) {
-        ALOGE("Camera2Client::FrameProcessor: Error waiting for new "
-                "frames: %s (%d)", strerror(-res), res);
+    if (processFaceDetect(frame, client) != OK) {
+        return false;
+    }
+
+    if (!ProFrameProcessor::processSingleFrame(frame, device)) {
+        return false;
     }
 
     return true;
 }
 
-void FrameProcessor::processNewFrames(sp<Camera2Client> &client) {
-    status_t res;
-    ATRACE_CALL();
-    CameraMetadata frame;
-    while ( (res = client->getCameraDevice()->getNextFrame(&frame)) == OK) {
-        camera_metadata_entry_t entry;
-
-        entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
-        if (entry.count == 0) {
-            ALOGE("%s: Camera %d: Error reading frame number",
-                    __FUNCTION__, client->getCameraId());
-            break;
-        }
-        ATRACE_INT("cam2_frame", entry.data.i32[0]);
-
-        res = processFaceDetect(frame, client);
-        if (res != OK) break;
-
-        res = processListeners(frame, client);
-        if (res != OK) break;
-
-        if (!frame.isEmpty()) {
-            mLastFrame.acquire(frame);
-        }
-    }
-    if (res != NOT_ENOUGH_DATA) {
-        ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
-        return;
-    }
-
-    return;
-}
-
-status_t FrameProcessor::processListeners(const CameraMetadata &frame,
-        sp<Camera2Client> &client) {
-    ATRACE_CALL();
-    camera_metadata_ro_entry_t entry;
-
-    entry = frame.find(ANDROID_REQUEST_ID);
-    if (entry.count == 0) {
-        ALOGE("%s: Camera %d: Error reading frame id",
-                __FUNCTION__, client->getCameraId());
-        return BAD_VALUE;
-    }
-    int32_t frameId = entry.data.i32[0];
-
-    List<sp<FilteredListener> > listeners;
-    {
-        Mutex::Autolock l(mInputMutex);
-
-        List<RangeListener>::iterator item = mRangeListeners.begin();
-        while (item != mRangeListeners.end()) {
-            if (frameId >= item->minId &&
-                    frameId < item->maxId) {
-                sp<FilteredListener> listener = item->listener.promote();
-                if (listener == 0) {
-                    item = mRangeListeners.erase(item);
-                    continue;
-                } else {
-                    listeners.push_back(listener);
-                }
-            }
-            item++;
-        }
-    }
-    ALOGV("Got %d range listeners out of %d", listeners.size(), mRangeListeners.size());
-    List<sp<FilteredListener> >::iterator item = listeners.begin();
-    for (; item != listeners.end(); item++) {
-        (*item)->onFrameAvailable(frameId, frame);
-    }
-    return OK;
-}
-
 status_t FrameProcessor::processFaceDetect(const CameraMetadata &frame,
-        sp<Camera2Client> &client) {
+        const sp<Camera2Client> &client) {
     status_t res = BAD_VALUE;
     ATRACE_CALL();
     camera_metadata_ro_entry_t entry;
@@ -190,12 +81,14 @@
     Vector<camera_face_t> faces;
     metadata.number_of_faces = 0;
 
-    if (enableFaceDetect && faceDetectMode != ANDROID_STATISTICS_FACE_DETECT_MODE_OFF) {
+    if (enableFaceDetect &&
+        faceDetectMode != ANDROID_STATISTICS_FACE_DETECT_MODE_OFF) {
+
         SharedParameters::Lock l(client->getParameters());
         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;
         }
@@ -263,17 +156,17 @@
             if (faceDetectMode == ANDROID_STATISTICS_FACE_DETECT_MODE_FULL) {
                 face.id = faceIds[i];
                 face.left_eye[0] =
-                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 0]);
+                    l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 0]);
                 face.left_eye[1] =
-                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 1]);
+                    l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 1]);
                 face.right_eye[0] =
-                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 2]);
+                    l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 2]);
                 face.right_eye[1] =
-                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 3]);
+                    l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 3]);
                 face.mouth[0] =
-                        l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 4]);
+                    l.mParameters.arrayXToNormalized(faceLandmarks[i*6 + 4]);
                 face.mouth[1] =
-                        l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 5]);
+                    l.mParameters.arrayYToNormalized(faceLandmarks[i*6 + 5]);
             } else {
                 face.id = 0;
                 face.left_eye[0] = face.left_eye[1] = -2000;
@@ -286,21 +179,31 @@
         metadata.faces = faces.editArray();
     }
 
-    /* warning: locks SharedCameraClient */
+    /* warning: locks SharedCameraCallbacks */
     callbackFaceDetection(client, metadata);
 
     return OK;
 }
 
 void FrameProcessor::callbackFaceDetection(sp<Camera2Client> client,
-                               /*in*/camera_frame_metadata &metadata) {
+                                     const camera_frame_metadata &metadata) {
 
-    /* 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,
-                    NULL, &metadata);
+    camera_frame_metadata *metadata_ptr =
+        const_cast<camera_frame_metadata*>(&metadata);
+
+    /**
+     * 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::SharedCameraCallbacks::Lock
+            l(client->mSharedCameraCallbacks);
+        if (l.mRemoteCallback != NULL) {
+            l.mRemoteCallback->dataCallback(CAMERA_MSG_PREVIEW_METADATA,
+                                            NULL,
+                                            metadata_ptr);
         }
     }
 
diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.h b/services/camera/libcameraservice/camera2/FrameProcessor.h
index 66e3cda..27ed8f6 100644
--- a/services/camera/libcameraservice/camera2/FrameProcessor.h
+++ b/services/camera/libcameraservice/camera2/FrameProcessor.h
@@ -22,7 +22,9 @@
 #include <utils/Vector.h>
 #include <utils/KeyedVector.h>
 #include <utils/List.h>
-#include "camera/CameraMetadata.h"
+#include <camera/CameraMetadata.h>
+
+#include "ProFrameProcessor.h"
 
 struct camera_frame_metadata;
 
@@ -35,51 +37,26 @@
 /* Output frame metadata processing thread.  This thread waits for new
  * frames from the device, and analyzes them as necessary.
  */
-class FrameProcessor: public Thread {
+class FrameProcessor : public ProFrameProcessor {
   public:
-    FrameProcessor(wp<Camera2Client> client);
+    FrameProcessor(wp<CameraDeviceBase> device, wp<Camera2Client> client);
     ~FrameProcessor();
 
-    struct FilteredListener: virtual public RefBase {
-        virtual void onFrameAvailable(int32_t frameId,
-                const CameraMetadata &frame) = 0;
-    };
-
-    // Register a listener for a range of IDs [minId, maxId). Multiple listeners
-    // can be listening to the same range
-    status_t registerListener(int32_t minId, int32_t maxId, wp<FilteredListener> listener);
-    status_t removeListener(int32_t minId, int32_t maxId, wp<FilteredListener> listener);
-
-    void dump(int fd, const Vector<String16>& args);
   private:
-    static const nsecs_t kWaitDuration = 10000000; // 10 ms
     wp<Camera2Client> mClient;
+    int mLastFrameNumberOfFaces;
 
-    virtual bool threadLoop();
+    void processNewFrames(const sp<Camera2Client> &client);
 
-    Mutex mInputMutex;
-
-    struct RangeListener {
-        int32_t minId;
-        int32_t maxId;
-        wp<FilteredListener> listener;
-    };
-    List<RangeListener> mRangeListeners;
-
-    void processNewFrames(sp<Camera2Client> &client);
+    virtual bool processSingleFrame(CameraMetadata &frame,
+                                    const sp<CameraDeviceBase> &device);
 
     status_t processFaceDetect(const CameraMetadata &frame,
-            sp<Camera2Client> &client);
-
-    status_t processListeners(const CameraMetadata &frame,
-            sp<Camera2Client> &client);
-
-    CameraMetadata mLastFrame;
-    int mLastFrameNumberOfFaces;
+            const sp<Camera2Client> &client);
 
     // Emit FaceDetection event to java if faces changed
     void callbackFaceDetection(sp<Camera2Client> client,
-                               camera_frame_metadata &metadata);
+                               const camera_frame_metadata &metadata);
 };
 
 
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
index 8d4933c..257a45f 100644
--- a/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
+++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.cpp
@@ -22,14 +22,14 @@
 #include <utils/Trace.h>
 
 #include "ProFrameProcessor.h"
-#include "../Camera2Device.h"
-#include "../ProCamera2Client.h"
+#include "../CameraDeviceBase.h"
 
 namespace android {
 namespace camera2 {
 
-ProFrameProcessor::ProFrameProcessor(wp<ProCamera2Client> client):
-        Thread(false), mClient(client) {
+ProFrameProcessor::ProFrameProcessor(wp<CameraDeviceBase> device) :
+    Thread(/*canCallJava*/false),
+    mDevice(device) {
 }
 
 ProFrameProcessor::~ProFrameProcessor() {
@@ -47,7 +47,8 @@
 }
 
 status_t ProFrameProcessor::removeListener(int32_t minId,
-        int32_t maxId, wp<FilteredListener> listener) {
+                                           int32_t maxId,
+                                           wp<FilteredListener> listener) {
     Mutex::Autolock l(mInputMutex);
     List<RangeListener>::iterator item = mRangeListeners.begin();
     while (item != mRangeListeners.end()) {
@@ -62,7 +63,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,44 +72,42 @@
 bool ProFrameProcessor::threadLoop() {
     status_t res;
 
-    sp<Camera2Device> device;
+    sp<CameraDeviceBase> device;
     {
-        sp<ProCamera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        device = client->getCameraDevice();
+        device = mDevice.promote();
         if (device == 0) return false;
     }
 
     res = device->waitForNextFrame(kWaitDuration);
     if (res == OK) {
-        sp<ProCamera2Client> client = mClient.promote();
-        if (client == 0) return false;
-        processNewFrames(client);
+        processNewFrames(device);
     } else if (res != TIMED_OUT) {
-        ALOGE("ProCamera2Client::ProFrameProcessor: Error waiting for new "
+        ALOGE("ProFrameProcessor: Error waiting for new "
                 "frames: %s (%d)", strerror(-res), res);
     }
 
     return true;
 }
 
-void ProFrameProcessor::processNewFrames(sp<ProCamera2Client> &client) {
+void ProFrameProcessor::processNewFrames(const sp<CameraDeviceBase> &device) {
     status_t res;
     ATRACE_CALL();
     CameraMetadata frame;
-    while ( (res = client->getCameraDevice()->getNextFrame(&frame)) == OK) {
+    while ( (res = device->getNextFrame(&frame)) == OK) {
+
         camera_metadata_entry_t entry;
 
         entry = frame.find(ANDROID_REQUEST_FRAME_COUNT);
         if (entry.count == 0) {
             ALOGE("%s: Camera %d: Error reading frame number",
-                    __FUNCTION__, client->getCameraId());
+                    __FUNCTION__, device->getId());
             break;
         }
         ATRACE_INT("cam2_frame", entry.data.i32[0]);
 
-        res = processListeners(frame, client);
-        if (res != OK) break;
+        if (!processSingleFrame(frame, device)) {
+            break;
+        }
 
         if (!frame.isEmpty()) {
             mLastFrame.acquire(frame);
@@ -116,23 +115,27 @@
     }
     if (res != NOT_ENOUGH_DATA) {
         ALOGE("%s: Camera %d: Error getting next frame: %s (%d)",
-                __FUNCTION__, client->getCameraId(), strerror(-res), res);
+                __FUNCTION__, device->getId(), strerror(-res), res);
         return;
     }
 
     return;
 }
 
+bool ProFrameProcessor::processSingleFrame(CameraMetadata &frame,
+                                           const sp<CameraDeviceBase> &device) {
+    return processListeners(frame, device) == OK;
+}
+
 status_t ProFrameProcessor::processListeners(const CameraMetadata &frame,
-        sp<ProCamera2Client> &client) {
-    status_t res;
+        const sp<CameraDeviceBase> &device) {
     ATRACE_CALL();
     camera_metadata_ro_entry_t entry;
 
     entry = frame.find(ANDROID_REQUEST_ID);
     if (entry.count == 0) {
         ALOGE("%s: Camera %d: Error reading frame id",
-                __FUNCTION__, client->getCameraId());
+                __FUNCTION__, device->getId());
         return BAD_VALUE;
     }
     int32_t frameId = entry.data.i32[0];
diff --git a/services/camera/libcameraservice/camera2/ProFrameProcessor.h b/services/camera/libcameraservice/camera2/ProFrameProcessor.h
index e4094a6..b82942c 100644
--- a/services/camera/libcameraservice/camera2/ProFrameProcessor.h
+++ b/services/camera/libcameraservice/camera2/ProFrameProcessor.h
@@ -24,11 +24,9 @@
 #include <utils/List.h>
 #include <camera/CameraMetadata.h>
 
-struct camera_frame_metadata;
-
 namespace android {
 
-class ProCamera2Client;
+class CameraDeviceBase;
 
 namespace camera2 {
 
@@ -37,23 +35,25 @@
  */
 class ProFrameProcessor: public Thread {
   public:
-    ProFrameProcessor(wp<ProCamera2Client> client);
-    ~ProFrameProcessor();
+    ProFrameProcessor(wp<CameraDeviceBase> device);
+    virtual ~ProFrameProcessor();
 
     struct FilteredListener: virtual public RefBase {
         virtual void onFrameAvailable(int32_t frameId,
-                const CameraMetadata &frame) = 0;
+                                      const CameraMetadata &frame) = 0;
     };
 
     // Register a listener for a range of IDs [minId, maxId). Multiple listeners
     // can be listening to the same range
-    status_t registerListener(int32_t minId, int32_t maxId, wp<FilteredListener> listener);
-    status_t removeListener(int32_t minId, int32_t maxId, wp<FilteredListener> listener);
+    status_t registerListener(int32_t minId, int32_t maxId,
+                              wp<FilteredListener> listener);
+    status_t removeListener(int32_t minId, int32_t maxId,
+                            wp<FilteredListener> listener);
 
     void dump(int fd, const Vector<String16>& args);
-  private:
+  protected:
     static const nsecs_t kWaitDuration = 10000000; // 10 ms
-    wp<ProCamera2Client> mClient;
+    wp<CameraDeviceBase> mDevice;
 
     virtual bool threadLoop();
 
@@ -66,10 +66,13 @@
     };
     List<RangeListener> mRangeListeners;
 
-    void processNewFrames(sp<ProCamera2Client> &client);
+    void processNewFrames(const sp<CameraDeviceBase> &device);
+
+    virtual bool processSingleFrame(CameraMetadata &frame,
+                                    const sp<CameraDeviceBase> &device);
 
     status_t processListeners(const CameraMetadata &frame,
-            sp<ProCamera2Client> &client);
+                              const sp<CameraDeviceBase> &device);
 
     CameraMetadata mLastFrame;
 };
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]);
     }
diff --git a/services/camera/tests/CameraServiceTest/Android.mk b/services/camera/tests/CameraServiceTest/Android.mk
deleted file mode 100644
index 41b6f63..0000000
--- a/services/camera/tests/CameraServiceTest/Android.mk
+++ /dev/null
@@ -1,26 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= CameraServiceTest.cpp
-
-LOCAL_MODULE:= CameraServiceTest
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_C_INCLUDES += \
-                frameworks/av/libs
-
-LOCAL_CFLAGS :=
-
-LOCAL_SHARED_LIBRARIES += \
-		libbinder \
-                libcutils \
-                libutils \
-                libui \
-                libcamera_client \
-                libgui
-
-# Disable it because the ISurface interface may change, and before we have a
-# chance to fix this test, we don't want to break normal builds.
-#include $(BUILD_EXECUTABLE)
diff --git a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp b/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
deleted file mode 100644
index e417b79..0000000
--- a/services/camera/tests/CameraServiceTest/CameraServiceTest.cpp
+++ /dev/null
@@ -1,924 +0,0 @@
-/*
- * Copyright (C) 2010 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 "CameraServiceTest"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <camera/Camera.h>
-#include <camera/CameraParameters.h>
-#include <ui/GraphicBuffer.h>
-#include <camera/ICamera.h>
-#include <camera/ICameraClient.h>
-#include <camera/ICameraService.h>
-#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
-#include <binder/ProcessState.h>
-#include <utils/KeyedVector.h>
-#include <utils/Log.h>
-#include <utils/Vector.h>
-#include <utils/threads.h>
-
-using namespace android;
-
-//
-//  Assertion and Logging utilities
-//
-#define INFO(...) \
-    do { \
-        printf(__VA_ARGS__); \
-        printf("\n"); \
-        ALOGD(__VA_ARGS__); \
-    } while(0)
-
-void assert_fail(const char *file, int line, const char *func, const char *expr) {
-    INFO("assertion failed at file %s, line %d, function %s:",
-            file, line, func);
-    INFO("%s", expr);
-    abort();
-}
-
-void assert_eq_fail(const char *file, int line, const char *func,
-        const char *expr, int actual) {
-    INFO("assertion failed at file %s, line %d, function %s:",
-            file, line, func);
-    INFO("(expected) %s != (actual) %d", expr, actual);
-    abort();
-}
-
-#define ASSERT(e) \
-    do { \
-        if (!(e)) \
-            assert_fail(__FILE__, __LINE__, __func__, #e); \
-    } while(0)
-
-#define ASSERT_EQ(expected, actual) \
-    do { \
-        int _x = (actual); \
-        if (_x != (expected)) \
-            assert_eq_fail(__FILE__, __LINE__, __func__, #expected, _x); \
-    } while(0)
-
-//
-//  Holder service for pass objects between processes.
-//
-class IHolder : public IInterface {
-protected:
-    enum {
-        HOLDER_PUT = IBinder::FIRST_CALL_TRANSACTION,
-        HOLDER_GET,
-        HOLDER_CLEAR
-    };
-public:
-    DECLARE_META_INTERFACE(Holder);
-
-    virtual void put(sp<IBinder> obj) = 0;
-    virtual sp<IBinder> get() = 0;
-    virtual void clear() = 0;
-};
-
-class BnHolder : public BnInterface<IHolder> {
-    virtual status_t onTransact(uint32_t code,
-                                const Parcel& data,
-                                Parcel* reply,
-                                uint32_t flags = 0);
-};
-
-class BpHolder : public BpInterface<IHolder> {
-public:
-    BpHolder(const sp<IBinder>& impl)
-        : BpInterface<IHolder>(impl) {
-    }
-
-    virtual void put(sp<IBinder> obj) {
-        Parcel data, reply;
-        data.writeStrongBinder(obj);
-        remote()->transact(HOLDER_PUT, data, &reply, IBinder::FLAG_ONEWAY);
-    }
-
-    virtual sp<IBinder> get() {
-        Parcel data, reply;
-        remote()->transact(HOLDER_GET, data, &reply);
-        return reply.readStrongBinder();
-    }
-
-    virtual void clear() {
-        Parcel data, reply;
-        remote()->transact(HOLDER_CLEAR, data, &reply);
-    }
-};
-
-IMPLEMENT_META_INTERFACE(Holder, "CameraServiceTest.Holder");
-
-status_t BnHolder::onTransact(
-    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
-    switch(code) {
-        case HOLDER_PUT: {
-            put(data.readStrongBinder());
-            return NO_ERROR;
-        } break;
-        case HOLDER_GET: {
-            reply->writeStrongBinder(get());
-            return NO_ERROR;
-        } break;
-        case HOLDER_CLEAR: {
-            clear();
-            return NO_ERROR;
-        } break;
-        default:
-            return BBinder::onTransact(code, data, reply, flags);
-    }
-}
-
-class HolderService : public BnHolder {
-    virtual void put(sp<IBinder> obj) {
-        mObj = obj;
-    }
-    virtual sp<IBinder> get() {
-        return mObj;
-    }
-    virtual void clear() {
-        mObj.clear();
-    }
-private:
-    sp<IBinder> mObj;
-};
-
-//
-//  A mock CameraClient
-//
-class MCameraClient : public BnCameraClient {
-public:
-    virtual void notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2);
-    virtual void dataCallback(int32_t msgType, const sp<IMemory>& data);
-    virtual void dataCallbackTimestamp(nsecs_t timestamp,
-            int32_t msgType, const sp<IMemory>& data);
-
-    // new functions
-    void clearStat();
-    enum OP { EQ, GE, LE, GT, LT };
-    void assertNotify(int32_t msgType, OP op, int count);
-    void assertData(int32_t msgType, OP op, int count);
-    void waitNotify(int32_t msgType, OP op, int count);
-    void waitData(int32_t msgType, OP op, int count);
-    void assertDataSize(int32_t msgType, OP op, int dataSize);
-
-    void setReleaser(ICamera *releaser) {
-        mReleaser = releaser;
-    }
-private:
-    Mutex mLock;
-    Condition mCond;
-    DefaultKeyedVector<int32_t, int> mNotifyCount;
-    DefaultKeyedVector<int32_t, int> mDataCount;
-    DefaultKeyedVector<int32_t, int> mDataSize;
-    bool test(OP op, int v1, int v2);
-    void assertTest(OP op, int v1, int v2);
-
-    ICamera *mReleaser;
-};
-
-void MCameraClient::clearStat() {
-    Mutex::Autolock _l(mLock);
-    mNotifyCount.clear();
-    mDataCount.clear();
-    mDataSize.clear();
-}
-
-bool MCameraClient::test(OP op, int v1, int v2) {
-    switch (op) {
-        case EQ: return v1 == v2;
-        case GT: return v1 > v2;
-        case LT: return v1 < v2;
-        case GE: return v1 >= v2;
-        case LE: return v1 <= v2;
-        default: ASSERT(0); break;
-    }
-    return false;
-}
-
-void MCameraClient::assertTest(OP op, int v1, int v2) {
-    if (!test(op, v1, v2)) {
-        ALOGE("assertTest failed: op=%d, v1=%d, v2=%d", op, v1, v2);
-        ASSERT(0);
-    }
-}
-
-void MCameraClient::assertNotify(int32_t msgType, OP op, int count) {
-    Mutex::Autolock _l(mLock);
-    int v = mNotifyCount.valueFor(msgType);
-    assertTest(op, v, count);
-}
-
-void MCameraClient::assertData(int32_t msgType, OP op, int count) {
-    Mutex::Autolock _l(mLock);
-    int v = mDataCount.valueFor(msgType);
-    assertTest(op, v, count);
-}
-
-void MCameraClient::assertDataSize(int32_t msgType, OP op, int dataSize) {
-    Mutex::Autolock _l(mLock);
-    int v = mDataSize.valueFor(msgType);
-    assertTest(op, v, dataSize);
-}
-
-void MCameraClient::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2) {
-    INFO("%s", __func__);
-    Mutex::Autolock _l(mLock);
-    ssize_t i = mNotifyCount.indexOfKey(msgType);
-    if (i < 0) {
-        mNotifyCount.add(msgType, 1);
-    } else {
-        ++mNotifyCount.editValueAt(i);
-    }
-    mCond.signal();
-}
-
-void MCameraClient::dataCallback(int32_t msgType, const sp<IMemory>& data) {
-    INFO("%s", __func__);
-    int dataSize = data->size();
-    INFO("data type = %d, size = %d", msgType, dataSize);
-    Mutex::Autolock _l(mLock);
-    ssize_t i = mDataCount.indexOfKey(msgType);
-    if (i < 0) {
-        mDataCount.add(msgType, 1);
-        mDataSize.add(msgType, dataSize);
-    } else {
-        ++mDataCount.editValueAt(i);
-        mDataSize.editValueAt(i) = dataSize;
-    }
-    mCond.signal();
-
-    if (msgType == CAMERA_MSG_VIDEO_FRAME) {
-        ASSERT(mReleaser != NULL);
-        mReleaser->releaseRecordingFrame(data);
-    }
-}
-
-void MCameraClient::dataCallbackTimestamp(nsecs_t timestamp, int32_t msgType,
-        const sp<IMemory>& data) {
-    dataCallback(msgType, data);
-}
-
-void MCameraClient::waitNotify(int32_t msgType, OP op, int count) {
-    INFO("waitNotify: %d, %d, %d", msgType, op, count);
-    Mutex::Autolock _l(mLock);
-    while (true) {
-        int v = mNotifyCount.valueFor(msgType);
-        if (test(op, v, count)) {
-            break;
-        }
-        mCond.wait(mLock);
-    }
-}
-
-void MCameraClient::waitData(int32_t msgType, OP op, int count) {
-    INFO("waitData: %d, %d, %d", msgType, op, count);
-    Mutex::Autolock _l(mLock);
-    while (true) {
-        int v = mDataCount.valueFor(msgType);
-        if (test(op, v, count)) {
-            break;
-        }
-        mCond.wait(mLock);
-    }
-}
-
-//
-//  A mock Surface
-//
-class MSurface : public BnSurface {
-public:
-    virtual status_t registerBuffers(const BufferHeap& buffers);
-    virtual void postBuffer(ssize_t offset);
-    virtual void unregisterBuffers();
-    virtual sp<GraphicBuffer> requestBuffer(int bufferIdx, int usage);
-    virtual status_t setBufferCount(int bufferCount);
-
-    // new functions
-    void clearStat();
-    void waitUntil(int c0, int c1, int c2);
-
-private:
-    // check callback count
-    Condition mCond;
-    Mutex mLock;
-    int registerBuffersCount;
-    int postBufferCount;
-    int unregisterBuffersCount;
-};
-
-status_t MSurface::registerBuffers(const BufferHeap& buffers) {
-    INFO("%s", __func__);
-    Mutex::Autolock _l(mLock);
-    ++registerBuffersCount;
-    mCond.signal();
-    return NO_ERROR;
-}
-
-void MSurface::postBuffer(ssize_t offset) {
-    // INFO("%s", __func__);
-    Mutex::Autolock _l(mLock);
-    ++postBufferCount;
-    mCond.signal();
-}
-
-void MSurface::unregisterBuffers() {
-    INFO("%s", __func__);
-    Mutex::Autolock _l(mLock);
-    ++unregisterBuffersCount;
-    mCond.signal();
-}
-
-sp<GraphicBuffer> MSurface::requestBuffer(int bufferIdx, int usage) {
-    INFO("%s", __func__);
-    return NULL;
-}
-
-status_t MSurface::setBufferCount(int bufferCount) {
-    INFO("%s", __func__);
-    return NULL;
-}
-
-void MSurface::clearStat() {
-    Mutex::Autolock _l(mLock);
-    registerBuffersCount = 0;
-    postBufferCount = 0;
-    unregisterBuffersCount = 0;
-}
-
-void MSurface::waitUntil(int c0, int c1, int c2) {
-    INFO("waitUntil: %d %d %d", c0, c1, c2);
-    Mutex::Autolock _l(mLock);
-    while (true) {
-        if (registerBuffersCount >= c0 &&
-            postBufferCount >= c1 &&
-            unregisterBuffersCount >= c2) {
-            break;
-        }
-        mCond.wait(mLock);
-    }
-}
-
-//
-//  Utilities to use the Holder service
-//
-sp<IHolder> getHolder() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    ASSERT(sm != 0);
-    sp<IBinder> binder = sm->getService(String16("CameraServiceTest.Holder"));
-    ASSERT(binder != 0);
-    sp<IHolder> holder = interface_cast<IHolder>(binder);
-    ASSERT(holder != 0);
-    return holder;
-}
-
-void putTempObject(sp<IBinder> obj) {
-    INFO("%s", __func__);
-    getHolder()->put(obj);
-}
-
-sp<IBinder> getTempObject() {
-    INFO("%s", __func__);
-    return getHolder()->get();
-}
-
-void clearTempObject() {
-    INFO("%s", __func__);
-    getHolder()->clear();
-}
-
-//
-//  Get a Camera Service
-//
-sp<ICameraService> getCameraService() {
-    sp<IServiceManager> sm = defaultServiceManager();
-    ASSERT(sm != 0);
-    sp<IBinder> binder = sm->getService(String16("media.camera"));
-    ASSERT(binder != 0);
-    sp<ICameraService> cs = interface_cast<ICameraService>(binder);
-    ASSERT(cs != 0);
-    return cs;
-}
-
-int getNumberOfCameras() {
-    sp<ICameraService> cs = getCameraService();
-    return cs->getNumberOfCameras();
-}
-
-//
-// Various Connect Tests
-//
-void testConnect(int cameraId) {
-    INFO("%s", __func__);
-    sp<ICameraService> cs = getCameraService();
-    sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc, cameraId);
-    ASSERT(c != 0);
-    c->disconnect();
-}
-
-void testAllowConnectOnceOnly(int cameraId) {
-    INFO("%s", __func__);
-    sp<ICameraService> cs = getCameraService();
-    // Connect the first client.
-    sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc, cameraId);
-    ASSERT(c != 0);
-    // Same client -- ok.
-    ASSERT(cs->connect(cc, cameraId) != 0);
-    // Different client -- not ok.
-    sp<MCameraClient> cc2 = new MCameraClient();
-    ASSERT(cs->connect(cc2, cameraId) == 0);
-    c->disconnect();
-}
-
-void testReconnectFailed() {
-    INFO("%s", __func__);
-    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
-    sp<MCameraClient> cc = new MCameraClient();
-    ASSERT(c->connect(cc) != NO_ERROR);
-}
-
-void testReconnectSuccess() {
-    INFO("%s", __func__);
-    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
-    sp<MCameraClient> cc = new MCameraClient();
-    ASSERT(c->connect(cc) == NO_ERROR);
-    c->disconnect();
-}
-
-void testLockFailed() {
-    INFO("%s", __func__);
-    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
-    ASSERT(c->lock() != NO_ERROR);
-}
-
-void testLockUnlockSuccess() {
-    INFO("%s", __func__);
-    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
-    ASSERT(c->lock() == NO_ERROR);
-    ASSERT(c->unlock() == NO_ERROR);
-}
-
-void testLockSuccess() {
-    INFO("%s", __func__);
-    sp<ICamera> c = interface_cast<ICamera>(getTempObject());
-    ASSERT(c->lock() == NO_ERROR);
-    c->disconnect();
-}
-
-//
-// Run the connect tests in another process.
-//
-const char *gExecutable;
-
-struct FunctionTableEntry {
-    const char *name;
-    void (*func)();
-};
-
-FunctionTableEntry function_table[] = {
-#define ENTRY(x) {#x, &x}
-    ENTRY(testReconnectFailed),
-    ENTRY(testReconnectSuccess),
-    ENTRY(testLockUnlockSuccess),
-    ENTRY(testLockFailed),
-    ENTRY(testLockSuccess),
-#undef ENTRY
-};
-
-void runFunction(const char *tag) {
-    INFO("runFunction: %s", tag);
-    int entries = sizeof(function_table) / sizeof(function_table[0]);
-    for (int i = 0; i < entries; i++) {
-        if (strcmp(function_table[i].name, tag) == 0) {
-            (*function_table[i].func)();
-            return;
-        }
-    }
-    ASSERT(0);
-}
-
-void runInAnotherProcess(const char *tag) {
-    pid_t pid = fork();
-    if (pid == 0) {
-        execlp(gExecutable, gExecutable, tag, NULL);
-        ASSERT(0);
-    } else {
-        int status;
-        ASSERT_EQ(pid, wait(&status));
-        ASSERT_EQ(0, status);
-    }
-}
-
-void testReconnect(int cameraId) {
-    INFO("%s", __func__);
-    sp<ICameraService> cs = getCameraService();
-    sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc, cameraId);
-    ASSERT(c != 0);
-    // Reconnect to the same client -- ok.
-    ASSERT(c->connect(cc) == NO_ERROR);
-    // Reconnect to a different client (but the same pid) -- ok.
-    sp<MCameraClient> cc2 = new MCameraClient();
-    ASSERT(c->connect(cc2) == NO_ERROR);
-    c->disconnect();
-    cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-}
-
-void testLockUnlock(int cameraId) {
-    sp<ICameraService> cs = getCameraService();
-    sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc, cameraId);
-    ASSERT(c != 0);
-    // We can lock as many times as we want.
-    ASSERT(c->lock() == NO_ERROR);
-    ASSERT(c->lock() == NO_ERROR);
-    // Lock from a different process -- not ok.
-    putTempObject(c->asBinder());
-    runInAnotherProcess("testLockFailed");
-    // Unlock then lock from a different process -- ok.
-    ASSERT(c->unlock() == NO_ERROR);
-    runInAnotherProcess("testLockUnlockSuccess");
-    // Unlock then lock from a different process -- ok.
-    runInAnotherProcess("testLockSuccess");
-    clearTempObject();
-}
-
-void testReconnectFromAnotherProcess(int cameraId) {
-    INFO("%s", __func__);
-
-    sp<ICameraService> cs = getCameraService();
-    sp<MCameraClient> cc = new MCameraClient();
-    sp<ICamera> c = cs->connect(cc, cameraId);
-    ASSERT(c != 0);
-    // Reconnect from a different process -- not ok.
-    putTempObject(c->asBinder());
-    runInAnotherProcess("testReconnectFailed");
-    // Unlock then reconnect from a different process -- ok.
-    ASSERT(c->unlock() == NO_ERROR);
-    runInAnotherProcess("testReconnectSuccess");
-    clearTempObject();
-}
-
-// We need to flush the command buffer after the reference
-// to ICamera is gone. The sleep is for the server to run
-// the destructor for it.
-static void flushCommands() {
-    IPCThreadState::self()->flushCommands();
-    usleep(200000);  // 200ms
-}
-
-// Run a test case
-#define RUN(class_name, cameraId) do { \
-    { \
-        INFO(#class_name); \
-        class_name instance; \
-        instance.init(cameraId); \
-        instance.run(); \
-    } \
-    flushCommands(); \
-} while(0)
-
-// Base test case after the the camera is connected.
-class AfterConnect {
-public:
-    void init(int cameraId) {
-        cs = getCameraService();
-        cc = new MCameraClient();
-        c = cs->connect(cc, cameraId);
-        ASSERT(c != 0);
-    }
-
-protected:
-    sp<ICameraService> cs;
-    sp<MCameraClient> cc;
-    sp<ICamera> c;
-
-    ~AfterConnect() {
-        c->disconnect();
-        c.clear();
-        cc.clear();
-        cs.clear();
-    }
-};
-
-class TestSetPreviewDisplay : public AfterConnect {
-public:
-    void run() {
-        sp<MSurface> surface = new MSurface();
-        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
-        c->disconnect();
-        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-    }
-};
-
-class TestStartPreview : public AfterConnect {
-public:
-    void run() {
-        sp<MSurface> surface = new MSurface();
-        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
-
-        ASSERT(c->startPreview() == NO_ERROR);
-        ASSERT(c->previewEnabled() == true);
-
-        surface->waitUntil(1, 10, 0); // needs 1 registerBuffers and 10 postBuffer
-        surface->clearStat();
-
-        sp<MSurface> another_surface = new MSurface();
-        c->setPreviewDisplay(another_surface);  // just to make sure unregisterBuffers
-                                                // is called.
-        surface->waitUntil(0, 0, 1);  // needs unregisterBuffers
-
-        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-    }
-};
-
-class TestStartPreviewWithoutDisplay : public AfterConnect {
-public:
-    void run() {
-        ASSERT(c->startPreview() == NO_ERROR);
-        ASSERT(c->previewEnabled() == true);
-        c->disconnect();
-        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-    }
-};
-
-// Base test case after the the camera is connected and the preview is started.
-class AfterStartPreview : public AfterConnect {
-public:
-    void init(int cameraId) {
-        AfterConnect::init(cameraId);
-        surface = new MSurface();
-        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
-        ASSERT(c->startPreview() == NO_ERROR);
-    }
-
-protected:
-    sp<MSurface> surface;
-
-    ~AfterStartPreview() {
-        surface.clear();
-    }
-};
-
-class TestAutoFocus : public AfterStartPreview {
-public:
-    void run() {
-        cc->assertNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 0);
-        c->autoFocus();
-        cc->waitNotify(CAMERA_MSG_FOCUS, MCameraClient::EQ, 1);
-        c->disconnect();
-        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-    }
-};
-
-class TestStopPreview : public AfterStartPreview {
-public:
-    void run() {
-        ASSERT(c->previewEnabled() == true);
-        c->stopPreview();
-        ASSERT(c->previewEnabled() == false);
-        c->disconnect();
-        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-    }
-};
-
-class TestTakePicture: public AfterStartPreview {
-public:
-    void run() {
-        ASSERT(c->takePicture() == NO_ERROR);
-        cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
-        cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
-        cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
-        c->stopPreview();
-        c->disconnect();
-        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-    }
-};
-
-class TestTakeMultiplePictures: public AfterStartPreview {
-public:
-    void run() {
-        for (int i = 0; i < 10; i++) {
-            cc->clearStat();
-            ASSERT(c->takePicture() == NO_ERROR);
-            cc->waitNotify(CAMERA_MSG_SHUTTER, MCameraClient::EQ, 1);
-            cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
-            cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
-        }
-        c->disconnect();
-        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-    }
-};
-
-class TestGetParameters: public AfterStartPreview {
-public:
-    void run() {
-        String8 param_str = c->getParameters();
-        INFO("%s", static_cast<const char*>(param_str));
-    }
-};
-
-static bool getNextSize(const char **ptrS, int *w, int *h) {
-    const char *s = *ptrS;
-
-    // skip over ','
-    if (*s == ',') s++;
-
-    // remember start position in p
-    const char *p = s;
-    while (*s != '\0' && *s != 'x') {
-        s++;
-    }
-    if (*s == '\0') return false;
-
-    // get the width
-    *w = atoi(p);
-
-    // skip over 'x'
-    ASSERT(*s == 'x');
-    p = s + 1;
-    while (*s != '\0' && *s != ',') {
-        s++;
-    }
-
-    // get the height
-    *h = atoi(p);
-    *ptrS = s;
-    return true;
-}
-
-class TestPictureSize : public AfterStartPreview {
-public:
-    void checkOnePicture(int w, int h) {
-        const float rate = 0.9;  // byte per pixel limit
-        int pixels = w * h;
-
-        CameraParameters param(c->getParameters());
-        param.setPictureSize(w, h);
-        // disable thumbnail to get more accurate size.
-        param.set(CameraParameters::KEY_JPEG_THUMBNAIL_WIDTH, 0);
-        param.set(CameraParameters::KEY_JPEG_THUMBNAIL_HEIGHT, 0);
-        c->setParameters(param.flatten());
-
-        cc->clearStat();
-        ASSERT(c->takePicture() == NO_ERROR);
-        cc->waitData(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, 1);
-        //cc->assertDataSize(CAMERA_MSG_RAW_IMAGE, MCameraClient::EQ, pixels*3/2);
-        cc->waitData(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::EQ, 1);
-        cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::LT,
-                int(pixels * rate));
-        cc->assertDataSize(CAMERA_MSG_COMPRESSED_IMAGE, MCameraClient::GT, 0);
-        cc->assertNotify(CAMERA_MSG_ERROR, MCameraClient::EQ, 0);
-    }
-
-    void run() {
-        CameraParameters param(c->getParameters());
-        int w, h;
-        const char *s = param.get(CameraParameters::KEY_SUPPORTED_PICTURE_SIZES);
-        while (getNextSize(&s, &w, &h)) {
-            ALOGD("checking picture size %dx%d", w, h);
-            checkOnePicture(w, h);
-        }
-    }
-};
-
-class TestPreviewCallbackFlag : public AfterConnect {
-public:
-    void run() {
-        sp<MSurface> surface = new MSurface();
-        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
-
-        // Try all flag combinations.
-        for (int v = 0; v < 8; v++) {
-            ALOGD("TestPreviewCallbackFlag: flag=%d", v);
-            usleep(100000); // sleep a while to clear the in-flight callbacks.
-            cc->clearStat();
-            c->setPreviewCallbackFlag(v);
-            ASSERT(c->previewEnabled() == false);
-            ASSERT(c->startPreview() == NO_ERROR);
-            ASSERT(c->previewEnabled() == true);
-            sleep(2);
-            c->stopPreview();
-            if ((v & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK) == 0) {
-                cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 0);
-            } else {
-                if ((v & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK) == 0) {
-                    cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 10);
-                } else {
-                    cc->assertData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, 1);
-                }
-            }
-        }
-    }
-};
-
-class TestRecording : public AfterConnect {
-public:
-    void run() {
-        ASSERT(c->recordingEnabled() == false);
-        sp<MSurface> surface = new MSurface();
-        ASSERT(c->setPreviewDisplay(surface) == NO_ERROR);
-        c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
-        cc->setReleaser(c.get());
-        c->startRecording();
-        ASSERT(c->recordingEnabled() == true);
-        sleep(2);
-        c->stopRecording();
-        usleep(100000); // sleep a while to clear the in-flight callbacks.
-        cc->setReleaser(NULL);
-        cc->assertData(CAMERA_MSG_VIDEO_FRAME, MCameraClient::GE, 10);
-    }
-};
-
-class TestPreviewSize : public AfterStartPreview {
-public:
-    void checkOnePicture(int w, int h) {
-        int size = w*h*3/2;  // should read from parameters
-
-        c->stopPreview();
-
-        CameraParameters param(c->getParameters());
-        param.setPreviewSize(w, h);
-        c->setPreviewCallbackFlag(CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
-        c->setParameters(param.flatten());
-
-        c->startPreview();
-
-        cc->clearStat();
-        cc->waitData(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::GE, 1);
-        cc->assertDataSize(CAMERA_MSG_PREVIEW_FRAME, MCameraClient::EQ, size);
-    }
-
-    void run() {
-        CameraParameters param(c->getParameters());
-        int w, h;
-        const char *s = param.get(CameraParameters::KEY_SUPPORTED_PREVIEW_SIZES);
-        while (getNextSize(&s, &w, &h)) {
-            ALOGD("checking preview size %dx%d", w, h);
-            checkOnePicture(w, h);
-        }
-    }
-};
-
-void runHolderService() {
-    defaultServiceManager()->addService(
-            String16("CameraServiceTest.Holder"), new HolderService());
-    ProcessState::self()->startThreadPool();
-}
-
-int main(int argc, char **argv)
-{
-    if (argc != 1) {
-        runFunction(argv[1]);
-        return 0;
-    }
-    INFO("CameraServiceTest start");
-    gExecutable = argv[0];
-    runHolderService();
-    int n = getNumberOfCameras();
-    INFO("%d Cameras available", n);
-
-    for (int id = 0; id < n; id++) {
-        INFO("Testing camera %d", id);
-        testConnect(id);                              flushCommands();
-        testAllowConnectOnceOnly(id);                 flushCommands();
-        testReconnect(id);                            flushCommands();
-        testLockUnlock(id);                           flushCommands();
-        testReconnectFromAnotherProcess(id);          flushCommands();
-
-        RUN(TestSetPreviewDisplay, id);
-        RUN(TestStartPreview, id);
-        RUN(TestStartPreviewWithoutDisplay, id);
-        RUN(TestAutoFocus, id);
-        RUN(TestStopPreview, id);
-        RUN(TestTakePicture, id);
-        RUN(TestTakeMultiplePictures, id);
-        RUN(TestGetParameters, id);
-        RUN(TestPictureSize, id);
-        RUN(TestPreviewCallbackFlag, id);
-        RUN(TestRecording, id);
-        RUN(TestPreviewSize, id);
-    }
-
-    INFO("CameraServiceTest finished");
-}
diff --git a/services/camera/tests/CameraServiceTest/MODULE_LICENSE_APACHE2 b/services/camera/tests/CameraServiceTest/MODULE_LICENSE_APACHE2
deleted file mode 100644
index e69de29..0000000
--- a/services/camera/tests/CameraServiceTest/MODULE_LICENSE_APACHE2
+++ /dev/null
diff --git a/services/camera/tests/CameraServiceTest/NOTICE b/services/camera/tests/CameraServiceTest/NOTICE
deleted file mode 100644
index c5b1efa..0000000
--- a/services/camera/tests/CameraServiceTest/NOTICE
+++ /dev/null
@@ -1,190 +0,0 @@
-
-   Copyright (c) 2005-2008, 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.
-
-   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.
-
-
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
-
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
-   1. Definitions.
-
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-