Camera: release extension when extension app crash
When extension use app crashed, extension proxy service does not clean up the SessionProcessorImpl or ExtenderImpl. This could cause the resource leak as all resources allocated is expected to be released from the onDeInit or deInitSession. This patch will attached DeathRecipient to the SessionProcessorImpl and ExtenderImpl. And, it will handle relevant release sequence. Bug: 286198063 Test: Manual test with the extension test app that intentionally crashes Change-Id: I9053bc9a51e65c33309eea78db538dfc9962affc
This commit is contained in:
committed by
Emilian Peev
parent
41fc44e370
commit
b2456b4058
@@ -34,6 +34,7 @@ import android.hardware.camera2.impl.CameraExtensionUtils;
|
||||
import android.hardware.camera2.impl.CameraMetadataNative;
|
||||
import android.hardware.camera2.params.ExtensionSessionConfiguration;
|
||||
import android.hardware.camera2.params.StreamConfigurationMap;
|
||||
import android.os.Binder;
|
||||
import android.os.ConditionVariable;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
@@ -48,7 +49,6 @@ import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -346,28 +346,29 @@ public final class CameraExtensionCharacteristics {
|
||||
}
|
||||
}
|
||||
|
||||
public long registerClient(Context ctx) {
|
||||
public boolean registerClient(Context ctx, IBinder token) {
|
||||
synchronized (mLock) {
|
||||
connectToProxyLocked(ctx);
|
||||
if (mProxy != null) {
|
||||
try {
|
||||
return mProxy.registerClient();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to initialize extension! Extension service does "
|
||||
+ " not respond!");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
if (mProxy == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
return mProxy.registerClient(token);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to initialize extension! Extension service does "
|
||||
+ " not respond!");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterClient(long clientId) {
|
||||
public void unregisterClient(IBinder token) {
|
||||
synchronized (mLock) {
|
||||
if (mProxy != null) {
|
||||
try {
|
||||
mProxy.unregisterClient(clientId);
|
||||
mProxy.unregisterClient(token);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to de-initialize extension! Extension service does"
|
||||
+ " not respond!");
|
||||
@@ -438,15 +439,15 @@ public final class CameraExtensionCharacteristics {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static long registerClient(Context ctx) {
|
||||
return CameraExtensionManagerGlobal.get().registerClient(ctx);
|
||||
public static boolean registerClient(Context ctx, IBinder token) {
|
||||
return CameraExtensionManagerGlobal.get().registerClient(ctx, token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static void unregisterClient(long clientId) {
|
||||
CameraExtensionManagerGlobal.get().unregisterClient(clientId);
|
||||
public static void unregisterClient(IBinder token) {
|
||||
CameraExtensionManagerGlobal.get().unregisterClient(token);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -564,8 +565,9 @@ public final class CameraExtensionCharacteristics {
|
||||
*/
|
||||
public @NonNull List<Integer> getSupportedExtensions() {
|
||||
ArrayList<Integer> ret = new ArrayList<>();
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#getSupportedExtensions:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
return Collections.unmodifiableList(ret);
|
||||
}
|
||||
|
||||
@@ -576,7 +578,7 @@ public final class CameraExtensionCharacteristics {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
|
||||
return Collections.unmodifiableList(ret);
|
||||
@@ -599,8 +601,9 @@ public final class CameraExtensionCharacteristics {
|
||||
* supported device-specific extension
|
||||
*/
|
||||
public boolean isPostviewAvailable(@Extension int extension) {
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#isPostviewAvailable:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
throw new IllegalArgumentException("Unsupported extensions");
|
||||
}
|
||||
|
||||
@@ -623,7 +626,7 @@ public final class CameraExtensionCharacteristics {
|
||||
Log.e(TAG, "Failed to query the extension for postview availability! Extension "
|
||||
+ "service does not respond!");
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -656,9 +659,9 @@ public final class CameraExtensionCharacteristics {
|
||||
@NonNull
|
||||
public List<Size> getPostviewSupportedSizes(@Extension int extension,
|
||||
@NonNull Size captureSize, int format) {
|
||||
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#getPostviewSupportedSizes:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
throw new IllegalArgumentException("Unsupported extensions");
|
||||
}
|
||||
|
||||
@@ -719,7 +722,7 @@ public final class CameraExtensionCharacteristics {
|
||||
+ "service does not respond!");
|
||||
return Collections.emptyList();
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -756,8 +759,9 @@ public final class CameraExtensionCharacteristics {
|
||||
// TODO: Revisit this code once the Extension preview processor output format
|
||||
// ambiguity is resolved in b/169799538.
|
||||
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#getExtensionSupportedSizes:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
throw new IllegalArgumentException("Unsupported extensions");
|
||||
}
|
||||
|
||||
@@ -787,7 +791,7 @@ public final class CameraExtensionCharacteristics {
|
||||
+ " not respond!");
|
||||
return new ArrayList<>();
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -814,8 +818,9 @@ public final class CameraExtensionCharacteristics {
|
||||
public @NonNull
|
||||
List<Size> getExtensionSupportedSizes(@Extension int extension, int format) {
|
||||
try {
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#getExtensionSupportedSizes:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
throw new IllegalArgumentException("Unsupported extensions");
|
||||
}
|
||||
|
||||
@@ -867,7 +872,7 @@ public final class CameraExtensionCharacteristics {
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to query the extension supported sizes! Extension service does"
|
||||
@@ -888,7 +893,6 @@ public final class CameraExtensionCharacteristics {
|
||||
* @param format device-specific extension output format
|
||||
* @return the range of estimated minimal and maximal capture latency in milliseconds
|
||||
* or null if no capture latency info can be provided
|
||||
*
|
||||
* @throws IllegalArgumentException in case of format different from {@link ImageFormat#JPEG} /
|
||||
* {@link ImageFormat#YUV_420_888}; or unsupported extension.
|
||||
*/
|
||||
@@ -903,8 +907,9 @@ public final class CameraExtensionCharacteristics {
|
||||
throw new IllegalArgumentException("Unsupported format: " + format);
|
||||
}
|
||||
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#getEstimatedCaptureLatencyRangeMillis:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
throw new IllegalArgumentException("Unsupported extensions");
|
||||
}
|
||||
|
||||
@@ -952,7 +957,7 @@ public final class CameraExtensionCharacteristics {
|
||||
Log.e(TAG, "Failed to query the extension capture latency! Extension service does"
|
||||
+ " not respond!");
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
|
||||
return null;
|
||||
@@ -968,8 +973,9 @@ public final class CameraExtensionCharacteristics {
|
||||
* @throws IllegalArgumentException in case of an unsupported extension.
|
||||
*/
|
||||
public boolean isCaptureProcessProgressAvailable(@Extension int extension) {
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#isCaptureProcessProgressAvailable:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
throw new IllegalArgumentException("Unsupported extensions");
|
||||
}
|
||||
|
||||
@@ -992,7 +998,7 @@ public final class CameraExtensionCharacteristics {
|
||||
Log.e(TAG, "Failed to query the extension progress callbacks! Extension service does"
|
||||
+ " not respond!");
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -1013,8 +1019,9 @@ public final class CameraExtensionCharacteristics {
|
||||
*/
|
||||
@NonNull
|
||||
public Set<CaptureRequest.Key> getAvailableCaptureRequestKeys(@Extension int extension) {
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#getAvailableCaptureRequestKeys:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
throw new IllegalArgumentException("Unsupported extensions");
|
||||
}
|
||||
|
||||
@@ -1033,10 +1040,11 @@ public final class CameraExtensionCharacteristics {
|
||||
} else {
|
||||
Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
|
||||
initializeExtension(extension);
|
||||
extenders.second.onInit(mCameraId, mCharacteristicsMapNative.get(mCameraId));
|
||||
extenders.second.onInit(token, mCameraId,
|
||||
mCharacteristicsMapNative.get(mCameraId));
|
||||
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
|
||||
captureRequestMeta = extenders.second.getAvailableCaptureRequestKeys();
|
||||
extenders.second.onDeInit();
|
||||
extenders.second.onDeInit(token);
|
||||
}
|
||||
|
||||
if (captureRequestMeta != null) {
|
||||
@@ -1067,7 +1075,7 @@ public final class CameraExtensionCharacteristics {
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("Failed to query the available capture request keys!");
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(ret);
|
||||
@@ -1092,8 +1100,9 @@ public final class CameraExtensionCharacteristics {
|
||||
*/
|
||||
@NonNull
|
||||
public Set<CaptureResult.Key> getAvailableCaptureResultKeys(@Extension int extension) {
|
||||
long clientId = registerClient(mContext);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + "#getAvailableCaptureResultKeys:" + mCameraId);
|
||||
boolean success = registerClient(mContext, token);
|
||||
if (!success) {
|
||||
throw new IllegalArgumentException("Unsupported extensions");
|
||||
}
|
||||
|
||||
@@ -1111,10 +1120,11 @@ public final class CameraExtensionCharacteristics {
|
||||
} else {
|
||||
Pair<IPreviewExtenderImpl, IImageCaptureExtenderImpl> extenders =
|
||||
initializeExtension(extension);
|
||||
extenders.second.onInit(mCameraId, mCharacteristicsMapNative.get(mCameraId));
|
||||
extenders.second.onInit(token, mCameraId,
|
||||
mCharacteristicsMapNative.get(mCameraId));
|
||||
extenders.second.init(mCameraId, mCharacteristicsMapNative.get(mCameraId));
|
||||
captureResultMeta = extenders.second.getAvailableCaptureResultKeys();
|
||||
extenders.second.onDeInit();
|
||||
extenders.second.onDeInit(token);
|
||||
}
|
||||
|
||||
if (captureResultMeta != null) {
|
||||
@@ -1126,7 +1136,7 @@ public final class CameraExtensionCharacteristics {
|
||||
}
|
||||
CameraCharacteristics resultChars = new CameraCharacteristics(captureResultMeta);
|
||||
Object crKey = CaptureResult.Key.class;
|
||||
Class<CaptureResult.Key<?>> crKeyTyped = (Class<CaptureResult.Key<?>>)crKey;
|
||||
Class<CaptureResult.Key<?>> crKeyTyped = (Class<CaptureResult.Key<?>>) crKey;
|
||||
|
||||
ret.addAll(resultChars.getAvailableKeyList(CaptureResult.class, crKeyTyped,
|
||||
resultKeys, /*includeSynthetic*/ true));
|
||||
@@ -1145,7 +1155,7 @@ public final class CameraExtensionCharacteristics {
|
||||
} catch (RemoteException e) {
|
||||
throw new IllegalStateException("Failed to query the available capture result keys!");
|
||||
} finally {
|
||||
unregisterClient(clientId);
|
||||
unregisterClient(token);
|
||||
}
|
||||
|
||||
return Collections.unmodifiableSet(ret);
|
||||
|
||||
@@ -20,11 +20,13 @@ import android.hardware.camera2.extension.IPreviewExtenderImpl;
|
||||
import android.hardware.camera2.extension.IImageCaptureExtenderImpl;
|
||||
import android.hardware.camera2.extension.IInitializeSessionCallback;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
||||
/** @hide */
|
||||
interface ICameraExtensionsProxyService
|
||||
{
|
||||
long registerClient();
|
||||
void unregisterClient(long clientId);
|
||||
boolean registerClient(in IBinder token);
|
||||
void unregisterClient(in IBinder token);
|
||||
boolean advancedExtensionsSupported();
|
||||
void initializeSession(in IInitializeSessionCallback cb);
|
||||
void releaseSession();
|
||||
|
||||
@@ -24,11 +24,13 @@ import android.hardware.camera2.extension.LatencyRange;
|
||||
import android.hardware.camera2.extension.Size;
|
||||
import android.hardware.camera2.extension.SizeList;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
||||
/** @hide */
|
||||
interface IImageCaptureExtenderImpl
|
||||
{
|
||||
void onInit(in String cameraId, in CameraMetadataNative cameraCharacteristics);
|
||||
void onDeInit();
|
||||
void onInit(in IBinder token, in String cameraId, in CameraMetadataNative cameraCharacteristics);
|
||||
void onDeInit(in IBinder token);
|
||||
@nullable CaptureStageImpl onPresetSession();
|
||||
@nullable CaptureStageImpl onEnableSession();
|
||||
@nullable CaptureStageImpl onDisableSession();
|
||||
|
||||
@@ -22,11 +22,13 @@ import android.hardware.camera2.extension.IPreviewImageProcessorImpl;
|
||||
import android.hardware.camera2.extension.IRequestUpdateProcessorImpl;
|
||||
import android.hardware.camera2.extension.SizeList;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
||||
/** @hide */
|
||||
interface IPreviewExtenderImpl
|
||||
{
|
||||
void onInit(in String cameraId, in CameraMetadataNative cameraCharacteristics);
|
||||
void onDeInit();
|
||||
void onInit(in IBinder token, in String cameraId, in CameraMetadataNative cameraCharacteristics);
|
||||
void onDeInit(in IBinder token);
|
||||
@nullable CaptureStageImpl onPresetSession();
|
||||
@nullable CaptureStageImpl onEnableSession();
|
||||
@nullable CaptureStageImpl onDisableSession();
|
||||
|
||||
@@ -25,13 +25,15 @@ import android.hardware.camera2.extension.LatencyPair;
|
||||
import android.hardware.camera2.extension.LatencyRange;
|
||||
import android.hardware.camera2.extension.OutputSurface;
|
||||
|
||||
import android.os.IBinder;
|
||||
|
||||
/** @hide */
|
||||
interface ISessionProcessorImpl
|
||||
{
|
||||
CameraSessionConfig initSession(in String cameraId,
|
||||
CameraSessionConfig initSession(in IBinder token, in String cameraId,
|
||||
in Map<String, CameraMetadataNative> charsMap, in OutputSurface previewSurface,
|
||||
in OutputSurface imageCaptureSurface, in OutputSurface postviewSurface);
|
||||
void deInitSession();
|
||||
void deInitSession(in IBinder token);
|
||||
void onCaptureSessionStart(IRequestProcessorImpl requestProcessor);
|
||||
void onCaptureSessionEnd();
|
||||
int startRepeating(in ICaptureCallback callback);
|
||||
|
||||
@@ -60,6 +60,7 @@ import android.media.ImageReader;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.Size;
|
||||
@@ -79,7 +80,6 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
private final Executor mExecutor;
|
||||
private CameraDevice mCameraDevice;
|
||||
private final Map<String, CameraMetadataNative> mCharacteristicsMap;
|
||||
private final long mExtensionClientId;
|
||||
private final Handler mHandler;
|
||||
private final HandlerThread mHandlerThread;
|
||||
private final CameraExtensionSession.StateCallback mCallbacks;
|
||||
@@ -90,6 +90,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
|
||||
private RequestProcessor mRequestProcessor = new RequestProcessor();
|
||||
private final int mSessionId;
|
||||
private final IBinder mToken;
|
||||
|
||||
private Surface mClientRepeatingRequestSurface;
|
||||
private Surface mClientCaptureSurface;
|
||||
@@ -114,8 +115,9 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
@NonNull Map<String, CameraCharacteristics> characteristicsMap,
|
||||
@NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId)
|
||||
throws CameraAccessException, RemoteException {
|
||||
long clientId = CameraExtensionCharacteristics.registerClient(ctx);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + " : " + sessionId);
|
||||
boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
|
||||
if (!success) {
|
||||
throw new UnsupportedOperationException("Unsupported extension!");
|
||||
}
|
||||
|
||||
@@ -202,11 +204,10 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
IAdvancedExtenderImpl extender = CameraExtensionCharacteristics.initializeAdvancedExtension(
|
||||
config.getExtension());
|
||||
extender.init(cameraId, characteristicsMapNative);
|
||||
|
||||
CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(clientId,
|
||||
extender, cameraDevice, characteristicsMapNative, repeatingRequestSurface,
|
||||
CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(extender,
|
||||
cameraDevice, characteristicsMapNative, repeatingRequestSurface,
|
||||
burstCaptureSurface, postviewSurface, config.getStateCallback(),
|
||||
config.getExecutor(), sessionId);
|
||||
config.getExecutor(), sessionId, token);
|
||||
|
||||
ret.mStatsAggregator.setClientName(ctx.getOpPackageName());
|
||||
ret.mStatsAggregator.setExtensionType(config.getExtension());
|
||||
@@ -216,15 +217,13 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
return ret;
|
||||
}
|
||||
|
||||
private CameraAdvancedExtensionSessionImpl(long extensionClientId,
|
||||
@NonNull IAdvancedExtenderImpl extender,
|
||||
private CameraAdvancedExtensionSessionImpl(@NonNull IAdvancedExtenderImpl extender,
|
||||
@NonNull CameraDeviceImpl cameraDevice,
|
||||
Map<String, CameraMetadataNative> characteristicsMap,
|
||||
@Nullable Surface repeatingRequestSurface, @Nullable Surface burstCaptureSurface,
|
||||
@Nullable Surface postviewSurface,
|
||||
@NonNull StateCallback callback, @NonNull Executor executor,
|
||||
int sessionId) {
|
||||
mExtensionClientId = extensionClientId;
|
||||
int sessionId, @NonNull IBinder token) {
|
||||
mAdvancedExtender = extender;
|
||||
mCameraDevice = cameraDevice;
|
||||
mCharacteristicsMap = characteristicsMap;
|
||||
@@ -240,6 +239,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
mSessionClosed = false;
|
||||
mInitializeHandler = new InitializeSessionHandler();
|
||||
mSessionId = sessionId;
|
||||
mToken = token;
|
||||
mInterfaceLock = cameraDevice.mInterfaceLock;
|
||||
|
||||
mStatsAggregator = new ExtensionSessionStatsAggregator(mCameraDevice.getId(),
|
||||
@@ -260,7 +260,8 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
OutputSurface postviewSurface = initializeParcelable(mClientPostviewSurface);
|
||||
|
||||
mSessionProcessor = mAdvancedExtender.getSessionProcessor();
|
||||
CameraSessionConfig sessionConfig = mSessionProcessor.initSession(mCameraDevice.getId(),
|
||||
CameraSessionConfig sessionConfig = mSessionProcessor.initSession(mToken,
|
||||
mCameraDevice.getId(),
|
||||
mCharacteristicsMap, previewSurface, captureSurface, postviewSurface);
|
||||
List<CameraOutputConfig> outputConfigs = sessionConfig.outputConfigs;
|
||||
ArrayList<OutputConfiguration> outputList = new ArrayList<>();
|
||||
@@ -569,7 +570,7 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
if (!mSessionClosed) {
|
||||
mSessionProcessor.onCaptureSessionEnd();
|
||||
}
|
||||
mSessionProcessor.deInitSession();
|
||||
mSessionProcessor.deInitSession(mToken);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to de-initialize session processor, extension service"
|
||||
+ " does not respond!") ;
|
||||
@@ -577,12 +578,10 @@ public final class CameraAdvancedExtensionSessionImpl extends CameraExtensionSes
|
||||
mSessionProcessor = null;
|
||||
}
|
||||
|
||||
if (mExtensionClientId >= 0) {
|
||||
CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
|
||||
if (mInitialized || (mCaptureSession != null)) {
|
||||
notifyClose = true;
|
||||
CameraExtensionCharacteristics.releaseSession();
|
||||
}
|
||||
CameraExtensionCharacteristics.unregisterClient(mToken);
|
||||
if (mInitialized || (mCaptureSession != null)) {
|
||||
notifyClose = true;
|
||||
CameraExtensionCharacteristics.releaseSession();
|
||||
}
|
||||
mInitialized = false;
|
||||
|
||||
|
||||
@@ -56,6 +56,7 @@ import android.media.ImageWriter;
|
||||
import android.os.Binder;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
import android.util.LongSparseArray;
|
||||
@@ -79,7 +80,6 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
|
||||
private final Executor mExecutor;
|
||||
private final CameraDevice mCameraDevice;
|
||||
private final long mExtensionClientId;
|
||||
private final IImageCaptureExtenderImpl mImageExtender;
|
||||
private final IPreviewExtenderImpl mPreviewExtender;
|
||||
private final Handler mHandler;
|
||||
@@ -91,6 +91,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
private final Set<CaptureRequest.Key> mSupportedRequestKeys;
|
||||
private final Set<CaptureResult.Key> mSupportedResultKeys;
|
||||
private final ExtensionSessionStatsAggregator mStatsAggregator;
|
||||
private final IBinder mToken;
|
||||
private boolean mCaptureResultsSupported;
|
||||
|
||||
private CameraCaptureSession mCaptureSession = null;
|
||||
@@ -136,8 +137,9 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
@NonNull ExtensionSessionConfiguration config,
|
||||
int sessionId)
|
||||
throws CameraAccessException, RemoteException {
|
||||
long clientId = CameraExtensionCharacteristics.registerClient(ctx);
|
||||
if (clientId < 0) {
|
||||
final IBinder token = new Binder(TAG + " : " + sessionId);
|
||||
boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
|
||||
if (!success) {
|
||||
throw new UnsupportedOperationException("Unsupported extension!");
|
||||
}
|
||||
|
||||
@@ -225,15 +227,16 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
}
|
||||
|
||||
extenders.first.init(cameraId, characteristicsMap.get(cameraId).getNativeMetadata());
|
||||
extenders.first.onInit(cameraId, characteristicsMap.get(cameraId).getNativeMetadata());
|
||||
extenders.first.onInit(token, cameraId,
|
||||
characteristicsMap.get(cameraId).getNativeMetadata());
|
||||
extenders.second.init(cameraId, characteristicsMap.get(cameraId).getNativeMetadata());
|
||||
extenders.second.onInit(cameraId, characteristicsMap.get(cameraId).getNativeMetadata());
|
||||
extenders.second.onInit(token, cameraId,
|
||||
characteristicsMap.get(cameraId).getNativeMetadata());
|
||||
|
||||
CameraExtensionSessionImpl session = new CameraExtensionSessionImpl(
|
||||
extenders.second,
|
||||
extenders.first,
|
||||
supportedPreviewSizes,
|
||||
clientId,
|
||||
cameraDevice,
|
||||
repeatingRequestSurface,
|
||||
burstCaptureSurface,
|
||||
@@ -241,6 +244,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
config.getStateCallback(),
|
||||
config.getExecutor(),
|
||||
sessionId,
|
||||
token,
|
||||
extensionChars.getAvailableCaptureRequestKeys(config.getExtension()),
|
||||
extensionChars.getAvailableCaptureResultKeys(config.getExtension()));
|
||||
|
||||
@@ -255,7 +259,6 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
public CameraExtensionSessionImpl(@NonNull IImageCaptureExtenderImpl imageExtender,
|
||||
@NonNull IPreviewExtenderImpl previewExtender,
|
||||
@NonNull List<Size> previewSizes,
|
||||
long extensionClientId,
|
||||
@NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
|
||||
@Nullable Surface repeatingRequestSurface,
|
||||
@Nullable Surface burstCaptureSurface,
|
||||
@@ -263,9 +266,9 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
@NonNull StateCallback callback,
|
||||
@NonNull Executor executor,
|
||||
int sessionId,
|
||||
@NonNull IBinder token,
|
||||
@NonNull Set<CaptureRequest.Key> requestKeys,
|
||||
@Nullable Set<CaptureResult.Key> resultKeys) {
|
||||
mExtensionClientId = extensionClientId;
|
||||
mImageExtender = imageExtender;
|
||||
mPreviewExtender = previewExtender;
|
||||
mCameraDevice = cameraDevice;
|
||||
@@ -282,6 +285,7 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
mSessionClosed = false;
|
||||
mInitializeHandler = new InitializeSessionHandler();
|
||||
mSessionId = sessionId;
|
||||
mToken = token;
|
||||
mSupportedRequestKeys = requestKeys;
|
||||
mSupportedResultKeys = resultKeys;
|
||||
mCaptureResultsSupported = !resultKeys.isEmpty();
|
||||
@@ -867,19 +871,17 @@ public final class CameraExtensionSessionImpl extends CameraExtensionSession {
|
||||
mPreviewExtender.onDisableSession();
|
||||
mImageExtender.onDisableSession();
|
||||
}
|
||||
mPreviewExtender.onDeInit();
|
||||
mImageExtender.onDeInit();
|
||||
mPreviewExtender.onDeInit(mToken);
|
||||
mImageExtender.onDeInit(mToken);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to release extensions! Extension service does not"
|
||||
+ " respond!");
|
||||
}
|
||||
|
||||
if (mExtensionClientId >= 0) {
|
||||
CameraExtensionCharacteristics.unregisterClient(mExtensionClientId);
|
||||
if (mInitialized || (mCaptureSession != null)) {
|
||||
notifyClose = true;
|
||||
CameraExtensionCharacteristics.releaseSession();
|
||||
}
|
||||
CameraExtensionCharacteristics.unregisterClient(mToken);
|
||||
if (mInitialized || (mCaptureSession != null)) {
|
||||
notifyClose = true;
|
||||
CameraExtensionCharacteristics.releaseSession();
|
||||
}
|
||||
mInitialized = false;
|
||||
|
||||
|
||||
@@ -75,6 +75,7 @@ import android.util.Range;
|
||||
import android.util.Size;
|
||||
import android.view.Surface;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.camera.extensions.impl.AutoImageCaptureExtenderImpl;
|
||||
import androidx.camera.extensions.impl.AutoPreviewExtenderImpl;
|
||||
import androidx.camera.extensions.impl.BeautyImageCaptureExtenderImpl;
|
||||
@@ -204,7 +205,7 @@ public class CameraExtensionsProxyService extends Service {
|
||||
* A per-process global camera extension manager instance, to track and
|
||||
* initialize/release extensions depending on client activity.
|
||||
*/
|
||||
private static final class CameraExtensionManagerGlobal {
|
||||
private static final class CameraExtensionManagerGlobal implements IBinder.DeathRecipient {
|
||||
private static final String TAG = "CameraExtensionManagerGlobal";
|
||||
private final int EXTENSION_DELAY_MS = 1000;
|
||||
|
||||
@@ -212,8 +213,9 @@ public class CameraExtensionsProxyService extends Service {
|
||||
private final HandlerThread mHandlerThread;
|
||||
private final Object mLock = new Object();
|
||||
|
||||
private long mCurrentClientCount = 0;
|
||||
private ArraySet<Long> mActiveClients = new ArraySet<>();
|
||||
private ArraySet<IBinder> mActiveClients = new ArraySet<>();
|
||||
private HashMap<IBinder, ArraySet<IBinder.DeathRecipient>> mClientDeathRecipient =
|
||||
new HashMap<>();
|
||||
private IInitializeSessionCallback mInitializeCb = null;
|
||||
|
||||
// Singleton instance
|
||||
@@ -314,8 +316,20 @@ public class CameraExtensionsProxyService extends Service {
|
||||
return GLOBAL_CAMERA_MANAGER;
|
||||
}
|
||||
|
||||
public long registerClient(Context ctx) {
|
||||
public boolean registerClient(Context ctx, IBinder token) {
|
||||
synchronized (mLock) {
|
||||
if (mActiveClients.contains(token)) {
|
||||
Log.e(TAG, "Failed to register existing client!");
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
token.linkToDeath(this, 0);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, "Failed to link to binder token!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (INIT_API_SUPPORTED) {
|
||||
if (mActiveClients.isEmpty()) {
|
||||
InitializerFuture status = new InitializerFuture();
|
||||
@@ -327,47 +341,80 @@ public class CameraExtensionsProxyService extends Service {
|
||||
TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
Log.e(TAG, "Timed out while initializing camera extensions!");
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
if (!initSuccess) {
|
||||
Log.e(TAG, "Failed while initializing camera extensions!");
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
long ret = mCurrentClientCount;
|
||||
mCurrentClientCount++;
|
||||
if (mCurrentClientCount < 0) {
|
||||
mCurrentClientCount = 0;
|
||||
}
|
||||
mActiveClients.add(ret);
|
||||
mActiveClients.add(token);
|
||||
mClientDeathRecipient.put(token, new ArraySet<>());
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterClient(long clientId) {
|
||||
public void unregisterClient(IBinder token) {
|
||||
synchronized (mLock) {
|
||||
if (mActiveClients.remove(clientId) && mActiveClients.isEmpty() &&
|
||||
INIT_API_SUPPORTED) {
|
||||
InitializerFuture status = new InitializerFuture();
|
||||
InitializerImpl.deinit(new ReleaseHandler(status),
|
||||
new HandlerExecutor(mHandler));
|
||||
boolean releaseSuccess;
|
||||
try {
|
||||
releaseSuccess = status.get(EXTENSION_DELAY_MS, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
Log.e(TAG, "Timed out while releasing camera extensions!");
|
||||
return;
|
||||
}
|
||||
if (!releaseSuccess) {
|
||||
Log.e(TAG, "Failed while releasing camera extensions!");
|
||||
if (mActiveClients.remove(token)) {
|
||||
token.unlinkToDeath(this, 0);
|
||||
mClientDeathRecipient.remove(token);
|
||||
if (mActiveClients.isEmpty() && INIT_API_SUPPORTED) {
|
||||
InitializerFuture status = new InitializerFuture();
|
||||
InitializerImpl.deinit(new ReleaseHandler(status),
|
||||
new HandlerExecutor(mHandler));
|
||||
boolean releaseSuccess;
|
||||
try {
|
||||
releaseSuccess = status.get(EXTENSION_DELAY_MS, TimeUnit.MILLISECONDS);
|
||||
} catch (TimeoutException e) {
|
||||
Log.e(TAG, "Timed out while releasing camera extensions!");
|
||||
return;
|
||||
}
|
||||
if (!releaseSuccess) {
|
||||
Log.e(TAG, "Failed while releasing camera extensions!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
// Do nothing, handled below
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied(@NonNull IBinder who) {
|
||||
synchronized (mLock) {
|
||||
if (mClientDeathRecipient.containsKey(who)) {
|
||||
mClientDeathRecipient.get(who).stream().forEach(
|
||||
recipient -> recipient.binderDied(who));
|
||||
}
|
||||
unregisterClient(who);
|
||||
}
|
||||
}
|
||||
|
||||
public void registerDeathRecipient(IBinder token, IBinder.DeathRecipient recipient) {
|
||||
synchronized (mLock) {
|
||||
if (mClientDeathRecipient.containsKey(token)) {
|
||||
ArraySet<IBinder.DeathRecipient> recipients = mClientDeathRecipient.get(token);
|
||||
recipients.add(recipient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterDeathRecipient(IBinder token, IBinder.DeathRecipient recipient) {
|
||||
synchronized (mLock) {
|
||||
if (mClientDeathRecipient.containsKey(token)) {
|
||||
ArraySet<IBinder.DeathRecipient> recipients = mClientDeathRecipient.get(token);
|
||||
recipients.remove(recipient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
|
||||
@Override
|
||||
public void binderDied() {
|
||||
@@ -406,21 +453,35 @@ public class CameraExtensionsProxyService extends Service {
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private static long registerClient(Context ctx) {
|
||||
private static boolean registerClient(Context ctx, IBinder token) {
|
||||
if (!EXTENSIONS_PRESENT) {
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
return CameraExtensionManagerGlobal.get().registerClient(ctx);
|
||||
return CameraExtensionManagerGlobal.get().registerClient(ctx, token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static void unregisterClient(long clientId) {
|
||||
public static void unregisterClient(IBinder token) {
|
||||
if (!EXTENSIONS_PRESENT) {
|
||||
return;
|
||||
}
|
||||
CameraExtensionManagerGlobal.get().unregisterClient(clientId);
|
||||
CameraExtensionManagerGlobal.get().unregisterClient(token);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private static void registerDeathRecipient(IBinder token, IBinder.DeathRecipient recipient) {
|
||||
CameraExtensionManagerGlobal.get().registerDeathRecipient(token, recipient);
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
private static void unregisterDeathRecipient(IBinder token, IBinder.DeathRecipient recipient) {
|
||||
CameraExtensionManagerGlobal.get().unregisterDeathRecipient(token, recipient);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -649,13 +710,14 @@ public class CameraExtensionsProxyService extends Service {
|
||||
|
||||
private class CameraExtensionsProxyServiceStub extends ICameraExtensionsProxyService.Stub {
|
||||
@Override
|
||||
public long registerClient() {
|
||||
return CameraExtensionsProxyService.registerClient(CameraExtensionsProxyService.this);
|
||||
public boolean registerClient(IBinder token) {
|
||||
return CameraExtensionsProxyService.registerClient(CameraExtensionsProxyService.this,
|
||||
token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterClient(long clientId) {
|
||||
CameraExtensionsProxyService.unregisterClient(clientId);
|
||||
public void unregisterClient(IBinder token) {
|
||||
CameraExtensionsProxyService.unregisterClient(token);
|
||||
}
|
||||
|
||||
private boolean checkCameraPermission() {
|
||||
@@ -1192,16 +1254,18 @@ public class CameraExtensionsProxyService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private class SessionProcessorImplStub extends ISessionProcessorImpl.Stub {
|
||||
private class SessionProcessorImplStub extends ISessionProcessorImpl.Stub implements
|
||||
IBinder.DeathRecipient {
|
||||
private final SessionProcessorImpl mSessionProcessor;
|
||||
private String mCameraId = null;
|
||||
private IBinder mToken;
|
||||
|
||||
public SessionProcessorImplStub(SessionProcessorImpl sessionProcessor) {
|
||||
mSessionProcessor = sessionProcessor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CameraSessionConfig initSession(String cameraId,
|
||||
public CameraSessionConfig initSession(IBinder token, String cameraId,
|
||||
Map<String, CameraMetadataNative> charsMapNative, OutputSurface previewSurface,
|
||||
OutputSurface imageCaptureSurface, OutputSurface postviewSurface) {
|
||||
OutputSurfaceImplStub outputPreviewSurfaceImpl =
|
||||
@@ -1253,12 +1317,14 @@ public class CameraExtensionsProxyService extends Service {
|
||||
ret.sessionParameter = initializeParcelableMetadata(
|
||||
sessionConfig.getSessionParameters(), cameraId);
|
||||
mCameraId = cameraId;
|
||||
|
||||
mToken = token;
|
||||
CameraExtensionsProxyService.registerDeathRecipient(mToken, this);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deInitSession() {
|
||||
public void deInitSession(IBinder token) {
|
||||
CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
|
||||
mSessionProcessor.deInitSession();
|
||||
}
|
||||
|
||||
@@ -1330,6 +1396,11 @@ public class CameraExtensionsProxyService extends Service {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
mSessionProcessor.deInitSession();
|
||||
}
|
||||
}
|
||||
|
||||
private class OutputSurfaceConfigurationImplStub implements OutputSurfaceConfigurationImpl {
|
||||
@@ -1395,24 +1466,31 @@ public class CameraExtensionsProxyService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub {
|
||||
private class PreviewExtenderImplStub extends IPreviewExtenderImpl.Stub implements
|
||||
IBinder.DeathRecipient {
|
||||
private final PreviewExtenderImpl mPreviewExtender;
|
||||
private String mCameraId = null;
|
||||
private boolean mSessionEnabled;
|
||||
private IBinder mToken;
|
||||
|
||||
public PreviewExtenderImplStub(PreviewExtenderImpl previewExtender) {
|
||||
mPreviewExtender = previewExtender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInit(String cameraId, CameraMetadataNative cameraCharacteristics) {
|
||||
public void onInit(IBinder token, String cameraId,
|
||||
CameraMetadataNative cameraCharacteristics) {
|
||||
mCameraId = cameraId;
|
||||
CameraCharacteristics chars = new CameraCharacteristics(cameraCharacteristics);
|
||||
mCameraManager.registerDeviceStateListener(chars);
|
||||
mPreviewExtender.onInit(cameraId, chars, CameraExtensionsProxyService.this);
|
||||
mToken = token;
|
||||
CameraExtensionsProxyService.registerDeathRecipient(mToken, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeInit() {
|
||||
public void onDeInit(IBinder token) {
|
||||
CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
|
||||
mPreviewExtender.onDeInit();
|
||||
}
|
||||
|
||||
@@ -1423,11 +1501,13 @@ public class CameraExtensionsProxyService extends Service {
|
||||
|
||||
@Override
|
||||
public CaptureStageImpl onEnableSession() {
|
||||
mSessionEnabled = true;
|
||||
return initializeParcelable(mPreviewExtender.onEnableSession(), mCameraId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CaptureStageImpl onDisableSession() {
|
||||
mSessionEnabled = false;
|
||||
return initializeParcelable(mPreviewExtender.onDisableSession(), mCameraId);
|
||||
}
|
||||
|
||||
@@ -1516,26 +1596,41 @@ public class CameraExtensionsProxyService extends Service {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
if (mSessionEnabled) {
|
||||
mPreviewExtender.onDisableSession();
|
||||
}
|
||||
mPreviewExtender.onDeInit();
|
||||
}
|
||||
}
|
||||
|
||||
private class ImageCaptureExtenderImplStub extends IImageCaptureExtenderImpl.Stub {
|
||||
private class ImageCaptureExtenderImplStub extends IImageCaptureExtenderImpl.Stub implements
|
||||
IBinder.DeathRecipient {
|
||||
private final ImageCaptureExtenderImpl mImageExtender;
|
||||
private String mCameraId = null;
|
||||
private boolean mSessionEnabled;
|
||||
private IBinder mToken;
|
||||
|
||||
public ImageCaptureExtenderImplStub(ImageCaptureExtenderImpl imageExtender) {
|
||||
mImageExtender = imageExtender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInit(String cameraId, CameraMetadataNative cameraCharacteristics) {
|
||||
public void onInit(IBinder token, String cameraId,
|
||||
CameraMetadataNative cameraCharacteristics) {
|
||||
CameraCharacteristics chars = new CameraCharacteristics(cameraCharacteristics);
|
||||
mCameraManager.registerDeviceStateListener(chars);
|
||||
mImageExtender.onInit(cameraId, chars, CameraExtensionsProxyService.this);
|
||||
mCameraId = cameraId;
|
||||
mToken = token;
|
||||
CameraExtensionsProxyService.registerDeathRecipient(mToken, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDeInit() {
|
||||
public void onDeInit(IBinder token) {
|
||||
CameraExtensionsProxyService.unregisterDeathRecipient(mToken, this);
|
||||
mImageExtender.onDeInit();
|
||||
}
|
||||
|
||||
@@ -1564,11 +1659,13 @@ public class CameraExtensionsProxyService extends Service {
|
||||
|
||||
@Override
|
||||
public CaptureStageImpl onEnableSession() {
|
||||
mSessionEnabled = true;
|
||||
return initializeParcelable(mImageExtender.onEnableSession(), mCameraId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CaptureStageImpl onDisableSession() {
|
||||
mSessionEnabled = false;
|
||||
return initializeParcelable(mImageExtender.onDisableSession(), mCameraId);
|
||||
}
|
||||
|
||||
@@ -1737,6 +1834,14 @@ public class CameraExtensionsProxyService extends Service {
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void binderDied() {
|
||||
if (mSessionEnabled) {
|
||||
mImageExtender.onDisableSession();
|
||||
}
|
||||
mImageExtender.onDeInit();
|
||||
}
|
||||
}
|
||||
|
||||
private class ProcessResultCallback implements ProcessResultImpl {
|
||||
|
||||
Reference in New Issue
Block a user