| /* |
| * Copyright (C) 2023 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; |
| |
| import android.annotation.FlaggedApi; |
| import android.annotation.NonNull; |
| import android.annotation.Nullable; |
| import android.annotation.SystemApi; |
| import android.app.AppOpsManager; |
| import android.app.Service; |
| import android.content.Intent; |
| import android.hardware.camera2.CameraExtensionCharacteristics.Extension; |
| import android.os.IBinder; |
| import android.os.RemoteException; |
| import android.util.Log; |
| |
| import com.android.internal.annotations.GuardedBy; |
| import com.android.internal.camera.flags.Flags; |
| |
| interface CameraUsageTracker { |
| void startCameraOperation(); |
| void finishCameraOperation(); |
| } |
| |
| /** |
| * Base service class that extension service implementations must extend. |
| * |
| * @hide |
| */ |
| @SystemApi |
| @FlaggedApi(Flags.FLAG_CONCERT_MODE) |
| public abstract class CameraExtensionService extends Service { |
| private static final String TAG = "CameraExtensionService"; |
| private CameraUsageTracker mCameraUsageTracker; |
| private static Object mLock = new Object(); |
| |
| private final class CameraTracker implements CameraUsageTracker { |
| |
| private final AppOpsManager mAppOpsService = getApplicationContext().getSystemService( |
| AppOpsManager.class); |
| private final String mPackageName = getPackageName(); |
| private final String mAttributionTag = getAttributionTag(); |
| private int mUid = getApplicationInfo().uid; |
| |
| @Override |
| public void startCameraOperation() { |
| if (mAppOpsService != null) { |
| mAppOpsService.startOp(AppOpsManager.OPSTR_CAMERA, mUid, mPackageName, |
| mAttributionTag, "Camera extensions"); |
| } |
| } |
| |
| @Override |
| public void finishCameraOperation() { |
| if (mAppOpsService != null) { |
| mAppOpsService.finishOp(AppOpsManager.OPSTR_CAMERA, mUid, mPackageName, |
| mAttributionTag); |
| } |
| } |
| } |
| @GuardedBy("mLock") |
| private static IInitializeSessionCallback mInitializeCb = null; |
| |
| private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() { |
| @Override |
| public void binderDied() { |
| synchronized (mLock) { |
| mInitializeCb = null; |
| } |
| if (mCameraUsageTracker != null) { |
| mCameraUsageTracker.finishCameraOperation(); |
| } |
| } |
| }; |
| |
| @FlaggedApi(Flags.FLAG_CONCERT_MODE) |
| protected CameraExtensionService() { } |
| |
| @FlaggedApi(Flags.FLAG_CONCERT_MODE) |
| @Override |
| @NonNull |
| public final IBinder onBind(@Nullable Intent intent) { |
| if (mCameraUsageTracker == null) { |
| mCameraUsageTracker = new CameraTracker(); |
| } |
| return new CameraExtensionServiceImpl(); |
| } |
| |
| private class CameraExtensionServiceImpl extends ICameraExtensionsProxyService.Stub { |
| @Override |
| public boolean registerClient(IBinder token) throws RemoteException { |
| return CameraExtensionService.this.onRegisterClient(token); |
| } |
| |
| @Override |
| public void unregisterClient(IBinder token) throws RemoteException { |
| CameraExtensionService.this.onUnregisterClient(token); |
| } |
| |
| @Override |
| public boolean advancedExtensionsSupported() throws RemoteException { |
| return true; |
| } |
| |
| @Override |
| public void initializeSession(IInitializeSessionCallback cb) { |
| boolean ret = false; |
| synchronized (mLock) { |
| if (mInitializeCb == null) { |
| mInitializeCb = cb; |
| try { |
| mInitializeCb.asBinder().linkToDeath(mDeathRecipient, 0); |
| } catch (RemoteException e) { |
| Log.e(TAG, "Failure to register binder death notifier!"); |
| } |
| ret = true; |
| } |
| } |
| |
| try { |
| if (ret) { |
| cb.onSuccess(); |
| } else { |
| cb.onFailure(); |
| } |
| } catch (RemoteException e) { |
| |
| Log.e(TAG, "Client doesn't respond!"); |
| } |
| } |
| |
| @Override |
| public void releaseSession() { |
| synchronized (mLock) { |
| if (mInitializeCb != null) { |
| mInitializeCb.asBinder().unlinkToDeath(mDeathRecipient, 0); |
| mInitializeCb = null; |
| } |
| } |
| } |
| |
| @Override |
| public IPreviewExtenderImpl initializePreviewExtension(@Extension int extensionType) |
| throws RemoteException { |
| // Basic Extension API is not supported |
| return null; |
| } |
| |
| @Override |
| public IImageCaptureExtenderImpl initializeImageExtension(@Extension int extensionType) |
| throws RemoteException { |
| // Basic Extension API is not supported |
| return null; |
| } |
| |
| @Override |
| public IAdvancedExtenderImpl initializeAdvancedExtension(@Extension int extensionType) |
| throws RemoteException { |
| AdvancedExtender extender = CameraExtensionService.this.onInitializeAdvancedExtension( |
| extensionType); |
| extender.setCameraUsageTracker(mCameraUsageTracker); |
| return extender.getAdvancedExtenderBinder(); |
| } |
| } |
| |
| /** |
| * Register an extension client. The client must call this method |
| * after successfully binding to the service. |
| * |
| * @param token Binder token that can be used for adding |
| * death notifier in case the client exits |
| * unexpectedly. |
| * @return true if the registration is successful, false otherwise |
| */ |
| @FlaggedApi(Flags.FLAG_CONCERT_MODE) |
| public abstract boolean onRegisterClient(@NonNull IBinder token); |
| |
| /** |
| * Unregister an extension client. |
| * |
| * @param token Binder token |
| */ |
| @FlaggedApi(Flags.FLAG_CONCERT_MODE) |
| public abstract void onUnregisterClient(@NonNull IBinder token); |
| |
| /** |
| * Initialize and return an advanced extension. |
| * |
| * @param extensionType {@link android.hardware.camera2.CameraExtensionCharacteristics} |
| * extension type |
| * @return Valid advanced extender of the requested type |
| */ |
| @FlaggedApi(Flags.FLAG_CONCERT_MODE) |
| @NonNull |
| public abstract AdvancedExtender onInitializeAdvancedExtension(@Extension int extensionType); |
| } |