相机可用性变化监听及流程分析
一、接口说明
相机可用性变化监听可以通过CameraManager中的接口registerAvailabilityCallback()来设置回调,接口如下:
/**
*注册一个回调以获得有关相机设备可用性的通知。
*
*<p>再次注册相同的回调将用提供的新回调替换处理程序</p>
*
*<p>第一次注册回调时,会立即调用回调,并显示当前已知的所有相机设备的可用性状态</p>
*
*任何相机API客户端打开相机设备时,都会调用<p>{@linkAvailabilityCallback#onCameraUnavailable(String)}。从API级别23开始,其他相机API客户端可能仍然能够打开这样的相机设备,如果它们的优先级高于相机设备的现有客户端,则会逐出现有客户端。有关详细信息,请参阅open()</p>
*
*<p>由于此回调将在相机服务中注册,请记住在不再需要时注销它;否则,回调将无限期地继续接收事件,并可能阻止其他资源被释放。具体来说,回调将调用各个CameraManager实例的状态</p>
*
*@param callback 向发送相机可用性通知的新回调。
*@param handler 应该调用回调的handler,或者为{@code null}的话使用当前线程的{@linkandroid.os.Looper Looper}。
*
*如果handler为{@code null},但当前线程没有Looper,则@throws IllegalArgumentException。
*/
public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback, @Nullable Handler handler)
AvailabilityCallback主要api如下:
/***摄像机设备变为可用或不可用的回调。**<p>当不再使用相机或连接新的可移动相机时,相机将可用。当某些应用程序或服务开始使用相机时,或者当可移动相机断开连接时,它们将不可用</p>**<p>扩展此回调,并将子类的一个实例传递给{@link CameraManager#registerAvailabilityCallback},以便收到此类可用性更改的通知</p>**@参见#registerAvailabilityCallback*/public static abstract class AvailabilityCallback {/***一台新相机已经可以使用了。**<p>此方法的默认实现不执行任何操作</p>**@param cameraId新相机的唯一标识符。*/public void onCameraAvailable(@NonNull String cameraId) {// default empty implementation}/***以前可用的相机已无法使用。**<p>*如果一个应用程序有一个活动的CameraDevice实例用于现在断开连接的相机,该应用程序将收到{@link CameraDevice.StateCallback#onDisconnected disconnection error}*</p>**<p>此方法的默认实现不执行任何操作</p>**@param cameraId断开连接的摄像机的唯一标识符。*/public void onCameraUnavailable(@NonNull String cameraId) {// default empty implementation}/***每当摄像机访问优先级更改时调用。**<p>通知相机访问优先级已更改,相机现在可以打开。先前由于较高优先级的用户已经在使用相机而被拒绝访问相机的应用程序,或者由于较高优先级用户试图打开相机而与活动相机会话断开连接的应用程序如果仍想使用相机,则应尝试再次打开相机。请注意,多个应用程序可能同时接收此回调,并且在实践中,根据确切的访问优先级和时间,只有其中一个应用程序能够成功打开相机。如果多个应用程序可能同时处于恢复状态,并且用户在它们之间切换焦点,或者使用应用程序的当前相机在全屏和画中画(PiP)状态之间移动,则此方法非常有用。在这种情况下,摄像机可用/不可用回调将不会被调用,但另一个应用程序现在可能比当前使用摄像机的应用程序具有更高的摄像机访问优先级</p>**<p>此方法的默认实现不执行任何操作</p>*/public void onCameraAccessPrioritiesChanged() {// default empty implementation}/***一台物理相机已可再次使用。**<p>默认情况下,逻辑多摄像机的所有物理摄像机都可用,因此当调用逻辑多摄像机用的{@link#onCameraAvailable}时,不会为逻辑多摄像机中的任何物理摄像机调用{@link#onPhysicalCameraAvailable}。但是,如果某些特定的物理摄影机一开始就不可用,则可以在{@link#onCameraAvailable}之后调用{@link#onPhysicalCameraUnavailable}</p>**<p>此方法的默认实现不执行任何操作</p>**@param cameraId逻辑多摄像机的唯一标识符。*@param physicalCameraId物理相机的唯一标识符。**@请参阅#onCameraAvailable*@请参阅#onPhysicalCamera不可用*/public void onPhysicalCameraAvailable(@NonNull String cameraId,@NonNull String physicalCameraId) {// default empty implementation}/***以前可用的物理相机已无法使用。**<p>默认情况下,逻辑多摄像机的所有物理摄像机都可用,因此当调用逻辑多摄像机用的{@link#onCameraAvailable}时,不会为逻辑多摄像机中的任何物理摄像机调用{@link#onPhysicalCameraAvailable}。如果某些特定的物理相机一开始就不可用,则可以在{@link#onCameraAvailable}之后调用{@link#onPhysicalCameraUnavailable}</p>**<p>此方法的默认实现不执行任何操作</p>**@param cameraId逻辑多摄像机的唯一标识符。*@param physicalCameraId物理相机的唯一标识符。**@请参阅#onCameraAvailable*@请参阅#onPhysicalCameraAvailable*/public void onPhysicalCameraUnavailable(@NonNull String cameraId,@NonNull String physicalCameraId) {// default empty implementation}}
注意这里physical camera和logical multi-camera的区别:
-
physical camera:物理摄像头,对应实际的物理硬件。
-
logical multi-camera:是在某些支持的 Android 设备上引入的一项功能,它允许开发者同时使用多个摄像头来进行更高级的图像处理和功能。在逻辑多摄像头系统中,多个物理摄像头可以捆绑在一起,并被视为单个逻辑摄像头设备。这些物理摄像头可以包括不同的焦距、不同的传感器类型(例如彩色相机和红外相机)等。由于这些物理摄像头协同工作,它们可以为开发者提供更丰富的功能和更灵活的图像处理能力。
二、源码调用链分析
1.回调设置的过程
\frameworks\base\core\java\android\hardware\camera2\CameraManager.java
public void registerAvailabilityCallback(@NonNull AvailabilityCallback callback, @Nullable Handler handler) {CameraManagerGlobal.get().registerAvailabilityCallback(callback, CameraDeviceImpl.checkAndWrapHandler(handler));
}
调用到CameraManager的内部类CameraManagerGlobal的方法registerAvailabilityCallback:
\frameworks\base\core\java\android\hardware\camera2\CameraManager.java
public void registerAvailabilityCallback(AvailabilityCallback callback,Executor executor) {synchronized (mLock) {/*1.连接到CameraService,如果已经连接,不执行任何操作。*/connectCameraServiceLocked();/*2.将设置的callback存入mCallbackMap中。mCallbackMap专门用于存储可用性回调以及执行它们的Executor。*/Executor oldExecutor = mCallbackMap.put(callback, executor);// For new callbacks, provide initial availability informationif (oldExecutor == null) {/*3.如果oldExecutor为空,说明是第一次设置该可用性回调。将当前已知的所有相机的状态触发设置的callback回调,以便使监听者了解当前所有相机状态。*/updateCallbackLocked(callback, executor);}// If not connected to camera service, schedule a reconnect to camera service.if (mCameraService == null) {/*4.如果mCameraService为空说明连接CameraService失败,计划一次新的重连尝试。*/scheduleCameraServiceReconnectionLocked();}}
}
到这里设置的可用性回调已经被存储到mCallbackMap当中,设置回调的流程完毕,后续相机状态变化触发回调时,将遍历mCallbackMap取出callback并执行相应的回调方法。
2.回调触发的过程
这里主要关注回调AvailabilityCallback中的onCameraAvailable和onCameraUnavailable方法的触发。我将从这两个方法最终被调用的地方开始往前梳理调用链。
发现方法最终被调用的地方只有一个,即为CameraManager的内部类CameraManagerGlobal的内部类中的private方法postSingleUpdate:
\frameworks\base\core\java\android\hardware\camera2\CameraManager.java
private void postSingleUpdate(final AvailabilityCallback callback,final Executor executor,final String id, final String physicalId, final int status) {/*略*/}
继续分析,发现调用postSingleUpdate的方法的地方为CameraManager的内部类CameraManagerGlobal中的另外3个private方法:
\frameworks\base\core\java\android\hardware\camera2\CameraManager.java
private void updateCallbackLocked(AvailabilityCallback callback,Executor executor) {/*略*/}
private void onStatusChangedLocked(int status, String id) {/*略*/}
private void onPhysicalCameraStatusChangedLocked(int status, String id, String physicalId) {/*略*/}
updateCallbackLocked方法只在注册回调时调用,忽略。关注onStatusChangedLocked和onPhysicalCameraStatusChangedLocked两个方法,从名称上可以看出这两个方法的用意,这里我们主要关注onStatusChangedLocked方法的调用。
发现调用onStatusChangedLocked方法的均为CameraManager的内部类CameraManagerGlobal中方法,包括以下4个方法:
\frameworks\base\core\java\android\hardware\camera2\CameraManager.java
private void connectCameraServiceLocked() {/*略*/}
public String[] getCameraIdListNoLazy() {/*略*/}
@Override
public void onStatusChanged(int status, String cameraId) throws RemoteException {/*略*/}
public void binderDied() {/*略*/}
其中onStatusChanged方法重写自CameraManagerGlobal实现的ICameraServiceListener.Stub接口,即该方法为相机框架中4个关键AIDL文件之一的CameraServiceListener.aidl中定义的方法,通过CameraServiceListener.aidl,CameraService可以调用CameraManager中的方法。(相机框架4个关键AIDL文件包括:ICameraService.aidl、ICameraDeviceCallback.aidl、ICameraDeviceUser.aidl、ICameraServiceListener.aidl)
所以现在直接追溯到CameraService中通过AIDL调用onStatusChanged的地方:
void CameraService::updateStatus(StatusInternal status, const String8& cameraId,std::initializer_list<StatusInternal>rejectSourceStates) {/*……略……*/for (auto& listener : mListenerList) {/*……略……*/listener->getListener()->onStatusChanged(mapToInterface(status),String16(cameraId));/*……略……*/}/*……略……*/
}
未完待续……