Merge "Camera: Avoid caching extension service connections" into udc-qpr-dev
diff --git a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
index 6baf91d7..ea951a5 100644
--- a/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraExtensionCharacteristics.java
@@ -236,9 +236,10 @@
         private static final CameraExtensionManagerGlobal GLOBAL_CAMERA_MANAGER =
                 new CameraExtensionManagerGlobal();
         private final Object mLock = new Object();
-        private final int PROXY_SERVICE_DELAY_MS = 1000;
+        private final int PROXY_SERVICE_DELAY_MS = 2000;
         private InitializerFuture mInitFuture = null;
         private ServiceConnection mConnection = null;
+        private int mConnectionCount = 0;
         private ICameraExtensionsProxyService mProxy = null;
         private boolean mSupportsAdvancedExtensions = false;
 
@@ -249,6 +250,15 @@
             return GLOBAL_CAMERA_MANAGER;
         }
 
+        private void releaseProxyConnectionLocked(Context ctx) {
+            if (mConnection != null ) {
+                ctx.unbindService(mConnection);
+                mConnection = null;
+                mProxy = null;
+                mConnectionCount = 0;
+            }
+        }
+
         private void connectToProxyLocked(Context ctx) {
             if (mConnection == null) {
                 Intent intent = new Intent();
@@ -270,7 +280,6 @@
                 mConnection = new ServiceConnection() {
                     @Override
                     public void onServiceDisconnected(ComponentName component) {
-                        mInitFuture.setStatus(false);
                         mConnection = null;
                         mProxy = null;
                     }
@@ -348,23 +357,32 @@
 
         public boolean registerClient(Context ctx, IBinder token) {
             synchronized (mLock) {
+                boolean ret = false;
                 connectToProxyLocked(ctx);
                 if (mProxy == null) {
                     return false;
                 }
+                mConnectionCount++;
 
                 try {
-                    return mProxy.registerClient(token);
+                    ret = mProxy.registerClient(token);
                 } catch (RemoteException e) {
                     Log.e(TAG, "Failed to initialize extension! Extension service does "
                             + " not respond!");
                 }
+                if (!ret) {
+                    mConnectionCount--;
+                }
 
-                return false;
+                if (mConnectionCount <= 0) {
+                    releaseProxyConnectionLocked(ctx);
+                }
+
+                return ret;
             }
         }
 
-        public void unregisterClient(IBinder token) {
+        public void unregisterClient(Context ctx, IBinder token) {
             synchronized (mLock) {
                 if (mProxy != null) {
                     try {
@@ -372,6 +390,11 @@
                     } catch (RemoteException e) {
                         Log.e(TAG, "Failed to de-initialize extension! Extension service does"
                                 + " not respond!");
+                    } finally {
+                        mConnectionCount--;
+                        if (mConnectionCount <= 0) {
+                            releaseProxyConnectionLocked(ctx);
+                        }
                     }
                 }
             }
@@ -446,8 +469,8 @@
     /**
      * @hide
      */
-    public static void unregisterClient(IBinder token) {
-        CameraExtensionManagerGlobal.get().unregisterClient(token);
+    public static void unregisterClient(Context ctx, IBinder token) {
+        CameraExtensionManagerGlobal.get().unregisterClient(ctx, token);
     }
 
     /**
@@ -578,7 +601,7 @@
                 }
             }
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return Collections.unmodifiableList(ret);
@@ -626,7 +649,7 @@
             Log.e(TAG, "Failed to query the extension for postview availability! Extension "
                     + "service does not respond!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return false;
@@ -722,7 +745,7 @@
                     + "service does not respond!");
             return Collections.emptyList();
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
     }
 
@@ -791,7 +814,7 @@
                     + " not respond!");
             return new ArrayList<>();
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
     }
 
@@ -872,7 +895,7 @@
                     }
                 }
             } finally {
-                unregisterClient(token);
+                unregisterClient(mContext, token);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to query the extension supported sizes! Extension service does"
@@ -957,7 +980,7 @@
             Log.e(TAG, "Failed to query the extension capture latency! Extension service does"
                     + " not respond!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return null;
@@ -998,7 +1021,7 @@
             Log.e(TAG, "Failed to query the extension progress callbacks! Extension service does"
                     + " not respond!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return false;
@@ -1075,7 +1098,7 @@
         } catch (RemoteException e) {
             throw new IllegalStateException("Failed to query the available capture request keys!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return Collections.unmodifiableSet(ret);
@@ -1155,7 +1178,7 @@
         } catch (RemoteException e) {
             throw new IllegalStateException("Failed to query the available capture result keys!");
         } finally {
-            unregisterClient(token);
+            unregisterClient(mContext, token);
         }
 
         return Collections.unmodifiableSet(ret);
diff --git a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
index ae700a0..f0fb2f9 100644
--- a/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraAdvancedExtensionSessionImpl.java
@@ -90,7 +90,7 @@
     private final HashMap<Integer, ImageReader> mReaderMap = new HashMap<>();
     private RequestProcessor mRequestProcessor = new RequestProcessor();
     private final int mSessionId;
-    private final IBinder mToken;
+    private IBinder mToken = null;
 
     private Surface mClientRepeatingRequestSurface;
     private Surface mClientCaptureSurface;
@@ -103,6 +103,8 @@
     private boolean mInitialized;
     private boolean mSessionClosed;
 
+    private final Context mContext;
+
     // Lock to synchronize cross-thread access to device public interface
     final Object mInterfaceLock;
 
@@ -113,14 +115,9 @@
     public static CameraAdvancedExtensionSessionImpl createCameraAdvancedExtensionSession(
             @NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
             @NonNull Map<String, CameraCharacteristics> characteristicsMap,
-            @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId)
+            @NonNull Context ctx, @NonNull ExtensionSessionConfiguration config, int sessionId,
+            @NonNull IBinder token)
             throws CameraAccessException, RemoteException {
-        final IBinder token = new Binder(TAG + " : " + sessionId);
-        boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
-        if (!success) {
-            throw new UnsupportedOperationException("Unsupported extension!");
-        }
-
         String cameraId = cameraDevice.getId();
         CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
                 cameraId, characteristicsMap);
@@ -204,8 +201,9 @@
         IAdvancedExtenderImpl extender = CameraExtensionCharacteristics.initializeAdvancedExtension(
                 config.getExtension());
         extender.init(cameraId, characteristicsMapNative);
-        CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(extender,
-                cameraDevice, characteristicsMapNative, repeatingRequestSurface,
+
+        CameraAdvancedExtensionSessionImpl ret = new CameraAdvancedExtensionSessionImpl(ctx,
+                extender, cameraDevice, characteristicsMapNative, repeatingRequestSurface,
                 burstCaptureSurface, postviewSurface, config.getStateCallback(),
                 config.getExecutor(), sessionId, token);
 
@@ -217,13 +215,16 @@
         return ret;
     }
 
-    private CameraAdvancedExtensionSessionImpl(@NonNull IAdvancedExtenderImpl extender,
+    private CameraAdvancedExtensionSessionImpl(Context ctx,
+            @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, @NonNull IBinder token) {
+            int sessionId,
+            @NonNull IBinder token) {
+        mContext = ctx;
         mAdvancedExtender = extender;
         mCameraDevice = cameraDevice;
         mCharacteristicsMap = characteristicsMap;
@@ -578,12 +579,16 @@
                 mSessionProcessor = null;
             }
 
-            CameraExtensionCharacteristics.unregisterClient(mToken);
-            if (mInitialized || (mCaptureSession != null)) {
-                notifyClose = true;
-                CameraExtensionCharacteristics.releaseSession();
+
+            if (mToken != null) {
+                if (mInitialized || (mCaptureSession != null)) {
+                    notifyClose = true;
+                    CameraExtensionCharacteristics.releaseSession();
+                }
+                CameraExtensionCharacteristics.unregisterClient(mContext, mToken);
             }
             mInitialized = false;
+            mToken = null;
 
             for (ImageReader reader : mReaderMap.values()) {
                 reader.close();
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index d3bde4b..181ab2c 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -2550,19 +2550,32 @@
         HashMap<String, CameraCharacteristics> characteristicsMap = new HashMap<>(
                 mPhysicalIdsToChars);
         characteristicsMap.put(mCameraId, mCharacteristics);
+        boolean initializationFailed = true;
+        IBinder token = new Binder(TAG + " : " + mNextSessionId++);
         try {
+            boolean ret = CameraExtensionCharacteristics.registerClient(mContext, token);
+            if (!ret) {
+                token = null;
+                throw new UnsupportedOperationException("Unsupported extension!");
+            }
+
             if (CameraExtensionCharacteristics.areAdvancedExtensionsSupported()) {
                 mCurrentAdvancedExtensionSession =
                         CameraAdvancedExtensionSessionImpl.createCameraAdvancedExtensionSession(
                                 this, characteristicsMap, mContext, extensionConfiguration,
-                                mNextSessionId++);
+                                mNextSessionId, token);
             } else {
                 mCurrentExtensionSession = CameraExtensionSessionImpl.createCameraExtensionSession(
                         this, characteristicsMap, mContext, extensionConfiguration,
-                        mNextSessionId++);
+                        mNextSessionId, token);
             }
+            initializationFailed = false;
         } catch (RemoteException e) {
             throw new CameraAccessException(CameraAccessException.CAMERA_ERROR);
+        } finally {
+            if (initializationFailed && (token != null)) {
+                CameraExtensionCharacteristics.unregisterClient(mContext, token);
+            }
         }
     }
 }
diff --git a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
index 1db4808..7b7d7de 100644
--- a/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraExtensionSessionImpl.java
@@ -91,7 +91,7 @@
     private final Set<CaptureRequest.Key> mSupportedRequestKeys;
     private final Set<CaptureResult.Key> mSupportedResultKeys;
     private final ExtensionSessionStatsAggregator mStatsAggregator;
-    private final IBinder mToken;
+    private IBinder mToken = null;
     private boolean mCaptureResultsSupported;
 
     private CameraCaptureSession mCaptureSession = null;
@@ -119,6 +119,8 @@
     // will do so internally.
     private boolean mInternalRepeatingRequestEnabled = true;
 
+    private final Context mContext;
+
     // Lock to synchronize cross-thread access to device public interface
     final Object mInterfaceLock;
 
@@ -135,14 +137,9 @@
             @NonNull Map<String, CameraCharacteristics> characteristicsMap,
             @NonNull Context ctx,
             @NonNull ExtensionSessionConfiguration config,
-            int sessionId)
+            int sessionId,
+            @NonNull IBinder token)
             throws CameraAccessException, RemoteException {
-        final IBinder token = new Binder(TAG + " : " + sessionId);
-        boolean success = CameraExtensionCharacteristics.registerClient(ctx, token);
-        if (!success) {
-            throw new UnsupportedOperationException("Unsupported extension!");
-        }
-
         String cameraId = cameraDevice.getId();
         CameraExtensionCharacteristics extensionChars = new CameraExtensionCharacteristics(ctx,
                 cameraId, characteristicsMap);
@@ -234,6 +231,7 @@
                 characteristicsMap.get(cameraId).getNativeMetadata());
 
         CameraExtensionSessionImpl session = new CameraExtensionSessionImpl(
+                ctx,
                 extenders.second,
                 extenders.first,
                 supportedPreviewSizes,
@@ -256,7 +254,7 @@
         return session;
     }
 
-    public CameraExtensionSessionImpl(@NonNull IImageCaptureExtenderImpl imageExtender,
+    public CameraExtensionSessionImpl(Context ctx, @NonNull IImageCaptureExtenderImpl imageExtender,
             @NonNull IPreviewExtenderImpl previewExtender,
             @NonNull List<Size> previewSizes,
             @NonNull android.hardware.camera2.impl.CameraDeviceImpl cameraDevice,
@@ -269,6 +267,7 @@
             @NonNull IBinder token,
             @NonNull Set<CaptureRequest.Key> requestKeys,
             @Nullable Set<CaptureResult.Key> resultKeys) {
+        mContext = ctx;
         mImageExtender = imageExtender;
         mPreviewExtender = previewExtender;
         mCameraDevice = cameraDevice;
@@ -878,12 +877,15 @@
                         + " respond!");
             }
 
-            CameraExtensionCharacteristics.unregisterClient(mToken);
-            if (mInitialized || (mCaptureSession != null)) {
-                notifyClose = true;
-                CameraExtensionCharacteristics.releaseSession();
+            if (mToken != null) {
+                if (mInitialized || (mCaptureSession != null)) {
+                    notifyClose = true;
+                    CameraExtensionCharacteristics.releaseSession();
+                }
+                CameraExtensionCharacteristics.unregisterClient(mContext, mToken);
             }
             mInitialized = false;
+            mToken = null;
 
             if (mRepeatingRequestImageCallback != null) {
                 mRepeatingRequestImageCallback.close();