Camera2 multi-client support

Enable multiple clients to establish a shared session. Once the
session is created, allow each client to independently initiate and
terminate streaming using the `startStreaming` and `stopStreaming`
APIs. Additionally, primary clients can call create captureRequest
API. Ensure that all clients can simultaneously stream the camera
images.

Flag: com.android.internal.camera.flags.camera_multi_client
Bug:265196098
API-Coverage-Bug: 377371012
Test: A session is established with a shared configuration that
supports two streams: SurfaceView and ImageReader. The Java client
can create a session utilizing the SurfaceView stream. The native
client can create a session utilizing the ImageReader stream.
The Java client initiates streaming by creating a capture request and
using the `setRepeatingRequest` method. The native client initiates
streaming using the `startStreaming` API and the ImageReader surface
to receive camera images. Also, ran camera CTS tests on these CLs to
ensure we don't introduce any regressions.

Change-Id: I6ab4e5eef094e75c9b1230ad24afe1c50133df86
diff --git a/camera/ndk/NdkCameraCaptureSession.cpp b/camera/ndk/NdkCameraCaptureSession.cpp
index 58370e5..06ee714 100644
--- a/camera/ndk/NdkCameraCaptureSession.cpp
+++ b/camera/ndk/NdkCameraCaptureSession.cpp
@@ -178,30 +178,39 @@
 
 EXPORT
 camera_status_t ACameraCaptureSessionShared_startStreaming(
-    ACameraCaptureSession* /*session*/, ACameraCaptureSession_captureCallbacksV2* /*callbacks*/,
-    int /*numOutputWindows*/, ANativeWindow** /*window*/,
-    int* /*captureSequenceId*/) {
+    ACameraCaptureSession* session,
+    /*optional*/ACameraCaptureSession_captureCallbacksV2* callbacks,
+    int numOutputWindows, ANativeWindow** windows,
+    /*optional*/int* captureSequenceId) {
     ATRACE_CALL();
-    // Todo: need to add implementation
-    return  ACAMERA_OK;
+    return startStreamingTemplate(session, callbacks, numOutputWindows, windows,
+            captureSequenceId);
 }
 
 EXPORT
 camera_status_t ACameraCaptureSessionShared_logicalCamera_startStreaming(
-    ACameraCaptureSession* /*session*/,
-    ACameraCaptureSession_logicalCamera_captureCallbacksV2* /*callbacks*/,
-    int /*numOutputWindows*/, ANativeWindow** /*windows*/,
-    int* /*captureSequenceId*/) {
+    ACameraCaptureSession* session,
+    /*optional*/ACameraCaptureSession_logicalCamera_captureCallbacksV2* callbacks,
+    int numOutputWindows, ANativeWindow** windows,
+    /*optional*/int* captureSequenceId) {
     ATRACE_CALL();
-    // Todo: need to add implementation
-    return  ACAMERA_OK;
+    return  startStreamingTemplate(session, callbacks, numOutputWindows, windows,
+            captureSequenceId);
 }
 
 EXPORT
-camera_status_t ACameraCaptureSessionShared_stopStreaming(ACameraCaptureSession* /*session*/) {
+camera_status_t ACameraCaptureSessionShared_stopStreaming(ACameraCaptureSession* session) {
     ATRACE_CALL();
-    // Todo: need to add implementation
-    return  ACAMERA_OK;
+    if (session == nullptr) {
+        ALOGE("%s: Error: session is null", __FUNCTION__);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (session->isClosed()) {
+        ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+    return session->stopStreaming();
 }
 
 EXPORT
diff --git a/camera/ndk/NdkCameraCaptureSession.inc b/camera/ndk/NdkCameraCaptureSession.inc
index 258e20d..3112735 100644
--- a/camera/ndk/NdkCameraCaptureSession.inc
+++ b/camera/ndk/NdkCameraCaptureSession.inc
@@ -68,3 +68,24 @@
 
     return session->setRepeatingRequest(cbs, numRequests, requests, captureSequenceId);
 }
+
+template <class CallbackType>
+camera_status_t startStreamingTemplate(ACameraCaptureSession* session,
+    /*optional*/CallbackType* callbacks,
+    int numOutputWindows, ANativeWindow** windows,
+    /*optional*/int* captureSequenceId) {
+    ATRACE_CALL();
+    if (session == nullptr || windows == nullptr || numOutputWindows < 1) {
+        ALOGE("%s: Error: invalid input: session %p, numOutputWindows %d, windows %p",
+                __FUNCTION__, session, numOutputWindows, windows);
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    if (session->isClosed()) {
+        ALOGE("%s: session %p is already closed", __FUNCTION__, session);
+        if (captureSequenceId) {
+            *captureSequenceId = CAPTURE_SEQUENCE_ID_NONE;
+        }
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+    return session->startStreaming(callbacks, numOutputWindows, windows, captureSequenceId);
+}
diff --git a/camera/ndk/NdkCameraDevice.cpp b/camera/ndk/NdkCameraDevice.cpp
index f2ec573..bc6b87a 100644
--- a/camera/ndk/NdkCameraDevice.cpp
+++ b/camera/ndk/NdkCameraDevice.cpp
@@ -59,6 +59,9 @@
                 __FUNCTION__, device, request);
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
+    if (device->isSharedMode() && !device->isPrimaryClient()) {
+        return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+    }
     switch (templateId) {
         case TEMPLATE_PREVIEW:
         case TEMPLATE_STILL_CAPTURE:
@@ -86,6 +89,9 @@
                 __FUNCTION__, device, request, physicalCameraIdList);
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
+    if (device->isSharedMode() && !device->isPrimaryClient()) {
+        return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+    }
     switch (templateId) {
         case TEMPLATE_PREVIEW:
         case TEMPLATE_STILL_CAPTURE:
diff --git a/camera/ndk/NdkCameraManager.cpp b/camera/ndk/NdkCameraManager.cpp
index 28cc9af..a2c34e3 100644
--- a/camera/ndk/NdkCameraManager.cpp
+++ b/camera/ndk/NdkCameraManager.cpp
@@ -227,6 +227,11 @@
                 __FUNCTION__, mgr, cameraId, callback, device, primaryClient);
         return ACAMERA_ERROR_INVALID_PARAMETER;
     }
+    bool sharedMode;
+    camera_status_t status = mgr->isCameraDeviceSharingSupported(cameraId, &sharedMode);
+    if ((status != ACAMERA_OK) || !sharedMode) {
+         return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+    }
     return mgr->openCamera(cameraId, /*sharedMode*/true, callback, device, primaryClient);
 }
 
diff --git a/camera/ndk/impl/ACameraCaptureSession.cpp b/camera/ndk/impl/ACameraCaptureSession.cpp
index 449c0b4..bda1f40 100644
--- a/camera/ndk/impl/ACameraCaptureSession.cpp
+++ b/camera/ndk/impl/ACameraCaptureSession.cpp
@@ -96,6 +96,9 @@
     camera_status_t ret;
     dev->lockDeviceForSessionOps();
     {
+        if (dev->isSharedMode() && !dev->isPrimaryClient()) {
+            return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+        }
         Mutex::Autolock _l(mSessionLock);
         ret = dev->stopRepeatingLocked();
     }
@@ -103,6 +106,27 @@
     return ret;
 }
 
+camera_status_t ACameraCaptureSession::stopStreaming() {
+#ifdef __ANDROID_VNDK__
+    std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
+    sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
+    if (dev == nullptr) {
+        ALOGE("Error: Device associated with session %p has been closed!", this);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+
+    camera_status_t ret;
+    dev->lockDeviceForSessionOps();
+    {
+        Mutex::Autolock _l(mSessionLock);
+        ret = dev->stopStreamingLocked();
+    }
+    dev->unlockDevice();
+    return ret;
+}
+
 camera_status_t
 ACameraCaptureSession::abortCaptures() {
 #ifdef __ANDROID_VNDK__
@@ -118,6 +142,9 @@
     camera_status_t ret;
     dev->lockDeviceForSessionOps();
     {
+        if (dev->isSharedMode() && !dev->isPrimaryClient()) {
+            return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+        }
         Mutex::Autolock _l(mSessionLock);
         ret = dev->flushLocked(this);
     }
@@ -139,6 +166,9 @@
     camera_status_t ret;
     dev->lockDeviceForSessionOps();
     {
+        if (dev->isSharedMode()) {
+            return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+        }
         Mutex::Autolock _l(mSessionLock);
         ret = dev->updateOutputConfigurationLocked(output);
     }
@@ -160,6 +190,9 @@
     camera_status_t ret;
     dev->lockDeviceForSessionOps();
     {
+        if (dev->isSharedMode()) {
+            return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+        }
         Mutex::Autolock _l(mSessionLock);
         ret = dev->prepareLocked(window);
     }
diff --git a/camera/ndk/impl/ACameraCaptureSession.h b/camera/ndk/impl/ACameraCaptureSession.h
index 0d7a2c1..eb13b96 100644
--- a/camera/ndk/impl/ACameraCaptureSession.h
+++ b/camera/ndk/impl/ACameraCaptureSession.h
@@ -150,6 +150,12 @@
 
     ACameraDevice* getDevice();
 
+    template<class T>
+    camera_status_t startStreaming(/*optional*/T* callbacks,
+            int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId);
+
+    camera_status_t stopStreaming();
+
   private:
     friend class android::acam::CameraDevice;
 
diff --git a/camera/ndk/impl/ACameraCaptureSession.inc b/camera/ndk/impl/ACameraCaptureSession.inc
index da535f8..695eb37 100644
--- a/camera/ndk/impl/ACameraCaptureSession.inc
+++ b/camera/ndk/impl/ACameraCaptureSession.inc
@@ -42,6 +42,9 @@
     camera_status_t ret;
     dev->lockDeviceForSessionOps();
     {
+        if (dev->isSharedMode() && !dev->isPrimaryClient()) {
+            return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+        }
         Mutex::Autolock _l(mSessionLock);
         ret = dev->setRepeatingRequestsLocked(
                 this, cbs, numRequests, requests, captureSequenceId);
@@ -67,9 +70,37 @@
     camera_status_t ret;
     dev->lockDeviceForSessionOps();
     {
+        if (dev->isSharedMode() && !dev->isPrimaryClient()) {
+            return ACAMERA_ERROR_UNSUPPORTED_OPERATION;
+        }
         Mutex::Autolock _l(mSessionLock);
         ret = dev->captureLocked(this, cbs, numRequests, requests, captureSequenceId);
     }
     dev->unlockDevice();
     return ret;
 }
+
+template <class T>
+camera_status_t ACameraCaptureSession::startStreaming(
+        /*optional*/T* callbacks, int numOutputWindows, ANativeWindow** windows,
+	/*optional*/int* captureSequenceId)  {
+#ifdef __ANDROID_VNDK__
+    std::shared_ptr<acam::CameraDevice> dev = getDevicePtr();
+#else
+    sp<acam::CameraDevice> dev = getDeviceSp();
+#endif
+    if (dev == nullptr) {
+        ALOGE("Error: Device associated with session %p has been closed!", this);
+        return ACAMERA_ERROR_SESSION_CLOSED;
+    }
+
+    camera_status_t ret;
+    dev->lockDeviceForSessionOps();
+    {
+        Mutex::Autolock _l(mSessionLock);
+        ret = dev->startStreamingLocked(this, callbacks, numOutputWindows, windows,
+                captureSequenceId);
+    }
+    dev->unlockDevice();
+    return ret;
+}
diff --git a/camera/ndk/impl/ACameraDevice.cpp b/camera/ndk/impl/ACameraDevice.cpp
index 4d21467..704dfc1 100644
--- a/camera/ndk/impl/ACameraDevice.cpp
+++ b/camera/ndk/impl/ACameraDevice.cpp
@@ -272,6 +272,28 @@
     }
 }
 
+camera_status_t CameraDevice::stopStreamingLocked() {
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret);
+        return ret;
+    }
+    ret = stopRepeatingLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("%s: error when trying to stop streaming %d", __FUNCTION__, ret);
+        return ret;
+    }
+    for (auto& outputTarget : mPreviewRequestOutputs) {
+        ACameraOutputTarget_free(outputTarget);
+    }
+    mPreviewRequestOutputs.clear();
+    if (mPreviewRequest) {
+        ACaptureRequest_free(mPreviewRequest);
+        mPreviewRequest = nullptr;
+    }
+    return ACAMERA_OK;
+}
+
 camera_status_t CameraDevice::updateOutputConfigurationLocked(ACaptureSessionOutput *output) {
     camera_status_t ret = checkCameraClosedOrErrorLocked();
     if (ret != ACAMERA_OK) {
@@ -715,10 +737,14 @@
         return ret;
     }
 
-    ret = waitUntilIdleLocked();
-    if (ret != ACAMERA_OK) {
-        ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
-        return ret;
+    // If device is opened in shared mode, there can be multiple clients accessing the
+    // camera device. So do not wait for idle if the device is opened in shared mode.
+    if ((!flags::camera_multi_client()) || (!mSharedMode)) {
+        ret = waitUntilIdleLocked();
+        if (ret != ACAMERA_OK) {
+            ALOGE("Camera device %s wait until idle failed, ret %d", getId(), ret);
+            return ret;
+        }
     }
 
     // Send onReady to previous session
diff --git a/camera/ndk/impl/ACameraDevice.h b/camera/ndk/impl/ACameraDevice.h
index ea7d9b6..067923c 100644
--- a/camera/ndk/impl/ACameraDevice.h
+++ b/camera/ndk/impl/ACameraDevice.h
@@ -127,6 +127,7 @@
 
     void setPrimaryClient(bool isPrimary) {mIsPrimaryClient = isPrimary;};
     bool isPrimaryClient() {return mIsPrimaryClient;};
+    bool isSharedMode() {return mSharedMode;};
 
   private:
     friend ACameraCaptureSession;
@@ -143,6 +144,15 @@
 
     camera_status_t waitUntilIdleLocked();
 
+    camera_status_t stopStreamingLocked();
+
+    template<class T>
+    camera_status_t startStreamingLocked(ACameraCaptureSession* session,
+            /*optional*/T* callbacks,
+            int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId);
+
+    ACaptureRequest* mPreviewRequest = nullptr;
+    std::vector<ACameraOutputTarget*> mPreviewRequestOutputs;
 
     template<class T>
     camera_status_t captureLocked(sp<ACameraCaptureSession> session,
@@ -476,11 +486,15 @@
         mDevice->setPrimaryClient(isPrimary);
     }
 
-    inline bool isPrimaryClient() {
+    inline bool isPrimaryClient() const {
         return mDevice->isPrimaryClient();
     }
 
-  private:
+    inline bool isSharedMode() const{
+        return mDevice->isSharedMode();
+    }
+
+ private:
     android::sp<android::acam::CameraDevice> mDevice;
 };
 
diff --git a/camera/ndk/impl/ACameraDevice.inc b/camera/ndk/impl/ACameraDevice.inc
index 1fc5352..7e70d39 100644
--- a/camera/ndk/impl/ACameraDevice.inc
+++ b/camera/ndk/impl/ACameraDevice.inc
@@ -126,5 +126,102 @@
     return ACAMERA_OK;
 }
 
+template<class T>
+camera_status_t CameraDevice::startStreamingLocked(ACameraCaptureSession* session,
+        /*optional*/T* callbacks, int numOutputWindows,
+        ANativeWindow** windows, /*optional*/int* captureSequenceId) {
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret);
+        return ret;
+    }
+    CameraMetadata rawPreviewRequest;
+    binder::Status remoteRet = mRemote->createDefaultRequest(TEMPLATE_PREVIEW, &rawPreviewRequest);
+    if (!remoteRet.isOk()) {
+        ALOGE("%s: Create capture request failed: %s", __FUNCTION__, remoteRet.toString8().c_str());
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+    // ToDo: Check if the memory allocation can be freed automatically using either default_delete
+    // or ScopedAResource.
+    mPreviewRequest = new ACaptureRequest();
+    mPreviewRequest->settings = new ACameraMetadata(rawPreviewRequest.release(),
+            ACameraMetadata::ACM_REQUEST);
+    mPreviewRequest->targets  = new ACameraOutputTargets();
+    for (int i = 0; i < numOutputWindows ; i++) {
+        ACameraOutputTarget* outputTarget = nullptr;
+        ret = ACameraOutputTarget_create(windows[i], &outputTarget);
+        if (ret != ACAMERA_OK) {
+            ALOGE("%s: error while ACameraOutputTarget_create %d", __FUNCTION__, ret);
+            return ret;
+        }
+        ret = ACaptureRequest_addTarget(mPreviewRequest, outputTarget);
+        if (ret != ACAMERA_OK) {
+            ALOGE("%s: error while ACaptureRequest_addTarget %d", __FUNCTION__, ret);
+            return ret;
+        }
+        mPreviewRequestOutputs.push_back(outputTarget);
+    }
+
+    sp<CaptureRequest> req;
+    ret = allocateCaptureRequest(mPreviewRequest, req);
+    if (ret != ACAMERA_OK) {
+        ALOGE("Convert capture request to internal format failure! ret %d", ret);
+        return ret;
+    }
+    if (req->mSurfaceList.empty()) {
+        ALOGE("Capture request without output target cannot be submitted!");
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+
+    // In shared session mode, if there are other active clients streaming then
+    // stoprepeating does not actually send request to HAL to cancel the request.
+    // Cameraservice will use this call to remove this client surfaces provided in its
+    // previous streaming request. If this is the only client for the shared camera device
+    // then camerservice will ask HAL to cancel the previous repeating request.
+    ret = stopRepeatingLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+        return ret;
+    }
+
+    hardware::camera2::utils::SubmitInfo info;
+    std::vector<int> streamIds(req->mStreamIdxList.begin(), req->mStreamIdxList.end());
+    std::vector<int> surfaceIds(req->mSurfaceIdxList.begin(), req->mSurfaceIdxList.end());
+    remoteRet = mRemote->startStreaming(streamIds, surfaceIds, &info);
+    int sequenceId = info.mRequestId;
+    int64_t lastFrameNumber = info.mLastFrameNumber;
+    if (sequenceId < 0) {
+        ALOGE("Camera %s start streaming remote failure: ret %d", getId(), sequenceId);
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+
+    Vector<sp<CaptureRequest> > requestsV;
+    requestsV.push_back(req);
+    CallbackHolder cbHolder(session, requestsV, true, callbacks);
+    mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+
+    // stopRepeating above should have cleanup repeating sequence id
+    if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+        setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+        return ACAMERA_ERROR_CAMERA_DEVICE;
+    }
+    mRepeatingSequenceId = sequenceId;
+
+    if (mIdle) {
+        sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+        msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+        msg->setObject(kSessionSpKey, session);
+        msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+        postSessionMsgAndCleanup(msg);
+    }
+    mIdle = false;
+    mBusySession = session;
+
+    if (captureSequenceId) {
+        *captureSequenceId = sequenceId;
+    }
+    return ACAMERA_OK;
+}
+
 } // namespace acam
 } // namespace android
diff --git a/camera/ndk/include/camera/NdkCameraCaptureSession.h b/camera/ndk/include/camera/NdkCameraCaptureSession.h
index 06e1d34..c2aae1c 100644
--- a/camera/ndk/include/camera/NdkCameraCaptureSession.h
+++ b/camera/ndk/include/camera/NdkCameraCaptureSession.h
@@ -1242,8 +1242,7 @@
  *         </ul>
  */
 camera_status_t ACameraCaptureSessionShared_stopStreaming(
-    ACameraCaptureSession *sharedSession
-)  __INTRODUCED_IN(36);
+    ACameraCaptureSession* sharedSession)  __INTRODUCED_IN(36);
 __END_DECLS
 
 #endif /* _NDK_CAMERA_CAPTURE_SESSION_H */
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
index d3a8e0d..b65aedf 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.cpp
@@ -562,6 +562,28 @@
     return ACAMERA_OK;
 }
 
+camera_status_t CameraDevice::stopStreamingLocked() {
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret);
+        return ret;
+    }
+    ret = stopRepeatingLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("%s: error when trying to stop streaming %d", __FUNCTION__, ret);
+        return ret;
+    }
+    for (auto& outputTarget : mPreviewRequestOutputs) {
+        ACameraOutputTarget_free(outputTarget);
+    }
+    mPreviewRequestOutputs.clear();
+    if (mPreviewRequest) {
+        ACaptureRequest_free(mPreviewRequest);
+        mPreviewRequest = nullptr;
+    }
+    return ACAMERA_OK;
+}
+
 camera_status_t CameraDevice::flushLocked(ACameraCaptureSession* session) {
     camera_status_t ret = checkCameraClosedOrErrorLocked();
     if (ret != ACAMERA_OK) {
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDevice.h b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
index 6ba30bb..5d03e95 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDevice.h
+++ b/camera/ndk/ndk_vendor/impl/ACameraDevice.h
@@ -157,6 +157,7 @@
     void stopLooperAndDisconnect();
     void setPrimaryClient(bool isPrimary) {mIsPrimaryClient = isPrimary;};
     bool isPrimaryClient() {return mIsPrimaryClient;};
+    bool isSharedMode() {return mSharedMode;};
 
   private:
     friend ACameraCaptureSession;
@@ -195,6 +196,13 @@
             /*out*/int* captureSequenceId,
             bool isRepeating);
 
+    camera_status_t stopStreamingLocked();
+
+    template<class T>
+    camera_status_t startStreamingLocked(ACameraCaptureSession* session,
+            /*optional*/T* callbacks,
+            int numOutputWindows, ANativeWindow** windows, /*optional*/int* captureSequenceId);
+
     void addRequestSettingsMetadata(ACaptureRequest *aCaptureRequest, sp<CaptureRequest> &req);
 
     camera_status_t updateOutputConfigurationLocked(ACaptureSessionOutput *output);
@@ -237,6 +245,8 @@
     ACameraDevice* mWrapper;
     bool mSharedMode;
     bool mIsPrimaryClient;
+    ACaptureRequest* mPreviewRequest = nullptr;
+    std::vector<ACameraOutputTarget*> mPreviewRequestOutputs;
 
     // stream id -> pair of (ACameraWindowType* from application, OutputConfiguration used for
     // camera service)
@@ -490,9 +500,12 @@
     inline void setPrimaryClient(bool isPrimary) {
         mDevice->setPrimaryClient(isPrimary);
     }
-    inline bool isPrimaryClient() {
+    inline bool isPrimaryClient() const {
         return mDevice->isPrimaryClient();
     }
+    inline bool isSharedMode() const {
+        return mDevice->isSharedMode();
+    }
 
   private:
     std::shared_ptr<android::acam::CameraDevice> mDevice;
diff --git a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
index 1e724eb..1f568d2 100644
--- a/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
+++ b/camera/ndk/ndk_vendor/impl/ACameraDeviceVendor.inc
@@ -147,5 +147,131 @@
     return ACAMERA_OK;
 }
 
+template<class T>
+camera_status_t CameraDevice::startStreamingLocked(ACameraCaptureSession* session,
+        /*optional*/T* callbacks, int numOutputWindows,
+        ANativeWindow** windows, /*optional*/int* captureSequenceId) {
+    camera_status_t ret = checkCameraClosedOrErrorLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("%s: camera is in closed or error state %d", __FUNCTION__, ret);
+        return ret;
+    }
+    utils::AidlCameraMetadata aidlMetadata;
+    ndk::ScopedAStatus remoteRet = mRemote->createDefaultRequest(utils::TemplateId::PREVIEW,
+            &aidlMetadata);
+    if (!remoteRet.isOk()) {
+        if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+            Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+            ALOGE("%s: submitRequestList call failed: %s",
+                  __FUNCTION__, toString(errStatus).c_str());
+            return utils::convertFromAidl(errStatus);
+        } else {
+            ALOGE("%s: Transaction error for submitRequestList call: %d", __FUNCTION__,
+                  remoteRet.getExceptionCode());
+            return ACAMERA_ERROR_UNKNOWN;
+        }
+    }
+    camera_metadata_t* rawPreviewRequest;
+    utils::cloneFromAidl(aidlMetadata, &rawPreviewRequest);
+    // ToDo: Check if the memory allocation can be freed automatically using either default_delete
+    // or ScopedAResource.
+    mPreviewRequest = new ACaptureRequest();
+    mPreviewRequest->settings = new ACameraMetadata(rawPreviewRequest,
+            ACameraMetadata::ACM_REQUEST);
+    mPreviewRequest->targets  = new ACameraOutputTargets();
+    for (int i = 0; i < numOutputWindows ; i++) {
+        ACameraOutputTarget* outputTarget = nullptr;
+        ret = ACameraOutputTarget_create(windows[i], &outputTarget);
+        if (ret != ACAMERA_OK) {
+            ALOGE("%s: error while ACameraOutputTarget_create %d", __FUNCTION__, ret);
+            return ret;
+        }
+        ret = ACaptureRequest_addTarget(mPreviewRequest, outputTarget);
+        if (ret != ACAMERA_OK) {
+            ALOGE("%s: error while ACaptureRequest_addTarget %d", __FUNCTION__, ret);
+            return ret;
+        }
+        mPreviewRequestOutputs.push_back(outputTarget);
+    }
+
+    std::vector<sp<CaptureRequest>> requestsV;
+    sp<CaptureRequest> req;
+    ret = allocateCaptureRequestLocked(mPreviewRequest, req);
+    // We need to call this method since after submitRequestList is called,
+    // the request metadata queue might have removed the capture request
+    // metadata. Therefore we simply add the metadata to its wrapper class,
+    // so that it can be retrieved later.
+    addRequestSettingsMetadata(mPreviewRequest, req);
+    if (ret != ACAMERA_OK) {
+        ALOGE("Convert capture request to internal format failure! ret %d", ret);
+        return ret;
+    }
+    if (req->mCaptureRequest.streamAndWindowIds.size() == 0) {
+        ALOGE("Capture request without output target cannot be submitted!");
+        return ACAMERA_ERROR_INVALID_PARAMETER;
+    }
+    requestsV.push_back(req);
+    // In shared session mode, if there are other active clients streaming then
+    // stoprepeating does not actually send request to HAL to cancel the request.
+    // Cameraservice will use this call to remove this client surfaces provided in its
+    // previous streaming request. If this is the only client for the shared camera device
+    // then camerservice will ask HAL to cancel the previous repeating request.
+    ret = stopRepeatingLocked();
+    if (ret != ACAMERA_OK) {
+        ALOGE("Camera %s stop repeating failed! ret %d", getId(), ret);
+        return ret;
+    }
+    SubmitInfo info;
+    std::vector<int> streamIds;
+    std::vector<int> surfaceIds;
+    for (const auto& streamAndWindowId : req->mCaptureRequest.streamAndWindowIds) {
+        streamIds.push_back(streamAndWindowId.streamId);
+        surfaceIds.push_back(streamAndWindowId.windowId);
+    }
+    remoteRet = mRemote->startStreaming(streamIds, surfaceIds, &info);
+    if (!remoteRet.isOk()) {
+        if (remoteRet.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+            Status errStatus = static_cast<Status>(remoteRet.getServiceSpecificError());
+            ALOGE("%s: startStreaming call failed: %s",
+                  __FUNCTION__, toString(errStatus).c_str());
+            return utils::convertFromAidl(errStatus);
+        } else {
+            ALOGE("%s: Transaction error for startStreaming call: %d", __FUNCTION__,
+                  remoteRet.getExceptionCode());
+            return ACAMERA_ERROR_UNKNOWN;
+        }
+    }
+
+    int32_t sequenceId = info.requestId;
+    int64_t lastFrameNumber = info.lastFrameNumber;
+    if (sequenceId < 0) {
+        ALOGE("Camera %s submit request remote failure: ret %d", getId(), sequenceId);
+        return ACAMERA_ERROR_UNKNOWN;
+    }
+    CallbackHolder cbHolder(session, requestsV, true, callbacks);
+    mSequenceCallbackMap.insert(std::make_pair(sequenceId, cbHolder));
+    // stopRepeating above should have cleanup repeating sequence id
+    if (mRepeatingSequenceId != REQUEST_ID_NONE) {
+        setCameraDeviceErrorLocked(ACAMERA_ERROR_CAMERA_DEVICE);
+        return ACAMERA_ERROR_CAMERA_DEVICE;
+    }
+    mRepeatingSequenceId = sequenceId;
+
+    if (mIdle) {
+        sp<AMessage> msg = new AMessage(kWhatSessionStateCb, mHandler);
+        msg->setPointer(kContextKey, session->mUserSessionCallback.context);
+        msg->setObject(kSessionSpKey, session);
+        msg->setPointer(kCallbackFpKey, (void*) session->mUserSessionCallback.onActive);
+        postSessionMsgAndCleanup(msg);
+    }
+    mIdle = false;
+    mBusySession = session;
+
+    if (captureSequenceId) {
+        *captureSequenceId = sequenceId;
+    }
+    return ACAMERA_OK;
+}
+
 } // namespace acam
 } // namespace android