summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEmilian Peev <epeev@google.com>2021-04-28 15:40:19 -0700
committerEmilian Peev <epeev@google.com>2021-06-24 15:33:35 -0700
commit876e6afd6ca9f34f89092edfe5b785a0d1ab3d7e (patch)
treefab4dfc4b013e32e1df4e0cb0164bf97fb535f79
parentc46c9e644f079150ffb89e388aac89cae841c765 (diff)
Camera: Disallow concurrent extension sessions
Support for concurrent extension processing sessions is not yet mandated. To avoid inconsistent behavior across devices, explicitly document and disallow concurrent extension sessions at the framework level. Bug: 187341271 Test: Manual using test application, Camera CTS Change-Id: Ibff194c58bbb37e884c27151a2a27fb21e3db928
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionCharacteristics.java36
-rw-r--r--core/java/android/hardware/camera2/CameraExtensionSession.java5
-rw-r--r--core/java/android/hardware/camera2/CameraManager.java3
-rw-r--r--core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl3
-rw-r--r--core/java/android/hardware/camera2/extension/IInitializeSessionCallback.aidl23
-rw-r--r--core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java37
-rw-r--r--core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java77
-rw-r--r--packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java91
8 files changed, 249 insertions, 26 deletions
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 5b259f71feda..5cfba3d945cd 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -25,6 +25,7 @@ import android.graphics.ImageFormat;
import android.hardware.camera2.extension.IAdvancedExtenderImpl;
import android.hardware.camera2.extension.ICameraExtensionsProxyService;
import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
+import android.hardware.camera2.extension.IInitializeSessionCallback;
import android.hardware.camera2.extension.IPreviewExtenderImpl;
import android.hardware.camera2.extension.LatencyRange;
import android.hardware.camera2.extension.SizeList;
@@ -357,6 +358,27 @@ public final class CameraExtensionCharacteristics {
}
}
+ public void initializeSession(IInitializeSessionCallback cb) throws RemoteException {
+ synchronized (mLock) {
+ if (mProxy != null) {
+ mProxy.initializeSession(cb);
+ }
+ }
+ }
+
+ public void releaseSession() {
+ synchronized (mLock) {
+ if (mProxy != null) {
+ try {
+ mProxy.releaseSession();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to release session! Extension service does"
+ + " not respond!");
+ }
+ }
+ }
+ }
+
public boolean areAdvancedExtensionsSupported() {
return mSupportsAdvancedExtensions;
}
@@ -412,6 +434,20 @@ public final class CameraExtensionCharacteristics {
/**
* @hide
*/
+ public static void initializeSession(IInitializeSessionCallback cb) throws RemoteException {
+ CameraExtensionManagerGlobal.get().initializeSession(cb);
+ }
+
+ /**
+ * @hide
+ */
+ public static void releaseSession() {
+ CameraExtensionManagerGlobal.get().releaseSession();
+ }
+
+ /**
+ * @hide
+ */
public static boolean areAdvancedExtensionsSupported() {
return CameraExtensionManagerGlobal.get().areAdvancedExtensionsSupported();
}
diff --git a/core/java/android/hardware/camera2/CameraExtensionSession.java b/core/java/android/hardware/camera2/CameraExtensionSession.java
index e1b817768461..5892f682dd49 100644
--- a/core/java/android/hardware/camera2/CameraExtensionSession.java
+++ b/core/java/android/hardware/camera2/CameraExtensionSession.java
@@ -195,8 +195,9 @@ public abstract class CameraExtensionSession implements AutoCloseable {
* This method is called if the session cannot be configured as requested.
*
* <p>This can happen if the set of requested outputs contains unsupported sizes,
- * too many outputs are requested at once or the camera device encounters an
- * unrecoverable error during configuration.</p>
+ * too many outputs are requested at once or when trying to initialize multiple
+ * concurrent extension sessions from two (or more) separate camera devices
+ * or the camera device encounters an unrecoverable error during configuration.</p>
*
* <p>The session is considered to be closed, and all methods called on it after this
* callback is invoked will throw an IllegalStateException.</p>
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index a1c8d29566be..5833b3dbef86 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -162,6 +162,9 @@ public final class CameraManager {
* <p>The set of combinations may include camera devices that may be in use by other camera API
* clients.</p>
*
+ * <p>Concurrent camera extension sessions {@link CameraExtensionSession} are not currently
+ * supported.</p>
+ *
* <p>The set of combinations doesn't contain physical cameras that can only be used as
* part of a logical multi-camera device.</p>
*
diff --git a/core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl b/core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl
index bc29e9a481ae..b52c650086f4 100644
--- a/core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl
+++ b/core/java/android/hardware/camera2/extension/ICameraExtensionsProxyService.aidl
@@ -18,6 +18,7 @@ package android.hardware.camera2.extension;
import android.hardware.camera2.extension.IAdvancedExtenderImpl;
import android.hardware.camera2.extension.IPreviewExtenderImpl;
import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
+import android.hardware.camera2.extension.IInitializeSessionCallback;
/** @hide */
interface ICameraExtensionsProxyService
@@ -25,6 +26,8 @@ interface ICameraExtensionsProxyService
long registerClient();
void unregisterClient(long clientId);
boolean advancedExtensionsSupported();
+ void initializeSession(in IInitializeSessionCallback cb);
+ void releaseSession();
@nullable IPreviewExtenderImpl initializePreviewExtension(int extensionType);
@nullable IImageCaptureExtenderImpl initializeImageExtension(int extensionType);
@nullable IAdvancedExtenderImpl initializeAdvancedExtension(int extensionType);
diff --git a/core/java/android/hardware/camera2/extension/IInitializeSessionCallback.aidl b/core/java/android/hardware/camera2/extension/IInitializeSessionCallback.aidl
new file mode 100644
index 000000000000..1747760d7d8c
--- /dev/null
+++ b/core/java/android/hardware/camera2/extension/IInitializeSessionCallback.aidl
@@ -0,0 +1,23 @@
+/**
+ * Copyright (c) 2021, 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.
+ */
+package android.hardware.camera2.extension;
+
+/** @hide */
+interface IInitializeSessionCallback
+{
+ void onSuccess();
+ void onFailure();
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index 5cf50a25de78..bfc1f2765c3b 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -35,9 +35,11 @@ import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.extension.CameraOutputConfig;
import android.hardware.camera2.extension.CameraSessionConfig;
+import android.hardware.camera2.extension.CaptureStageImpl;
import android.hardware.camera2.extension.IAdvancedExtenderImpl;
import android.hardware.camera2.extension.ICaptureCallback;
import android.hardware.camera2.extension.IImageProcessorImpl;
+import android.hardware.camera2.extension.IInitializeSessionCallback;
import android.hardware.camera2.extension.IRequestCallback;
import android.hardware.camera2.extension.IRequestProcessorImpl;
import android.hardware.camera2.extension.ISessionProcessorImpl;
@@ -89,6 +91,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
private Surface mClientCaptureSurface;
private CameraCaptureSession mCaptureSession = null;
private ISessionProcessorImpl mSessionProcessor = null;
+ private final InitializeSessionHandler mInitializeHandler;
private boolean mInitialized;
@@ -181,6 +184,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mInitialized = false;
+ mInitializeHandler = new InitializeSessionHandler();
}
/**
@@ -444,7 +448,6 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
public void release() {
synchronized (mInterfaceLock) {
- mInitialized = false;
mHandlerThread.quitSafely();
if (mSessionProcessor != null) {
@@ -459,7 +462,11 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
if (mExtensionClientId >= 0) {
CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
+ if (mInitialized) {
+ CameraExtensionCharacteristics.releaseSession();
+ }
}
+ mInitialized = false;
for (ImageReader reader : mReaderMap.values()) {
reader.close();
@@ -512,17 +519,32 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
- boolean status = true;
synchronized (mInterfaceLock) {
mCaptureSession = session;
try {
+ CameraExtensionCharacteristics.initializeSession(mInitializeHandler);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to initialize session! Extension service does"
+ + " not respond!");
+ notifyConfigurationFailure();
+ }
+ }
+ }
+ }
+
+ private class InitializeSessionHandler extends IInitializeSessionCallback.Stub {
+ @Override
+ public void onSuccess() {
+ boolean status = true;
+ synchronized (mInterfaceLock) {
+ try {
mSessionProcessor.onCaptureSessionStart(mRequestProcessor);
mInitialized = true;
} catch (RemoteException e) {
Log.e(TAG, "Failed to start capture session,"
+ " extension service does not respond!");
status = false;
- session.close();
+ mCaptureSession.close();
}
}
@@ -538,6 +560,15 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
notifyConfigurationFailure();
}
}
+
+ @Override
+ public void onFailure() {
+ mCaptureSession.close();
+ Log.e(TAG, "Failed to initialize proxy service session!"
+ + " This can happen when trying to configure multiple "
+ + "concurrent extension sessions!");
+ notifyConfigurationFailure();
+ }
}
private final class RequestCallbackHandler extends ICaptureCallback.Stub {
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 4bcc4942d8a0..537b894d9a6a 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -34,6 +34,7 @@ import android.hardware.camera2.extension.CaptureBundle;
import android.hardware.camera2.extension.CaptureStageImpl;
import android.hardware.camera2.extension.ICaptureProcessorImpl;
import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
+import android.hardware.camera2.extension.IInitializeSessionCallback;
import android.hardware.camera2.extension.IPreviewExtenderImpl;
import android.hardware.camera2.extension.IRequestUpdateProcessorImpl;
import android.hardware.camera2.extension.ParcelImage;
@@ -48,6 +49,8 @@ import android.media.ImageWriter;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.IInterface;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.annotation.NonNull;
@@ -80,6 +83,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
private final HandlerThread mHandlerThread;
private final StateCallback mCallbacks;
private final List<Size> mSupportedPreviewSizes;
+ private final InitializeSessionHandler mInitializeHandler;
private CameraCaptureSession mCaptureSession = null;
private Surface mCameraRepeatingSurface, mClientRepeatingRequestSurface;
@@ -216,6 +220,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mInitialized = false;
+ mInitializeHandler = new InitializeSessionHandler();
}
private void initializeRepeatingRequestPipeline() throws RemoteException {
@@ -621,7 +626,6 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
public void release() {
synchronized (mInterfaceLock) {
mInternalRepeatingRequestEnabled = false;
- mInitialized = false;
mHandlerThread.quitSafely();
try {
@@ -634,7 +638,11 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
if (mExtensionClientId >= 0) {
CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
+ if (mInitialized) {
+ CameraExtensionCharacteristics.releaseSession();
+ }
}
+ mInitialized = false;
if (mRepeatingRequestImageCallback != null) {
mRepeatingRequestImageCallback.close();
@@ -739,36 +747,63 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
- boolean status = true;
synchronized (mInterfaceLock) {
mCaptureSession = session;
+ try {
+ CameraExtensionCharacteristics.initializeSession(mInitializeHandler);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to initialize session! Extension service does"
+ + " not respond!");
+ notifyConfigurationFailure();
+ }
+ }
+ }
+ }
- ArrayList<CaptureStageImpl> initialRequestList = compileInitialRequestList();
- if (!initialRequestList.isEmpty()) {
- try {
- setInitialCaptureRequest(initialRequestList,
- new InitialRequestHandler(mRepeatingRequestImageCallback));
- } catch (CameraAccessException e) {
- Log.e(TAG, "Failed to initialize the initial capture request!");
- status = false;
- }
- } else {
- try {
- setRepeatingRequest(mPreviewExtender.getCaptureStage(),
- new RepeatingRequestHandler(null, null, null,
- mRepeatingRequestImageCallback));
- } catch (CameraAccessException | RemoteException e) {
- Log.e(TAG, "Failed to initialize internal repeating request!");
- status = false;
- }
-
+ private class InitializeSessionHandler extends IInitializeSessionCallback.Stub {
+ @Override
+ public void onSuccess() {
+ boolean status = true;
+ ArrayList<CaptureStageImpl> initialRequestList =
+ compileInitialRequestList();
+ if (!initialRequestList.isEmpty()) {
+ try {
+ setInitialCaptureRequest(initialRequestList,
+ new InitialRequestHandler(
+ mRepeatingRequestImageCallback));
+ } catch (CameraAccessException e) {
+ Log.e(TAG,
+ "Failed to initialize the initial capture "
+ + "request!");
+ status = false;
}
+ } else {
+ try {
+ setRepeatingRequest(mPreviewExtender.getCaptureStage(),
+ new RepeatingRequestHandler(null, null, null,
+ mRepeatingRequestImageCallback));
+ } catch (CameraAccessException | RemoteException e) {
+ Log.e(TAG,
+ "Failed to initialize internal repeating "
+ + "request!");
+ status = false;
+ }
+
}
if (!status) {
notifyConfigurationFailure();
}
}
+
+ @Override
+ public void onFailure() {
+ mCaptureSession.close();
+ Log.e(TAG, "Failed to initialize proxy service session!"
+ + " This can happen when trying to configure multiple "
+ + "concurrent extension sessions!");
+ notifyConfigurationFailure();
+ }
}
private class BurstRequestHandler extends CameraCaptureSession.CaptureCallback {
diff --git a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
index 69874f8a305a..ab3643c2a911 100644
--- a/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
+++ b/packages/services/CameraExtensionsProxy/src/com/android/cameraextensions/CameraExtensionsProxyService.java
@@ -18,6 +18,7 @@ package com.android.cameraextensions;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.graphics.GraphicBuffer;
import android.graphics.Rect;
import android.hardware.camera2.CameraAccessException;
@@ -42,6 +43,7 @@ import android.hardware.camera2.extension.IRequestProcessorImpl;
import android.hardware.camera2.extension.IRequestUpdateProcessorImpl;
import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
import android.hardware.camera2.extension.IImageProcessorImpl;
+import android.hardware.camera2.extension.IInitializeSessionCallback;
import android.hardware.camera2.extension.ISessionProcessorImpl;
import android.hardware.camera2.extension.LatencyRange;
import android.hardware.camera2.extension.OutputConfigId;
@@ -57,6 +59,7 @@ import android.hardware.HardwareBuffer;
import android.hardware.camera2.impl.PhysicalCaptureResultInfo;
import android.media.Image;
import android.media.ImageReader;
+import android.os.Binder;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerExecutor;
@@ -176,6 +179,7 @@ public class CameraExtensionsProxyService extends Service {
private long mCurrentClientCount = 0;
private ArraySet<Long> mActiveClients = new ArraySet<>();
+ private IInitializeSessionCallback mInitializeCb = null;
// Singleton instance
private static final CameraExtensionManagerGlobal GLOBAL_CAMERA_MANAGER =
@@ -328,6 +332,40 @@ public class CameraExtensionsProxyService extends Service {
}
}
}
+
+ private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mInitializeCb = null;
+ }
+ }
+ };
+
+ public boolean initializeSession(IInitializeSessionCallback cb) {
+ synchronized (mLock) {
+ if (mInitializeCb == null) {
+ mInitializeCb = cb;
+ try {
+ mInitializeCb.asBinder().linkToDeath(mDeathRecipient, 0);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ } else {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ public void releaseSession() {
+ synchronized (mLock) {
+ if (mInitializeCb != null) {
+ mInitializeCb.asBinder().unlinkToDeath(mDeathRecipient, 0);
+ mInitializeCb = null;
+ }
+ }
+ }
}
/**
@@ -353,6 +391,26 @@ public class CameraExtensionsProxyService extends Service {
/**
* @hide
*/
+ public static boolean initializeSession(IInitializeSessionCallback cb) {
+ if (!EXTENSIONS_PRESENT) {
+ return false;
+ }
+ return CameraExtensionManagerGlobal.get().initializeSession(cb);
+ }
+
+ /**
+ * @hide
+ */
+ public static void releaseSession() {
+ if (!EXTENSIONS_PRESENT) {
+ return;
+ }
+ CameraExtensionManagerGlobal.get().releaseSession();
+ }
+
+ /**
+ * @hide
+ */
public static Pair<PreviewExtenderImpl, ImageCaptureExtenderImpl> initializeExtension(
int extensionType) {
switch (extensionType) {
@@ -538,6 +596,39 @@ public class CameraExtensionsProxyService extends Service {
CameraExtensionsProxyService.unregisterClient(clientId);
}
+ private boolean checkCameraPermission() {
+ int allowed = CameraExtensionsProxyService.this.checkPermission(
+ android.Manifest.permission.CAMERA, Binder.getCallingPid(),
+ Binder.getCallingUid());
+ return (PackageManager.PERMISSION_GRANTED == allowed);
+ }
+
+ @Override
+ public void initializeSession(IInitializeSessionCallback cb) {
+ try {
+ if (!checkCameraPermission()) {
+ Log.i(TAG, "Camera permission required for initializing capture session");
+ cb.onFailure();
+ return;
+ }
+
+ if (CameraExtensionsProxyService.initializeSession(cb)) {
+ cb.onSuccess();
+ } else {
+ cb.onFailure();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Client doesn't respond!");
+ }
+ }
+
+ @Override
+ public void releaseSession() {
+ if (checkCameraPermission()) {
+ CameraExtensionsProxyService.releaseSession();
+ }
+ }
+
@Override
public boolean advancedExtensionsSupported() {
return ADVANCED_API_SUPPORTED;