Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b2456b40 authored by Kwangkyu Park's avatar Kwangkyu Park Committed by Emilian Peev
Browse files

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
parent 41fc44e3
Loading
Loading
Loading
Loading
+62 −52
Original line number Diff line number Diff line
@@ -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) {
                if (mProxy == null) {
                    return false;
                }

                try {
                        return mProxy.registerClient();
                    return mProxy.registerClient(token);
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to initialize extension! Extension service does "
                            + " not respond!");
                        return -1;
                    }
                } else {
                    return -1;
                }

                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) {
@@ -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);
+4 −2
Original line number Diff line number Diff line
@@ -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();
+4 −2
Original line number Diff line number Diff line
@@ -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();
+4 −2
Original line number Diff line number Diff line
@@ -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();
+4 −2
Original line number Diff line number Diff line
@@ -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);
Loading