CameraService笔记
cameraservice
- camera 结构图
- 1. 启动CameraServer
- 1.1 注册media.camera服务
- 1.2 构造CameraService
- 1.3 CameraService::onFirstRef
- 1.4 CameraService::enumerateProviders:前置准备知识
- 1.4 CameraService::enumerateProviders:Provider和Device初始化
- 1.4.1 initializeHidlProvider:HIDL Provider初始化
- 1.4.2 addDevice:HIDL Device初始化
- 1.4.2.1 initializeDeviceInfo
- 1.4.2.2 new HidlDeviceInfo3
- 1.4.2.3 修复/更新 mCameraCharacteristics
- 1.4.5 CameraDeviceStatus:前置准备知识
- 1.4.5 CameraDeviceStatus的处理流程
- 开始处理CachedStatus回调
- 1.4.6 CameraID和CameraDevice相关的变量
- 1.4.7 AIDL CameraProvider和CameraDevice初始化
- 1.4.8 初始化VendorTags, Flashlight和PerfClass
- 2. Java层 Camera Framework AIDL
- 2.1 ICameraService.aidl
- 2.2 ICameraServiceListener.aidl
- 2.3 ICameraDeviceUser.aidl
- 2.4 ICameraDeviceCallbacks.aidl详解
- 2.5 Parcel对象相关的AIDL
- 3. libcameraservice
- 3.1 C++层CameraService总体架构
- 3.2 C++层CameraService和Client架构
- 3.3 C++层CameraService的Device架构介绍
- 3.4 C++层CameraService的API1和API2调用HAL3流程
- 4. C++层CameraService的Camera2流程
- 1. C++层Camera2获取CameraCharacteristic
- 2. C++层Camera2获取addListener
- 3. C++层Camera2 OpenCamera
camera 结构图
1. 启动CameraServer
1.1 注册media.camera服务
将media.camera注册到ServiceManager。
1.2 构造CameraService
- AttributionAndPermissionUtilsEncapsulator:
- mCameraServiceProxyWrapper:
- mEventLog:打开或者关闭camera的event log;
- mNumberOfCameras:camera的数量;
- mNumberOfCamerasWithoutSystemCamera:剔除systemCamera以后得数量;
- mSoundRef:控制mAudioRestriction;
- mInitialized:是否已经做了mInitialized;
构造完之后会执行onFirstRef。
1.3 CameraService::onFirstRef
- notifier.noteResetCamera、notifier.noteResetFlashlight:统计camera、Flashlight的使用时长,重置统计使用时长的Timer;
- enumerateProviders:跟hal进程交互;
- mUidPolicy->registerSelf:registerSelf–>registerUidObserverForUids,UidPolicy向ActivityManger调用registerUidObserverForUids,监听使用camera的UID变化,如果UID不是active,不允许使用camera,为了保护用户隐私;
- mSensorPrivacyPolicy->registerSelf:判断SensorPrivacy是否启用了隐私,如果启用就阻止所有进程使用camera;
- mAppOps.setCameraAudioRestriction`:设置声音;
- hcs->registerAsService:注册C++层的HidlCameraService,让vndk可以获取到CameraServer,向hal提供访问CameraServer的接口;
- mCameraServiceProxyWrapper->pingCameraServiceProxy:CameraServiceProxy会通知CameraService是否有user switch和device state(更新sensor orientation);
- CameraServiceProxyWrapper是system_server进程中的一个服务,协助处理多用户、usb camera、折叠屏等场景;
1.4 CameraService::enumerateProviders:前置准备知识
看enumerateProviders前,先了解前置准备知识:
- 1.4.1-p1 CameraHALProvider接口
- 1.4.1-p2 CameraService与CameraProviderManager的关系
1.4.1 准备知识:CameraHALProvider接口
CameraHALProvider接口分成HIDL和AIDL两种。
代码路径:/hardware/interfaces/camera/
AIDL代码:
HIDL代码:
主要接口:
作用:
- ICameraProvider:由CameraHALProvider实现,帮助cameraserver调到CameraHALProvider;管理多个ICameraDevice;
- ICameraProviderCallback:由CameraServer实现,帮助CameraHALProvider调到cameraserver;
- ICameraDevice:代表并管理某一个CameraDevice(Physical Camera、Logical Camera);
- ICameraDeviceSession:打开camera后,hal device操作device;
- ICameraDeviceCallback:帮助device回调到hal device;
创建时机:
初始化时,创建ICameraProvider、ICameraDevice;
open camera/close camera时,创建ICameraDeviceSession;
关系:通过ICameraProvider获取ICameraDevice,通过ICameraDevice获取ICameraDeviceSession;
1.4.1-p2 准备知识:CameraService与CameraProviderManager的关系
-
CameraService通过CameraProviderManager管理Camera HAL Provider;
-
Camera HAL Provider通过CameraProvicerManager::StatusListener回调到CameraService;
1.4.1-p3 准备知识:ProviderInfo
CameraProviderManager::ProviderInfo -
CameraProviderManager抽象出ProviderInfo来屏蔽HIDL和AIDL Provider的差异,将差异部分交给HidlProviderInfo和AidlProviderInfo去处理。
前置准备知识已经看完了,开始看enumerateProviders
1.4 CameraService::enumerateProviders:Provider和Device初始化
-
什么时候调用enumerateProviders
- CameraServer进程启动时调用CameraService::onFirstRef;
- CameraServer进程启动后,有新的Provider注册到ServiceManager时调用CameraService::onNewProviderRegistered;
-
enumerateProviders
- 创建CameraProviderManager,并调用initialize完成初始化;
- 初始化VendorTags;
- 初始化Flashlight,完成枚举动作;
- 获取所有deviceId,把deviceId设置成PRESENT,即设置成可用状态;
- 针对
主
前/后摄,为SPerfClass过滤CameraCharacteristics;- SPerfClass是为不同安卓手机定义的Performmance的级别,为了满足CDD要求过滤CameraCharacteristics;
-
CameraHALProvider初始化流程
Add Hidl Provider重要流程:- 在registerForNotifications方法中,向hwservicemanager/ServiceManager.cpp注册ICameraProvider的HidlService的Notification,如果HidlService注册到hwservicemanager;
- registerForNotifications的回调方法是onRegistration,如果收到onRegistration回调通知,会调到CameraServer::onNewProviderRegistered,告诉CameraServer注册成功,也会做addHidlProviderLocked操作;
- 用listServices方法查找hwservicemanager中有多少是ICameraProvider的HidlService,然后做addHidlProviderLocked操作,创建HidlProviderInfo;
- 在registerForNotifications方法中,向hwservicemanager/ServiceManager.cpp注册ICameraProvider的HidlService的Notification,如果HidlService注册到hwservicemanager;
- registerForNotifications方法的作用:
- CameraServer监听Provider,防止hal进程比CameraServer启动慢;
- 防止hal进程发生crash重启,hal进程会重启并重新注册到HwServiceManager,CameraServer会收到hal进程重新注册回调;
1.4.1 initializeHidlProvider:HIDL Provider初始化
HidlProviderInfo::initializeHidlProvider
- castFrom:判断ICameraProvider的mMinorVersion;
- setCallback:Cameraserver接收hal的ICameraProviderCallback的回调;
- linkToDeath:这是监听HidlService挂掉,上面的onRegistration是监听注册成功,在HidlProviderInfo::serviceDied方法处理HidlService挂掉后的异常,从mProviders 中删掉Provider;
- notifyDeviceStateChange:通知HAL进程,当前摄像头的状态(NORMAL/BACK_COVERED被盖住/FRONT_COVERED前置被盖住/FOLDED折叠状态,可以一次性通知多个状态),只有在Provider 2.5及之后的版本才有;
- setUpVendorTags:调用ICameraProvider的getVendorTags方法拿到VendorTagSection,然后创建VendorTagDescriptor,通过VendorTagDescriptor就能知道有哪些Vendor Tag了;
- interface->getCameraIdList:获取当前Provider有多少Camera Device,解析出Camera ID存放在mProviderPublicCameraIds(interface = ICameraProvider);
- getConcurrentCameraIdsInternalLocked:如果Provider >= 2.6,获取哪些Camera可以同时做ConfigureStream,存放在mConcurrentCameraIdCombinations;
- interface->isSetTorchModeSupported:判断是否支持手电筒,结果存放在mSetTorchModeSupported;
- initializeProviderInfoCommon:完成Device的初始化;
1 initializeProviderInfoCommon
CameraProviderManager::ProviderInfo::initializeProviderInfoCommon
主要完成2件事情:
- 调用addDevice将CameraDevice保持在mDevices中;
- 处理cachedStatus回调,就是初始化Provider过程中,Device状态发生变化,先把状态缓存起来,初始化Provider结束后再做状态变化操作;
1.4.2 addDevice:HIDL Device初始化
CameraProviderManager::ProviderInfo::addDevice
- 检查CameraDevice的版本是否正确:
- 根据device的name解析出的Camera ID、MajorVersion、IPCTransport都必须唯一;
- IPCTransport::HIDL的对应的Device MajorVersion必须为3,IPCTransport::AIDL的对应的Device MajorVersion必须为1;
- initializeDeviceInfo:初始化Camera Device Info,由AIDLProviderInfo/HIDLProviderInfo实现;(重点)
- notifyDeviceStateChange:根据手机状态去更新ANDROID_SENSOR_ORIENTATION,这里的DeviceState不是手机摄像头状态,是指手机状态;
- isAPI1Compatible:判断是否支持API1,根据 ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT、ANDROID_REQUEST_AVAILABLE_CAPABILITIES判断;
- 如果ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT是NIR(Near Infrared Filter,近红外sensor,捕获波长大约在750纳米和1400纳米之间的光线),则这种sensor不支持API1
1.4.2.1 initializeDeviceInfo
HidlProviderInfo::initializeDeviceInfo
- 获取到ICameraDevice的实例:调用ICameraProvider的getCameraDeviceInterface_V3_x获取到ICameraDevice的实例,不会每次都调用Provider接口,HidlDeviceInfo3会缓存ICameraDevice实例;
- cameraInterface->getResourceCost:调用ICameraDevice的getResourceCost获取到ResourceCost,ResourceCost是指统计打开camera消耗的资源得分,超过100就禁止打开;
- new HidlDeviceInfo3:处理静态信息,比如获取SystemCameraKind和修复/更新mCameraCharacteristics(重点)
1.4.2.2 new HidlDeviceInfo3
- 获取CameraCharacteristics:调用getCameraCharacteristics获取metadata放入mCameraCharacteristics(Characteristics:静态信息)
- 获取DeviceStateOrientationMap:获取 ANDROID_INFO_DEVICE_STATE_ORIENTATIONS的值,保存在mDeviceStateOrientationMap
- 获取到mSystemCameraKind:调用getSystemCameraKind获取到mSystemCameraKind
- 如果Capability是ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA,则返回SystemCameraKind::HIDDEN_SECURE_CAMERA
- 如果Capability有ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,则返回SystemCameraKind::SYSTEM_ONLY_CAMERA
- 其他情况返回SystemCameraKind::PUBLIC
- 修复/更新mCameraCharacteristics:fixupMonochromeTags、addDynamicDepthTags、deriveHeicTags、addRotateCropTags、addPreCorrectionActiveArraySize、overrideZoomRatioTags、fixupTorchStrengthTags、queryPhysicalCameraIds(重点)
- 修复/更新未Public出去的PhysicalCameraCharacteristics: overrideZoomRatioTags(重点)
1.4.2.3 修复/更新 mCameraCharacteristics
- CameraProviderManager::ProviderInfo::DeviceInfo3::fixupMonochromeTags(黑白camera)
- 如果Camera Device < 3.5 并且包含Monochrome(HAL 3.3新增)
- 更新ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT为ANDROID_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT_MONO
- 删除不需要的metadata(Static Keys,Request Keys,Result Keys)
- ANDROID_SENSOR_BLACK_LEVEL_PATTERN的4个通道设为同一个值。
- CameraProviderManager::ProviderInfo::DeviceInfo3::addDynamicDepthTags(景深信息)
- 是指包含Depth信息的JPEG,在Camera Framework完成Jpeg和Depth Buffer的合成,在这里填相关静态Metadata,HAL不会填,筛选规则是:Jpeg和Depth Size相同(或宽高相近)的Streams
- ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STREAM_CONFIGURATIONS
- ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS
- ANDROID_DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS
- CameraProviderManager::ProviderInfo::DeviceInfo3::deriveHeicTags
- HEIC是Camera Framework调用Encoder的接口压成HEIC的,因此相关静态Metadata需要补上
- ANDROID_HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS
- ANDROID_HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS
- ANDROID_HEIC_AVAILABLE_HEIC_STALL_DURATIONS
- CameraProviderManager::ProviderInfo::DeviceInfo3::addRotateCropTags
- 如果ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES没有填,则至少填一个值:ANDROID_SCALER_ROTATE_AND_CROP_NONE
- ameraProviderManager::ProviderInfo::DeviceInfo3::addPreCorrectionActiveArraySize
- 如果ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE没有填,则获取ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE的值填进去
- ZoomRatioMapper::overrideZoomRatioTags
- 如果HAL不支持ANDROID_CONTROL_ZOOM_RATIO_RANGE,则通过ANDROID_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM来构造一个ZoomRatioRange更新到ANDROID_CONTROL_ZOOM_RATIO_RANGE。并增加ZoomRatio相关的Static/Request/Result Keys
- CameraProviderManager::ProviderInfo::DeviceInfo3::fixupTorchStrengthTags
- 如果没有填ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,则填成1
- 如果没有填ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,则填成1
- CameraProviderManager::ProviderInfo::DeviceInfo3::queryPhysicalCameraIds
- 如果支持LogicalCamera,则从ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS获取到PhysicalCameraIds放到mPhysicalIds
- 修复/更新 PhysicalCamera Characteristics
- 如果支持LogicalCamera
- getPhysicalCameraCharacteristics
- overrideZoomRatioTags
1.4.5 CameraDeviceStatus:前置准备知识
看CameraDeviceStatus前,先了解前置准备知识:
- p1 CameraDeviceStatus流程
- p2 HIDL Camera Device Status
- p3 Framework Camera Device Status
- p4 Logical VS Physical VS Logical MultiCam
p1. CameraDeviceStatus流程
p2. HIDL Camera Device Status
代码位置:hardware/interfaces/camera/common/aidl/android/hardware/camera/common/CameraDeviceStatus.aidl
- NOT_PRESENT: CameraDevice没有连接物理设备;
- ENUMERATING: CameraDevice已经连接物理设备,暂时还不能使用,等enumerateProviders结束;
- PRESENT: CameraDevice已经连接物理设备,可以使用,调用getCameraIdList可以发现该CameraDevice;
p3. Framework Camera Device Status
代码位置:frameworks/av/camera/aidl/android/hardware/ICameraServiceListener.aidl
- STATUS_NOT_PRESENT: CameraDevice没有连接物理设备;
- STATUS_PRESENT: CameraDevice已经连接物理设备,可以被使用;
- STATUS_ENUMERATING: CameraDevice已经连接物理设备,暂时还不能使用,需要等enumerateProviders结束;
- STATUS_NOT_AVAILABLE:其他APP在占用CameraDevice;
- STATUS_UNKNOWN:仅用于初始化变量,无意义;
p4. Logical VS Physical VS Logical MultiCam
-
APP只能看见LogicalCameraId或者LogicalCameraDevice,如果APP看到的是LogicalMultiCamera,逻辑上是一个CameraDevice,但是有多个CameraDevice硬件;
-
logical 和 physical有值的对应关系。
- APP能看到5颗Camera,实际只有3颗物理Camera
- Logical 0,1,2都对应一个PhysicalCamera;
- Logical multicam 3和4分别对应2个PhysicalCamera;
1.4.5 CameraDeviceStatus的处理流程
- 在providerManager中用mDevices管理cameraDevice的状态,在cameraservice里面通过mCameraStates管理cameraDevice的状态。
1 initializeProviderInfoCommon
CameraProviderManager::ProviderInfo::initializeProviderInfoCommon:
-
initializeProviderInfoCommon主要完成2件事情:
- 调用addDevice将CameraDevice保持在mDevices中;
- 处理CachedStatus回调;
前面的课程已经介绍了addDevice的逻辑,这里介绍处理Cached Status回调。
-
什么时候会有Cache Status:
- 在CameraServer初始化Provider过程中,HAL通知CameraService的CameraDeviceStatus发生physicalCameraDeviceStatusChange或cameraDeviceStatusChange(logical)
开始处理CachedStatus回调
1 physicalCameraDeviceStatusChangeLocked
CameraProviderManager::ProviderInfo::physicalCameraDeviceStatusChangeLocked:
1. 拿logical cameraDeviceId;
2. 检查physicalCameraDevice是否合法;
参数:
cameraDeviceName: logical cameraDeviceName;
physicalCameraDeviceName: physical cameraDeviceName;
2 onDeviceStatusChanged
CameraService::onDeviceStatusChanged
三个参数的方法是physical使用
SystemCameraKind:
PUBLIC: 所有拥有Camera权限的进程可使用,比如三方相机;
SYSTEM_ONLY_CAMERA: 系统自带相机,三方APP不可用,且必须有SYSTEM_CAMERA权限;
HIDDEN_SECURE_CAMERA: 只给vender分区(HAL进程)使用,hal层的相机,比如人脸解锁;
3 cameraDeviceStatusChangeLocked
CameraProviderManager::ProviderInfo::cameraDeviceStatusChangeLocked
- 在mDevices中根据cameraDeviceName找到对应的DeviceInfo;
- 如果找到,状态为NOT_PRESENT,执行removeDevice;
- 如果没有找到,状态为PRESENT,执行addDevice;
- reCacheConcurrentStreamingCameraIdsLocked;
- 返回cameraId;
4 onDeviceStatusChanged
CameraService::onDeviceStatusChanged
- getCameraState(cameraId):获取cameraDevice的状态;
- 如果获取的state为空,执行addStates、updateStatus;
- 如果state不为空,newStatus == StatusInternal::NOT_PRESENT;
- 如果是,执行updateStatus,把cameraId的状态更新成NOT_PRESENT;
- logDeviceRemoved: cameraserver里的logEvent都可以用dumpsys media.camera打印出来;
- removeClientsLocked,包括online和offline;
- disconnectClients,包括onlin和offline;
- removeStates(cameraId);
- 如果不是,并且oldStatus == StatusInternal::NOT_PRESENT,执行添加状态;addStates(cameraId);执行updateStatus,把cameraId的状态更新成NOT_PRESENT;
- 如果是,执行updateStatus,把cameraId的状态更新成NOT_PRESENT;
CameraService::onDeviceStatusChanged,两个参数的方法是logical使用。
5 updateStatus
CameraService::updateStatus
- 获取cameraId状态
- getSystemCameraKind:是系统分区的camera,还是vender分区的camera;
- getCameraCharacteristics;
- state->updateStatus;
- 如果新的状态不是ENUMERATING,需要检查这颗camera的TorchModeStatus是否发生变化,如果有变化则调用onTorchStatusChangedLocked,最终会通过i->getListener()->onTorchStatusChanged调到app;
- 调用notifyPhysicalCameraStatusLocked,如果拿不到logicalCameraIds则不会调用这个方法,调这个方法的原因是一个PhysicalCamera可能会映射到多个LogicalCamera;
- 针对每一个Listener调用listener->getListener()->onStatusChanged,调到app;
6 addStates
CameraService::addStates
- 有一个新的camera来了,需要构建一个cameraStates对象,步骤:
- mCameraProviderManager->getResourceCost;
- mCameraProviderManager->getSystemCameraKind;
- mCameraProviderManager->isLogicalCamera;
- 执行updateCameraNumAndIds,更新mCameraStates、mTorchStatusMap、mNumberOfCameras、mNormalDeviceIds: 能兼容api1和api2;
- logDeviceAdded: 打印event log;
7 removeStates
CameraService::removeStates
- updateCameraNumAndIds:更新cameraNumber、cameraId;
- mCameraProviderManager->getCameraCount();
- 更新mNumberOfCameras、mNormalDeviceIds;
- 从mTorchStatusMap、mCameraStates中erase cameraId;
1.4.6 CameraID和CameraDevice相关的变量
1 CameraProviderManager里面CameraId、CameraDevice相关的变量
- CameraProviderManager.cpp:
- mProviders:表示所有的ProviderInfo,包含HIDLProviderInfo、AIDLProviderInfo;
- mDevices:表示所有的DeviceInfo,保存支持的cameraDevice;
- mPublicCameraIds:表示所有的存放该Provider的PublicCameraIds,它和下面的mProviderPublicCameraIds相同;
- mProviderPublicCameraIds:表示provider初始的CameraIds,来自getCameraIdList;
- mUniqueCameraIds:存放当前Provider所有可用的CameraDevice的CameraID,cameraId会在addDevice时增加,removeDevice时减少;
- mUniqueAPI1CompatibleCameraIds:存放该Provider所有兼容API1 Device的CameraId;
- mDevices:表示所有的DeviceInfo,保存支持的cameraDevice;
- mProviders:表示所有的ProviderInfo,包含HIDLProviderInfo、AIDLProviderInfo;
2 CameraService里面CameraID和CameraDevice相关的变量
CameraService里面的CameraID和CameraDevice都来自CameraProviderManager,下面是CameraService的变量来自CameraProviderManager的哪些变量;
-
mNumberOfCameras、mNumberOfCamerasWithoutSystemCamera:来自所有Provider的mUniqueCameraIds总和,当前hal支持的所有camera的数量,去除HIDDEN_SECURE_CAMERA;
- mNumberOfCameras:表示有多少颗cameraDevice,只会取PUBLIC、SYSTEM_ONLY_CAMERA类型,去除HIDDEN_SECURE_CAMERA类型;
- mNumberOfCamerasWithoutSystemCamera:表示有多少颗cameraDevice,只会取PUBLIC类型,去除HIDDEN_SECURE_CAMERA、SYSTEM_ONLY_CAMERA类型;
- 使用的地方CameraService::updateCameraNumAndIds --> mCameraProviderManager->getCameraCount;
-
mNormalDeviceIds、mNormalDeviceIdsWithoutSystemCamera:来自所有Provider的mUniqueAPI1CompatibleCameraIds总和,会去除HIDDEN_SECURE_CAMERA,针对Logical Multi-Camera每个Facing只暴露一个logicalCameraId出去;
- 使用的地方:CameraService::updateCameraNumAndIds --> mCameraProviderManager->getAPI1CompatibleCameraDeviceIds;
- getAPI1CompatibleCameraDeviceIds:处理兼容API1的CameraDeviceId;把所有的DeviceId过滤一遍,把HIDDEN_SECURE_CAMERA、Logical Multi-Camera类型去除,然后再把DeviceId分成两组,分成publicDeviceId和systemDeviceId依次写入deviceIds;
-
mCameraStates:当定义LogicalDevice的onDeviceStatusChanged时,会执行addStates往mCameraStates添加state;
- 是一个map,key:cameraId, value:cameraState,对变量操作的方法:removeStates、addStates;
-
mTorchStatusMap:定义LogicalDevice的onDeviceStatusChanged;
- 是一个map,key:cameraId, value:torchStatus,操作变量的方法:removeStates、addStates,这两个变量是跟mCameraStates走的;
-
mPerfClassPrimaryCameraIds:mUniqueCameraIds;
- 表示根据当前CameraDevice的Perform等级把PrimaryCameraId存入mPerfClassPrimaryCameraIds,参考前面的mNormalDeviceIdsWithoutSystemCamera;
- 操作变量的方法:filterSPerfClassCharacteristicsLocked
1.4.7 AIDL CameraProvider和CameraDevice初始化
AIDL Camera Provider初始化
CameraProviderManager::tryToAddAidlProvidersLocked
- 每个AIDL Provider都要注册一次sm->registerForNotifications,多个HIDL只会注册一次;
- tryToInitializeAidlProviderLocked–>initializeAidlProvider;
- initializeAidlProvider:
- 不需要像HIDL判断版本,aidl只有一个版本,直接调用setCallback方法,接收ICameraProvider的回调;
- 调用AIBinder_linkToDeath方法,监听binderDied方法,处理Hal进程挂掉后的异常;HIDL是监听serviceDied方法处理hal挂掉后的异常;
- notifyDeviceStateChange:更新state
- setUpVendorTags
- getCameraIdList
- getConcurrentCameraIdsInternalLocked
- 直接将mSetTorchModeSupported = true;HIDL调用isSetTorchModeSupported,判断是否有一个cameraDevice是否支持TorchMode,AIDL不需要,因为在各自的device会判断是否支持touch;
- initializeProviderInfoCommon
AIDL CameraDevice初始化
AidlProviderInfo::initializeDeviceInfo,AIDL初始化CameraDevice和HIDL初始化CameraDevice的流程一样。
- 获取ICameraDevice的实例:调用ICameraProvider的getCameraDeviceInterface获取到ICameraDevice的实例;
- startDeviceInterface–>interface->getCameraDeviceInterface
- 调用ICameraDevice的getResourceCost获取到ResourceCost;
- 创建AidlDeviceInfo3:处理静态信息,比如获取SystemCameraKind和修复/更新mCameraCharacteristics;
创建AidlDeviceInfo3完成5件事情
AidlDeviceInfo3::AidlDeviceInfo3
- 获取CameraCharacteristics:调用getCameraCharacteristics对mCameraCharacteristics赋值;
- 获取DeviceStateOrientationMap:获取ANDROID_INFO_DEVICE_STATE_ORIENTATIONS的值,保存在mDeviceStateOrientationMap;
- 获取到mSystemCameraKind:调用getSystemCameraKind获取到mSystemCameraKind – 如果Capability是ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SECURE_IMAGE_DATA,则返回SystemCameraKind::HIDDEN_SECURE_CAMERA – 如果Capability有ANDROID_REQUEST_AVAILABLE_CAPABILITIES_SYSTEM_CAMERA,则返回SystemCameraKind::SYSTEM_ONLY_CAMERA – 其他情况返回SystemCameraKind::PUBLIC
- 修复/更新 mCameraCharacteristics:fixupMonochromeTags、addDynamicDepthTags、deriveHeicTags、addRotateCropTags、addPreCorrectionActiveArraySize、overrideZoomRatioTags、fixupTorchS
- 修复/更新 未Public 出去的PhysicalCamera Characteristics:
- overrideZoomRatioTags
1.4.8 初始化VendorTags, Flashlight和PerfClass
1 创建VendorTagDescriptorCache
主要工作:创建VendorTagDescriptorCache,把provider的VendorTag存进去。
VendorTag:是vender厂商自定义的metadata,这种情况会用到vendorTag。vendor厂商定义了metadata之后,会有venderTag的管理者,管理metadata供app、framework使用。
enumerateProviders–>mCameraProviderManager->setUpVendorTags:
- 创建VendorTagDescriptorCache
- VendorTagDescriptorCache::setAsGlobalVendorTagCache:将provider里面的mProviderTagid和mVendorTagDescriptor放入VendorTagDescriptorCache里面,然后把当前的tagCache setAsGlobalVendorTagCache,把对应的vendorTag的Ops传入metadata类里面去。
VendorTagDescriptorCache是管理venderTag的Manager,管理厂商自定义的metadata供app、framework使用,管理不同Provider里面的VendorTagDescriptor,VendorTagDescriptor维护管理所有VendorTags的Section、Name、Type,ID之间的关系:
key | value |
---|---|
vendorId1 | VendorTagDescriptor1 |
2 Flashlight初始化
主要工作:判断每颗camera里面是否有flashUnit这个硬件单元。
CameraServer通过CameraFlashlight来管理各个CameraDevice的Flashligh:
通过CameraFlashlight::findFlashUnits完成Flashlight的初始化,流程如下:
CameraFlashlight::findFlashUnits:
- mProviderManager->getCameraDeviceIds:拿到所有支持的Id;
- 遍历所有cameraIds,如果cameraId在mHasFlashlightMap不存在,执行createFlashlightControl;
- createFlashlightControl:查询CameraProviderManager是否支持设置TorchMode,如果支持则创建ProviderFlashControl;
- 执行mFlashControl->hasFlashUnit(id, &hasFlash):判断是否支持Flash,更新hasFlash,最终是从ProviderInfo的mCameraCharacteristics读取ANDROID_FLASH_INFO_AVAILABLE来给mHasFlashUnit赋值;
- 执行mHasFlashlightMap.add(id, hasFlash):把cameraId和是否支持Flash写入mHasFlashlightMap;
3 为SPerfClass过滤Characteristics
主要工作:针对performance_class做jpeg size以及Dynamic Depth size的过滤,把小于1080p的全部过滤掉。
CameraService::filterSPerfClassCharacteristicsLocked
执行条件:ro.odm.build.media_performance_class >= 31 (android S)
执行动作:针对主后置和主前置,过滤掉小于1080p的JPEG尺寸
CTS(SPerfClassTest.java):testSPerfClassJpegSizesByCamera
CameraService::filterSPerfClassCharacteristicsLocked
流程:
- 初始化firstRearCameraSeen、firstFrontCameraSeen
- 遍历mNormalDeviceIdsWithoutSystemCamera,去掉SystemCamera
- getDeviceVersion获取到Facing
- 如果Facing是back或者front且是第一次执行,调用mCameraProviderManager->filterSmallJpegSizes(cameraId)
- filterSmallJpegSizes:更新jpeg和Dynamic Depth的如下三个Tag,过滤掉小于1080P的STREAM_CONFIGURATIONS、MIN_FRAME_DURATIONS、STALL_DURATIONS
2. Java层 Camera Framework AIDL
1 文件路径
/frameworks/av/camera/aidl/android/hardware/
2 AIDL产生的库/文件
-
libcamera client.so:包含客户端代码,也包含服务端代码;
- 如果是客户端代码,会被Libcamera2ndk.so实现;
- 如果是服务端代码,会被Libcameraservice.so实现,比如Binder客户端framework-minus-apex.jar的IcameraService的connect方法会先调到Binder服务端libcamera_client.so的IcameraService的connect然后再调用到libcameraservice.so的connect方法;
-
AIDL产生的Java源文件:
- out\soong.intermediates\frameworks\base\framework-minus-apex\android_common\gen\aidl\ aidl36.srcjar
-
AIDL产生的C++源文件:
- out\soong.intermediates\frameworks\av\camera\libcamera_client\android_arm64_armv8-a_shared_cfi\gen\aidl\android\hardware
3 AIDL核心类
ICameraService.aidl:Cameraserver进程对外提供的接口入口;
ICameraServiceListener.aidl:ICameraService的回调类,CameraService相关状态通知到上层APP;
ICameraDeviceUser.aidl:CameraDevice的封装接口,用于操作一颗CameraDevice;
ICameraDeviceCallbacks.aidl:CameraDevice的回调,通知上层APP;
AIDL核心类之间的调用关系如下图所示:
2.1 ICameraService.aidl
1 ICameraService.aidl类图
ICameraService.aidl产生的Java或C++代码,相关类图如下所示:
java端的ICameraService.Stub:是抽象类,如果实现Stub的是其他Java端进程,调用者是其他java端、c++端,比如c++端回调的ICameraServiceLisenter、CameraDeviceCallback,java端要实现这个Stub,c++端调Bp端的BpCameraService,会调到Stub;
2 调用端获取ICameraService对象:
Java端获取ICameraService.Stub.Proxy对象:
//cameraServiceBinder就是mRemote变量
IBinder cameraServiceBinder = ServiceManager.getService("media.camera");
//返回的是ICameraService.Stub.Proxy,asInterface传入的是就是上面的mRemote
ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);
C++端获取BpCameraService对象:
//binder就是BnCameraService
sp<IBinder> binder = sm->getService(String16("media.camera"));
//mCameraService是BpCameraService
mCameraService = interface_cast<hardware::ICameraService>(binder);
- Interface_cast获取的是BpCameraService的实例,但是从ServiceManager获取的binder是BnCameraService的实例。
/frameworks/native/include/binder/IInterface.h
//第三个参数是BP类型
DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(PARENT::I##INTERFACE, I##INTERFACE, PARENT::Bp##INTERFACE)//构造Bp类型的对象BpCameraService
::android::sp<ITYPE> ITYPE::asInterface(const ::android::sp<::android::IBinder>& obj) {::android::sp<ITYPE> intr;if (obj != nullptr) {intr = ::android::sp<ITYPE>::cast(obj->queryLocalInterface(ITYPE::descriptor));if (intr == nullptr) {intr = ::android::sp<BPTYPE>::make(obj);}}return intr;
}inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{return INTERFACE::asInterface(obj);
}
3 ICameraService.aidl主要的接口详解:
- int getNumberOfCameras(int type);
- 获取当前平台支持多少颗Camera,废弃;
- CameraInfo getCameraInfo(int cameraId);
- 获取某颗Camera的基本信息(facing和orientation),API2不使用该API;
- ICamera connect()
- Open某颗Camera,获取到ICamera 实例,API2不使用该API;
- ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks, String cameraId, String opPackageName, String featureId, int clientUid, int oomScoreOffset, int targetSdkVersion);
- Open Camera,获取到ICameraDeviceUser实例;
- callbacks:回调CameraDevice的状态信息;
- featureId:AppContext里面获取的属性Tag,权限管理时传入OpManager里去;
- CameraStatus[] addListener(ICameraServiceListener listener);
- 注册Listener,监听CameraService状态变化,比如CameraDevice、Torch变化;
- ConcurrentCameraIdCombination[] getConcurrentCameraIds();
- 获取可以并发访问的Camera ID组合;
- boolean isConcurrentSessionConfigurationSupported( in CameraIdAndSessionConfiguration[] sessions, int targetSdkVersion);
- 同时使用多颗Camera时,判断并发SessionConfiguration是否支持;
- void removeListener(ICameraServiceListener listener);
- 删除Listener,取消监听CameraService状态变化;
- CameraMetadataNative getCameraCharacteristics(String cameraId, int targetSdkVersion);
- 获取指定Camera的静态CameraMetadata;
- VendorTagDescriptor getCameraVendorTagDescriptor();
- 获取VendorTagDescriptor,在CameraMetadataNative解析Vendor Tag时需要用到;
- VendorTagDescriptorCache getCameraVendorTagCache();
- 获取VendorTagDescriptorCache,其中存放不同VendorID的VendorTagDescriptor,在CameraMetadataNative解析Vendor Tag时需要用到
- boolean supportsCameraApi(String cameraId, int apiVersion);
- 判断当前平台是否支持HAL3;
- boolean isHiddenPhysicalCamera(String cameraId);
- 判断指定的Camera是否是隐藏的PhysicalCamera,针对隐藏的PhysicalCamera,CamcorderProfile可能不可用,因此使用Stream configurationMap来获取最大录像size(MandatoryStreamCombination)。
- ICameraInjectionSession injectCamera(String packageName, String internalCamId, String externalCamId, in ICameraInjectionCallback CameraInjectionCallback);
- 注入外部Camera来取代内部Camera,同一颗CameraID可以在Internal或External Camera间切换。
- void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);
- 控制手电筒模式的ON/OFF
- void turnOnTorchWithStrengthLevel(String cameraId, int strengthLevel, IBinder clientBinder);
- 调整手电筒的强度;
- int getTorchStrengthLevel(String cameraId);
- 获取当前手电筒模式的强度。
- oneway void notifySystemEvent(int eventId, in int[] args);
- 向CameraService通知系统操作事件(多用户切换、USB设备插拔事件),CameraServiceProxy调用。
- oneway void notifyDisplayConfigurationChange();
- 向CameraService通知Display窗口配置发生变化,CameraServiceProxy调用;
- oneway void notifyDeviceStateChange(long newState);
- 向CameraService通知设备状态发生变化(如折叠屏发生折叠,前镜头/后镜头被挡住),CameraServiceProxy调用。
以上Api只有connectDevice需要openCamera,其他方法不需要openCamera可以直接调用。
2.2 ICameraServiceListener.aidl
1 ICameraServiceListener.aidl类图
2 Android AIDL oneway修饰符
在 Android AIDL中,oneway 是一种修饰符,用于声明一个方法是单向的(one-way)。
使用oneway修饰符声明的方法不会阻塞调用线程,而是立即返回并在后台运行,因此不需要等待方法执行完成。
这种方式适用于客户端和服务端之间不需要进行同步通信的情况,例如通知服务端某项任务已经完成。
需要注意的是,在客户端调用带有oneway修饰符的方法时,无法得知方法是否返回成功或失败,因为该方法会立即返回,而不会等待服务端响应。因此,建议将 oneway 修饰符仅用于不需要接收服务端响应的方法。
3 ICameraServiceListener.aidl接口详解
- oneway void onTorchStatusChanged(int status, String cameraId)
- 回调通知FlashTorch模式的状态变化;
- oneway void onTorchStrengthLevelChanged(String cameraId, int newTorchStrength)
- 回调通知FlashTorch的强度发生变化;
- oneway void onCameraAccessPrioritiesChanged()
- 当进程的adj或前后台状态发生变化时,会回调该方法,CameraService的任何一个client进程。
- oneway void onCameraOpened(String cameraId, String clientPackageId)
- 回调通知某个client打开了某颗Camera,每一个client都有包名。
- client需要有android.permission.CAMERA_OPEN_CLOSE_LISTENER权限。
- oneway void onCameraClosed(String cameraId)
- 回调通知某颗Camera被关闭了。
- 需要有android.permission.CAMERA_OPEN_CLOSE_LISTENER权限。
2.3 ICameraDeviceUser.aidl
1 ICameraDeviceUser.aidl是什么
- 获取:CameraApp执行openCamera,Java层CameraFWK调用ICameraService.aidl的connectDevice方法返回ICameraDeviceUser对象。
ICameraDeviceUser代表的就是一颗CameraDevice
,后续的Camera操作流程就是基于ICameraDeviceUser对象,所有的拍照、创建session都是通过ICameraDeviceUser执行。
2 ICameraDeviceUser.aidl类图&调用
- java层ICameraDeviceUser和c++层CameraDeviceClient都有相同的方法名互相对应。
3 ICameraDeviceUser.aidl接口详解:
java层CameraDevice代码路径:framework/base/core/java/android/hardware/camera2/CameraDevice.java
CameraDevice的createCaptureSession对应的ICameraDeviceUser的API:
- void waitUntilIdle();
- createCaptureSession时会先调stopRepeating,然后用该API等待上一次Session为IDLE;
- void beginConfigure()
- 开始创建Session;
- int createStream(in OutputConfiguration outputConfiguration);
- 根据OutputConfiguration创建OutputStream;
- void deleteStream(int streamId);
- 根据streamId删除未配置的Stream;
- int createInputStream(int width, int height, int format, boolean isMultiResolution);
- 在Reprocess流程中,根据宽/高/format等信息创建Input Stream;
- int[] endConfigure(int operatingMode, in CameraMetadataNative sessionParams, long startTimeMs);
- 结束创建Session;
- 这是createCaptureSession最耗时的一步,传给把参数传给NativeFramework,然后完成真正的Session创建;
ICameraDeviceUser中与Buffer有关的API:
- boolean isSessionConfigurationSupported(in SessionConfiguration sessionConfiguration);
- 对应CameraDevice的isSessionConfigurationSupported;
- 判断指定的SessionConfiguration是否支持,可以在创建Session之前判断config的宽高、format、buffer的路数是否支持,找到底层支持的;sessionConfiguration;
- void prepare(int streamId);
- 对应CameraCaptureSession的prepare;
- 预申请某路流的Buffers, 这样能提升第一帧到来的性能;
- void prepare2(int maxCount, int streamId);
- 对应CameraCaptureSession的prepare;
- 预申请某路流的Buffers,可以指定最大张数;prepare2是对prepare的补充;
- void updateOutputConfiguration(int streamId, in OutputConfiguration outputConfiguration);
- 对应CameraCaptureSession的updateOutputConfiguration;
- 更新OutputConfiguration;
- void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
- 对应CameraCaptureSession的finalizeOutputConfigurations;
- 最终决定OutputConfiguration;
- 对应CameraMetadataNative createDefaultRequest(int templateId);
- CameraDevice的createCaptureRequest;
- 根据templateId创建默认的CaptureRequest;
- SubmitInfo submitRequestList(in CaptureRequest[] requestList, boolean streaming)
- 对应CameraCaptureSession的capture/captureBurst/setRepeatingRequest/setRepeatingBurst;
- 向Framework送CaptureRequests;
- long cancelRequest(int requestId)
- 对应CameraCaptureSession的stopRepeating;
- 停止CaptureRequests,取消正在repeating的CaptureRequest,已经送到hal的继续执行;
- long flush();
- 对应CameraCaptureSession的abortCaptures;
- 放弃正在处理队列中,未被处理的Requests,Framework还在排队准备送hal的session,送到hal还没有处理的request也能结束;
ICameraDeviceUser中与OfflineSession和AudioRestriction相关的API:
- ICameraOfflineSession switchToOffline(in ICameraDeviceCallbacks callbacks, in int[] offlineOutputIds);
- 对应CameraCaptureSession的switchToOffline;
- 将当前的CameraCaptureSession切换到后台继续运行,应对快拍需求;
- Surface getInputSurface();
- 对应CameraCaptureSession的getInputSurface;
- 在Reprocess流程中,创建接受Input Buffer的Surface;
- 意思是上层APP给底层送buffer,需要给APP提供一个InputSurface,APP往InputSurface quee buffer,底层就能收到;
- void setCameraAudioRestriction(int mode);
- 对应CameraDevice 的 setCameraAudioRestriction;
- 设置当前CameraDevice的Audio限制策略;
- int getGlobalAudioRestriction();
- 对应CameraDevice的getCameraAudioRestriction;
- 获取当前CameraDevice的Audio限制策略;
- void disconnect()
- 对应CameraDevice#close;
- 关闭CameraDevice;
2.4 ICameraDeviceCallbacks.aidl详解
1 ICameraDeviceCallbacks是什么
ICameraDeviceCallbacks是ICameraDeviceUser的回调类,回调以下信息给App:
- CameraDevice的状态;
- 每一个CaptureRequest的状态以及回调CaptureResult;
2 ICameraDeviceCallbacks.aidl类图
3 ICameraDeviceCallbacks.aidl接口详解
- oneway void onPrepared(int streamId)
- prepare/prepare2的回调函数,说明执行streamId的Stream已经prepare完成;
- oneway void onCaptureStarted( in CaptureResultExtras resultExtras, long timestamp);
- 通知App,HAL开始处理一个CaptureRequest, 其中resultExtras存放的sequenceId,frameNumber等信息;timestamp是sencer开始曝光的时间点。
- oneway void onResultReceived( in CameraMetadataNative result, in CaptureResultExtras resultExtras, in PhysicalCaptureResultInfo[] physicalCaptureResultInfos);
- 通知App,HAL处理这个Request的进度,Java层CameraFWK会根据resultExtras来判断是否是PartialResult,如果是PartialResult就会回调onCaptureProgressed给APP,如果不是PartialResult表示这一帧的Result已经处理结束,回调onCaptureCompleted给APP;
- oneway void onRepeatingRequestError( in long lastFrameNumber, in int repeatingRequestId);
- 每次CameraServer送repeatingRequest给hal,都会从Surface dequee一张buffer,在dequee之前CameraServer会检查repeatingRequest里面的Surface是否出现Abandon了,Abandon就是App是否把这个Surface销毁了,如果销毁就不能拿到buffer,就会回调通知给App当前RepeatingRequest出现Error,通知停止repeating动作;App收到Error通知需要检查repeatingRequest里设置的Surface的生命周期出现问题;
- oneway void onRequestQueueEmpty();
- CameraServer的非Repeating的RequestQueue队列为空,通知给App;
- CameraServer有一个是非Repeating的RequestQueue:拍照使用,另一个是Repeating的RequestQueue:预览使用;
- oneway void onDeviceError( int errorCode, in CaptureResultExtras resultExtras)
- 通知CameraApp,CameraDevice出现error,具体的error在errorCode里面描述;
- oneway void onDeviceIdle();
- CameraDevice已经处理完所有的Request(Buffer都已收到),CameraDevice处于IDLE状态了,等待App送CaptureRequest下来处理;
2.5 Parcel对象相关的AIDL
Camera2 Java FWK AIDL有哪些自定义的Parcel对象
- 在AIDL的客户端和服务端通信的过程中,除了方法调用外,我们还需要传递不同类型的数据,这些数据的类型都必须实现parcelable接口,重载这两个方法writeToParcel、readFromParcel。
自定义的Parcel对象:
- frameworks/av/aidl/camera/aidl/android/hardware/camera2/impl/
- CameraMetadataNative.aidl
- CaptureResultExtras.aidl
- PhysicalCaptureResultInfo.aidl
- frameworks/av/aidl/camera/aidl/android/hardware/camera2/params/
- OutputConfiguration.aidl
- SessionConfiguration.aidl
- VendorTagDescriptor.aidl
- VendorTagDescriptorCache.aidl
- frameworks/av/aidl/camera/aidl/android/hardware/camera2/utils/
- CameraIdAndSessionConfiguration.aidl
- ConcurrentCameraIdCombination.aidl
- SubmitInfo.aidl
- CaptureRequest.aidl
Camera2 Java FWK不会生成中间文件的AIDL文件说明
- 如果一个AIDL文件没有被放在android.bp文件中,而仅仅是被其他AIDL文件import引用的话,在编译时不会生成对应的源代码(Java/C++)。
- 因为在Android编译系统中,根据aidl规则,当一个AIDL文件被import引用时,并不会单独处理该文件,而是一起处理引用它的AIDL文件。即使在被引用的AIDL文件中定义了parcelable或interface关键字,也不会单独生成对应的源代码(Java/C++)。
Camera2的Java层Parcel AIDL与C++ Parcel AIDL一一对应关系
以下是需要自己写的AIDL的类:
- impl/CameraMetadataNative.aidl
- CameraMetadataNative.java
- CameraMetadata.cpp
- impl/CaptureResultExtras.aidl
- CaptureResultExtras.java
- CaptureResult.cpp
- impl/PhysicalCaptureResultInfo.aidl
- PhysicalCaptureResultInfo.java
- CaptureResult.cpp
- params/OutputConfiguration.aidl
- OutputConfiguration.java
- OutputConfiguration.cpp
- params/SessionConfiguration.aidl
- SessionConfiguration.java
- SessionConfiguration.cpp
- params/VendorTagDescriptor.aidl
- VendorTagDescriptor.java
- VendorTagDescriptor.cpp
- params/VendorTagDescriptorCache.aidl
- VendorTagDescriptorCache.java
- VendorTagDescriptor.cpp
- utils/CameraIdAndSessionConfiguration.aidl
- CameraIdAndSessionConfiguration.java
- ConcurrentCamera.cpp
- utils/ConcurrentCameraIdCombination.aidl
- ConcurrentCameraIdCombination.java
- ConcurrentCamera.cpp
- utils/SubmitInfo.aidl
- SubmitInfo.java
- SubmitInfo.cpp
- CaptureRequest.aidl
- CaptureRequest.java
- CaptureRequest.cpp
为什么要自己写Parcel对象的Java/C++端代码
- writeToParcel、readFromParcel逻辑复杂,无法通过代码生成;
- 在Java/C++端,Parcel对象中有非Binder通信调用的方法;
上面的Parcel对象主要用途:
- CameraMetadataNative
- 本质上是CameraMetadata,封装成camera_metadata_t;
- CaptureResultExtras
- 存放CaptureResult各种索引信息,比如partialResultCount, requestId,回调给APP时会使用;
- PhysicalCaptureResultInfo
- 把PhysicalCamera和PhysicalCameraMetadata做一个映射关系;
- OutputConfiguration
- 描述一个OutputStream的配置信息(比如宽/高/是否shared等);
- SessionConfiguration
- Session配置信息;
- VendorTagDescriptor
- VendorTag的描述信息,Java端的没有使用;
- VendorTagDescriptorCache
- 按VendorID存放VendorTagDescriptor,Java端的没有使用;
- CameraIdAndSessionConfiguration
- 并行多颗Camera做ConfigureSession使用,可以并行做ConfigureSession的ID和SessionConfiguration;
- ConcurrentCameraIdCombination
- 描述可以并行ConfigureSession的ID;
- SubmitInfo
- 包括RequestId和LastFrameNumber,是submitRequestList的返回信息;
- CaptureRequest
- 描述一次CaptureRequest,包括mPhysicalCameraSettings和mSurfaceList等信息;
3. libcameraservice
3.1 C++层CameraService总体架构
Camera VNDK Client:vender分区的客户端,比如人脸解锁;
1 LibCameraService目录结构:
framework/services/camera/libcameraservice/
hidl:是和上层Camera VNDK Client通信的接口;
fuzzer:google测试框架;
3 libcameraservice主要模块关系
-
CameraService:常驻的一个CameraService的服务;
-
Client:是指CameraService自己的Client实例;
-
使用步骤:
- 如果有OpenCamera动作,OpenCamera–>Client–>CameraDevice–>平台选择HIDL/AIDL–>HAL;
- open结束后把CameraService的Client实例给到上层APP或者vender客户端,上层APP或者vender客户端操作Client就能操作CameraDevice,然后发送request到HAL,HAL处理结束后在把结果返回给CameraDevice,CameraDevice–>Client–>Callback给上层APP或者vender客户端;
3.2 C++层CameraService和Client架构
1 CameraService与CameraProviderManager的关系
- CameraService对上实现BnCameraService,就是实现java层CameraService提供的AIDL接口IcameraService.aidl;
- CameraService对下与CameraProviderManager交互,通过CameraProviderManager调用HAL层的实现,HAL层会实现AIDL或HIDL的ICameraProvider/ICameraDevice。
2 ClientManager类图
- CameraClientManager:管理处于Active状态的所有CameraClient对象;
- ClientDescriptor:描述当前CameraClient对象的信息;
- BasicClient:描述当前处于active状态的Client实例;
- CameraClient:可以通过sCameraService静态属性调到CameraService.cpp;
- CameraService里面的mActiveClientManager可以调到具体的CameraClient对象;
- ClientEventListener:监听Client的add和remove;
3 CameraClient的类图
- 所有Client都继承BasicClient;
- API1/API2的Client都抽象出一个类实现对上的接口;
- Camera2ClientBase主要封装对CameraDevice的操作;
3.1 CameraClient API2
- Camera2ClientBase:模版类,模版是CameraDeviceClientBase,下面API1模版是Client,封装API1和API2操作CameraDevice的common部分;
3.2 CameraClient API1
3.3 C++层CameraService的Device架构介绍
CameraDevice主要交互逻辑
- java层调用c++层:提供接口给上层控制操作CameraDevice,主要接口是CameraDeviceBase;
- 调用过程:APP先调用Client,然后通过CameraDeviceBase调用CameraDevice,最后调到HAL;
- c++层回调java层:回调ResultMetadata和ImageBuffer给上层,主要接口是FrameProcessor和Stream。
- 有两条回调通路:
- 一条通路:CameraDevice处理完某一帧后,有一个或者多个metadata存放在一个ResultQueue里面,FrameProcessor是一个线程,这个线程不停的向ResultQueue询问是否有可用的metadata,如果有就取出metadata处理,这是异步操作;
- 另一条通路:CameraDevice处理完某一路流后,会调用Stream的QueueBuffer接口,因为Stream是对BufferQueue的封装,整张图就会到BufferQueue的Consumer那边,通知消费者去取buffer,这是同步操作;
1 java层调用c++层的接口–>CameraDeviceBase
- CameraDeviceBase继承FrameProducer,FrameProducer是获取某一帧的ResultMetadata;
- CameraDeviceBase接口用于Client操作HAL2/HAL3 Device, Camera2Device是过渡产品,代码已经废弃;
- HidlCamera3Device对接HIDL HAL层接口,AidlCamera3Device对接AIDL HAL层接口,他们都继承自Camera3Device;
2 c++层回调java层,回调部分的ResultMetadata架构–>FrameProcessor
- 核心是FrameProcessorBase,它相当一个线程循环的处理FrameProducer的waitForNextFrame和getNextResult从mResultQueue里面获取CaptureResult
- Camera API2的ResultMetadata处理逻辑在FrameProcessorBase里面;
- Camera API1的ResultMetadata处理逻辑在FrameProcessor里面;
- 处理流程:
- Camera3Device不停的往FrameProducer的mResultQueue插入ResultMetadata,FrameProcessorBase循环从FrameProducer的mResultQueue获取ResultMetadata;
- FrameProcessorBase会调用
FrameProducer
的waitForNextFrame获取下一帧,获取到后调用getNextResult从mResultQueue里面获取CaptureResult; - 处理完帧后,调用FrameProcessorBase::FilteredListener,最终会调用API2的CameraDeviceClient,这里面实现了onResultAvailable,它会把CaptureResult返回到上层APP;
3 c++层回调java层,API2回调部分的ImageBuffer架构 -->CameraStream
- Camera3Device根据hal的配置信息决定创建Camera3InputStream、Camera3OutputStream、Camera3SharedOutputStream;
- camera_stream:是一个结构体,camera_stream装载hel传上来的buffer流,是和hal层的stream长得一样的结构体;
- Camera3Stream:
- 是InputStream和OutputStream的基类,继承camera_stream,能把hal层的stream转换成c++层cameraservice的stream;
- 维护Stream的状态机切换;
- 提供接口访问Stream的信息,比如ID、width、height、usage、dataspace等等;
- 提供接口转换成hal层的stream;
- Camera3IOStreamBase:是InputStream和OutputStream的基类,管理整个stream的buffer状态,哪些在hal,哪些已经回给我了,维护当前这路stream,一个stream有很多张buffer;
- Camera3OutputStreamInterface:
- Camera3Device对InputStream和OutputStream操作的流程完全不一样,所以将OutputStream的特殊操作抽象出来放到Camera3OutputStreamInterface;
- 对InputStream的操作还是放在Camera3Stream;
4 c++层回调java层,API1回调部分的ImageBuffer架构–>Processor
- 上层使用API1时,hal把Buffer送到我们的Stream后,要么直接送给上层这三类直接送给上层:StreamingProcessor、JpegProcessor、带surface的CallbackProcessor;要么送给Processor取出Buffer通过binder回调给上层java层。
- Processor:
- StreamingProcessor:用于预览,创建PreviewStream和RecordingStream,上层APP会创建一个surface传给c++层cameraservice,当hal3把buffer填充到我们的Stream后,Processor把buffer从Stream取出来,把buffer送到上层APP的surface;
- JpegProcessor:用于Jpeg拍照,创建一路Jpeg的Stream接收hal3传上来的JpegBuffer,取出来JpegBuffer回调到上层;
- CallbackProcessor:用于预览Callback,和StreamingProcessor一样,创建一路Callback的Stream接收hal3上传buffer,取出来buffer回调到上层;
- ZslProcessor:用于拍照时可以选到靠前的用户看到的那张图,用zslQueue做缓存,当拍照时从队列取出来;
3.4 C++层CameraService的API1和API2调用HAL3流程
1. API1 call HAL3,参数设置流程
- 第一步:上层APP调用Camera2Client的setParameters方法将参数送到C++层CameraService;
- 第二步:创建默认CaptureRequest,Camera2Client会将参数送给StreamingProcessor,再交给Parameters把参数更新到CaptureRequest;
- 第三步:更新后的CaptureRequest ,如
mPreviewRequest
、mRecordingRequest
,保存在StreamingProcessor中;
2. API1 call HAL3,startPreview流程
- 第一步:调用StreamingProcessor和JPEG/Callback/ZSL Processor的updateStream,创建OutputStream,StreamingProcessor是创建预览流,JPEG/Callback/ZSL Processor是创建拍照流;
- 第二步:再次更新
mPreviewRequest
、mRecordingRequest
; - 第三步:调用StreamingProcessor的startStream,将Request送给Camera3Device,Camera3Device执行ConfigureStream,调到hal3执行configStream,然后调用setRepeatingRequests,让RepeatingRequest队列转起来不停的向hal3送CaptureRequest;
3. HAL3 call back API1,参数回调流程
- 第一步:FrameProcessorBase有一个线程不停查询CameraDeviceBase是否有可用的CaptureResult,就是调用waitForNextFrame方法等待有可用的一帧,然后调用getNextResult获取metadata;
- 第二步:处理FaceDetect回调和向Parameters更新3A State:拿到可用的CaptureResult和metadata后调用FrameProcessor::processSingleFrame开始处理,先调用processFaceDetect检查是否有人脸信息,如果有就通过binder call告诉上层APP有人脸信息到了;然后调用process3aState更新到Camera2Client的Parameters。
4. HAL3 call back API1,图像数据回调流程
4.1 HAL3 call back API1,图像数据回调流程 – 预览/录像
StreamingProcessor:预览/录像
- 预览/录像:
- 第一步:上层APP传递一个surface下来给到StreamingProcessor,用surface创建一个outputStream,当hal层的processCaptureResult上来,CaptureResult里面如果有buffer就会找到outputStream,告诉outputStream buffer已经来了,outputStream就是Camera3OutputStream;
- 第二步:然后Camera3OutputStream就会调用BufferQueue的queueBuffer方法,通知到BufferQueue,这张buffer已经ready;
- 第三步:然后跨binder通知Consumer进程的onFrameAvailable方法有buffer来了,把buffer从bufferQueue里面取出这张buffer图使用,Consumer通常是APP/SurfaceFlinger/录像(VideoEncoder)。
CallbackProcessor:预览
- 有两种,一种是使用setPreviewCallbackTarget方式接收回调预览buffer,和上面的StreamingProcessor一样,就是使用BufferQueue的方式传递buffer;
- 这里讨论另一种,不使用setPreviewCallbackTarget方式接收回调预览buffer:
- 第一步:需要c++层cameraservice自己创建BufferQueue,名字是Camera2-CallbackConsumer,然后用这个BufferQueue去创建Camera3OutputStream,hal3执行processCaptureResult,将buffer发给Camera2-CallbackConsumer;
- 第二步:自己创建BufferQueue的Consumer端在自己进程,Camera2-CallbackConsumer在CallbackProcessor.cpp里,然后执行CallbackProcessor的onFrameAvailable把buffer取出来,执行dataCallback跨binder将这张图发送给APP。
4.2 HAL3 call back API1,图像数据回调流程 – 拍照
Google创建了一个CaptureSequencer.cpp来维护拍照的状态机,通过不同的函数切换状态。
- 第一步:有线程在manageIdle等待触发拍照,当用户触发拍照,执行startCapture,将状态从manageIdle切到manageStart,在manageStart方法会判断拍照是zsl还是Non-zsl;
- 第二步:如果拍zsl,切换到manageZslStart状态,执行manageZslStart函数,会从zsl队列选一张图能不能满足拍zsl的条件,比如要求AE/AF是收敛的,如果zsl队列里面所有的图都是没有收敛就选不到,选不到就会切换到manageStandardStart,如果能选到zsl就会触发zsl拍照,会走pushToReprocess流程,把图再灌回给hal,hal这边重新处理,处理完之后就回调一张jpeg图,状态切换成manageStandardCaptureWait等待pushToReprocess产生的jpeg图,最后状态切换成manageDone取出Jpeg,然后调用callback,将jpeg送回上层APP。
- 第二步:如果拍Non-zsl,切换到manageStandardStart判断flush状态,判断是否要做AEPrecapture,如果要做AEPrecapture会触发AEPrecaptureTrigger,然后切换到manageStandardPrecaptureWait等待AEPrecapture做完,做完后切换到manageStandardCapture做拍照动作,如果不需要做AEPrecapture直接从manageStandardStart切到manageStandardCapture,切换成manageStandardCaptureWait等待Jpeg产生,最后状态切换成manageDone取出Jpeg,然后调用callback,将jpeg送回上层APP。
4.2.1 HAL3 call back API1,拍照回图的Non-ZSL&&Non-AEPrecapture流程
- 非ZSL且不做AEPrepareTrigger的拍照流程如上图所示,整个拍照过程由CaptureSequencer来驱动,JpegProcessor收到拍照图像后,通知给CaptureSequencer负责回调给App。
- 第一步:首先APP触发tackPicture,在Camera2Client里面会调用startCapture,将CaptureSequencer从manageIdle切换到manageSart,在manageStart里面判断是否走zsl,不走zsl切换到manageStandardCapture,然后是触发拍照流程,执行JpegProcessor的getStreamId、updateStream,就是检查JpegStreasm是否存在,如果存在就拿到这个StreamId,否则创建一个Stream,然后将StreamId更新到CaptureRequest里面,执行CameraDeviceBase::capture,拍照流程结束。
- 第二步:状态切换到manageStandardCaptureWait,等待Jpeg产生,当hal层执行到processCaptureResult向我们回调data时,会回调到JpegProcessor的onFrameAvailable,也就是这张Jpeg已经ready,会调用CaptureSequencer::onCaptureAvailable告诉CaptureSequencer这张图已经拍好,状态切换到manageDone把这张图取出来,通过dataCallback回调到上层APP。
1 API2 call HAL3,控制流程与参数回调
- 第一步:APP调用hal,调用createCaptureSession,在java层cameraservice最后一步会调用到endConfigure,在endConfigure会调用Camera3Device::configureStreams接着调到hal层的HalInterface::configureStreams,完成整个streamConfig,其他比如submitRequest、flush,流程和这个一样的。
- 第二步:参数回调,FrameProcessorBase这个线程一直在waitForNextFrame,等到后执行processNewFrames拿到ResultMetadata,拿到以后在自己的实现类调用CameraDeviceClient::onResultAvailable某一帧的resultMetadata已经ready,执行onResultReceived将metadata送到java层cameraservice。
2 HAL3 call back API2,数据流回调
- API2中,所有数据流都走BufferQueue传递,这个更高效,和上面的API1的StreamingProcessor一样;
- 步骤:hal回图告诉Camera3Device通知Camera3Stream这张buffer图已经ready,执行queueBuffer给BufferQueue,进而Consumer就会被通知到有Buffer上来了,Consumer通常是APP/SurfaceFlinger/录像(VideoEncoder)。
4. C++层CameraService的Camera2流程
1. C++层Camera2获取CameraCharacteristic
1. C++层CameraService的getCameraCharacteristics总流程
getCameraCharacteristics:
- 获取静态metadata,这颗CameraDevice支持的参数,比如JpegSize;
- 如果是call HAL3的getCameraCharacteristics,可以不需要openCamera;
- 使用步骤:
- 第一步:Cameraserver进程刚起来做enumerate时会将CameraCharacteristics存放在CameraProviderManager的DeviceInfo3里面的mCameraCharacteristics,因为当C++层CameraService启动后,CameraDevice的静态metadata不会改变;
- 第二步:上层APP问CameraService要CameraCharacteristics时,CameraService就从DeviceInfo3对象中直接获取,不会调用到HAL去,可以减少binder call hal的次数;
1.1 CameraProvider初始化mCameraCharacteristics流程:
步骤:
- 第一步:C++层CameraService启动时,会问hal有多少颗CameraDevice,对每颗cameraDevice都执行addDevice,每一颗CameraDevice会去获取CameraCharacteristics,保存在mCameraCharacteristics;
- 第二步:如果是Logical MultiCamera,会针对每一颗Physical Camera调用HAL层的getPhysicalCameraCharacteristics,保存在mPhysicalCameraCharacteristics Map中;
1.2 CameraProvider初始化mCameraCharNoPCOverride流程:
步骤:
- C++层CameraService启动时,在enumerateProviders会调用CameraProviderManager的filterSmallJpegSizes,这个方法是剔除小于1080P的JpegSize,目的是兼容老的hal版本,剔除前会保留mCameraCharacteristics到mCameraCharNoPCOverride,然后删除mCameraCharacteristics里小于1080P的JpegSize;
- 如果APP TargetSdkVersion小于S,使用mCameraCharNoPCOverride,如果大于S,使用mCameraCharacteristics;
2. CameraService的getCameraCharacteristics逻辑
步骤:
- 第一步:根据SystemCameraKind判断是否要拒绝访问,如果不拒绝,则通过上层APP传入的TargetSDK获取overrideForPerfClass,然后传递给CameraProviderManager获取CameraCharacteristics;
- 第二步:判断是否有Camera权限,如果没有Camera权限,删除必须要有Camera权限才能访问的静态metadata,然后再返回静态metadata(这里可以优化下,将无静态权限才能访问的静态Metadata缓存起来,不用每次都去操作Metadata);
2.1 shouldRejectSystemCameraConnection逻辑,获取SystemCameraKind的权限:
SystemCameraKind:
- PUBLIC:对所有应用程序和系统组件都是可见;
- SYSTEM_ONLY_CAMERA:只对有android.permission.SYSTEM_CAMERA权限的进程可见,比如系统相机,不会暴露给第三方应用程序;
- HIDDEN_SECURE_CAMERA:只对HAL应用可见,比如人脸解锁(通过hwbinder连接);
步骤:
- 第一步:获取调用者的PID/UID/SystemCameraKind/以及是否是systemClient;
- 第二步:如果是c++层cameraserver自己调用自己,则不拒绝,这种情况一般出现在hal调用c++层cameraserver再调用自己,不会拒绝;
- 第三步:如果是systemClient,则不拒绝,uid小于10000都是systemClient;
- 第四步:如果systemCameraKind是PUBLIC,则不拒绝;
- 如果systemCameraKind是HIDDEN_SECURE_CAMERA,拒绝,因为走到这里说明不是hal调用过来,所以拒绝;
- 如果systemCameraKind是SYSTEM_ONLY_CAMERA,并且有SYSTEM_CAMERA权限,则不拒绝,没有SYSTEM_CAMERA权限则拒绝;
2.2 CameraProviderManager的getCameraCharacteristics逻辑
步骤:
- 第一步:判断是否要为PerfClass做Override;如果要做Override,则返回mCameraCharacteristics,否则返回mCameraCharNoPCOverride;
- 第二步:则根据CameraId从mPhysicalCameraCharacteristics里面获取hidden physical camera characteristics;
2. C++层Camera2获取addListener
1 addListener总体流程
-
作用:实时监听手机每颗camera的状态,每颗camera都保持一个状态,比如打开相机,手机摔到了某颗camera,camera不能使用了,CameraService可以立刻返回一个状态给客户端,如果有多个客户端使用,可以通知到多个客户端。
-
ICameraService.aidl的addListener:
- CameraStatusAndId[] addListener(in ICameraServiceListener listener);
- CameraStatusAndId[] addListener(in ICameraServiceListener listener);
-
直接调用addListenerHelper就是vendorListener,直接调addListener就不是vendorListener
1.1 CameraService::addListener方法详解
- 步骤:
- 第一步:检查调用者进程是否有监听Camera Open和Close权限,如果没有就不会告诉调用者哪颗camera打开、关闭,不会调用onCameraOpened、onCameraClosed;
- 第二步:判断调用者进程是否已经add过Listener,如果没有add过,构造ServiceListener并调用initialize方法,将ServiceListener保存在mListenerList,然后向UidPolicy注册Monitor事件,监听UID的变化;
- 第三步:遍历mCameraStates,将结果存放入输出对象cameraStatuses中,然后erase掉需要对调用者隐藏的CameraStates;最后执行listener->onTorchStatusChanged,更新TorchModeStatus给调用者进程;
CameraStatus:
cameraId:Camera设备的Id;
status:Camera设备当前的状态;
unavailablePhysicalIds:针对LogicalMulticamera情况,存放不可用的PhysicalCameraID;
clientPackage:如果拥有监控Opened/Closed权限,返回CameraDevice被哪个进程正在使用;
1.2 removeListener流程详解
- 步骤:
- 第一步:CameraService会保存每一个调用者客户端的ServiceListener对象,都会监听对端客户端的binderDied,当对端died,CameraService这边的binderDied会被调用,然后调用CameraService::removeListener,将这个客户端的ServiceListener从mListener移除;
- 第二步:注销UidPolicy监听对端进程状态,注销binder监听,删除mListenerList的ServiceListener;
3. C++层Camera2 OpenCamera
1. OpenCamera总体流程
- 步骤:
- 第一步:检查权限,权限包括camera自己的权限、手机对camera的限制(比如DevicePolicy)、censer隐私权限;
- 第二步:调用者需要打开的Camera和已经打开Camera的关系,如果两个调用者进程都去打开一个Camera,就会有两个进程抢占;
- 第三步:做openCamera动作,主要是cameraClient初始化,调用hal真正做openCamera,给Camera做上电动作;
- 第四步:初始化cameraDevice;
正常耗时30ms左右,如果hal异步做就不耗时;
2. CameraService::connectDevice,都是从这里开始
- API2用connectDevice–>检查权限–>ConnectHelper,这里说API2;
- API1用connect–>ConnectHelper;
- 步骤:
- 第一步:通过CallingUid判断是否是systemNativeClient,systemNativeClient主要针对VendorClient,hal端的Client,比如人脸解锁,在流程上做一些特殊处理,VendorClient没有包名,可以不用对包名做检查权限;
- 第二步:通过UserId判断是否当前User被DevicePolicy限制使用Camera,一般在多用户场景,如果限制就会报错结束,如果不限制继续往下走,判断是否有权限通过oomScoreOffset降低抢占权限,意思用oomScoreOffset降低抢占优先级,这种只是为了SystemCamera,如果是SystemCamera但是没有oomScoreOffset也会结束退出;
- 第三步:执行ConnectHelper完成OpenCamera流程(重点),然后重置匿名共享内存文件mMemFd,mMemFd是记录上一次openSession的信息,调用AMS的logFgsApiBegin,logFgsApiBegin表示有ForegroundService在使用Camera,closeCamera是logFgsApiEnd;
3. CameraService::connectHelper(重点)
- 步骤:
- 第一步:为非SystemNDKClient获取clientPackageName,定位那个进程在使用camera,然后记录openCamera开始时间点openTimeNs里,在connectHelper结束时会记录OpenCamera的耗时openLatencyMs,传递给mCameraServiceProxyWrapper->logOpen,没有log打印耗时。
- 绿色方框里面部分:
- 抢到mServiceLockWrapper这把锁,超时时间是3s,保证同一时刻只有一个客户端在openCamera,如果这里超时看一下上次openCamera时候这把锁是不是没有释放,也有可能close卡主,mServiceLockWrapper被持有的地方比较多都要查;
- 检查权限和CameraId:validateConnectLocked(重点);
- 处理抢占逻辑:handleEvictionsLocked(重点);
- 准备创建cameraClient,准备参数:
- deviceVersionAndTransport:是指hidl的deviceVersion、Transport;
- portaitRotation:旋转多少度是竖屏;
- facing:打开camera是前置还是后置;
- orientation:设备角度;
- overrideForPerfClass:对参数做的修改;
- 把准备的参数传入makeClient,这里会区分API1或者API2,API1创建camera2Client,API2创建cameraDeviceClient,这里看API2;client->initialize,会传入monitorTags,monitorTags:可以监听每一帧里面的metadata变化,debug时使用,比如dumpsys media.camera。(重点)
- CameraService watchdog:监听函数的耗时;rotate-and-crop override behaviour:是否要做override行为;autoframing override behaviour:自动选帧;camera muting behavior:camera没有关闭,但是不能出正常的图像,比如显示黑屏或者测试图片,如果isCameraPrivacyEnabled=true就不能出正常的图像,接着如果supportsCameraMute=ture启流时需要mute,否则关闭camera。 client->setImageDumpMask;client->setStreamUseCaseOverrides;client->setZoomOverride,这3个都是debug使用。
- finishConnectLocked:把打开后的CameraClient添加到ActiveClientManager中,ActiveClientManager监听CameraClient进程是否挂掉;
- logConnected:dumpsys 可以看到;linkToDeath:监听调用者进程是否挂掉,调用者挂掉CameraService就会disconnect;
- mInjectionInitPending:是指外接的camera可以动态切换,暂时没人用。
3.1 validateConnectLocked
- 步骤:
- 第一步:validateClientPermissionsLocked:获取调用者客户端的UID和PID;执行shouldRejectSystemCameraConnection对SystemCamera的权限进行检查,前面说过这个;检查非系统camera的权限,是否已经有Camera权限;检查调用者UID是否处于Active状态;检查调用者SensorPrivacy是否Enable,如果没有就不能使用;检查当前用户是否在mAllowedUsers里面,多用户场景,
- mAllowedUsers赋值:
CameraService::onFirstRefmCameraServiceProxyWrapper->pingCameraServiceProxy
CameraServiceProxyWrapper::pingCameraServiceProxyproxyBinder->pingForUserUpdate
binder call java层
CameraServiceProxy.javanotifySwitchWithRetriesnotifySwitchWithRetriesLockednotifyCameraserverLocked(ICameraService.EVENT_USER_SWITCHED, ..)mCameraServiceRaw.notifySystemEvent(eventType, ..)
binder call c++层
CameraService::notifySystemEventICameraService::EVENT_USER_SWITCHED:doUserSwitch(/*newUserIds*/ args);CameraService::doUserSwitch(.. newUserIds)mAllowedUsers = std::move(newAllowedUsers);
- 第二步:根据CameraId获取CameraState,检查CameraId是否合法;
- 第三步:根据CameraState检查当前CameraDevice是否可用,CameraDevice的状态:PRESENT、NOT_PRESENT、ENUMERATING;
3.2 handleEvictionsLocked
- 步骤:
- 第一步:新的客户端进程打开camera时,获取所有已经连接camera客户端进程的oom_adj scores和process state,这两个都是实时变化的,更新各ClientPriority。比如有多个客户端进程连接camera,每一个客户端进程都持有一个client,这个client就是ActiveClient,客户端进程的pid就是ActivePid,保存在数组里面。
- 第二步:根据当前客户端进程想打开的camera创建一个ClientDescriptor,每个连接camera的进程都有一个ClientDescriptor,然后调用CameraClientManager的wouldEvict方法拿到需要被抢占的调用者进程的evicted列表,wouldEvict是抢占逻辑的核心。比如已经有进程连接camera,新的进程也想要连接camera,把所有的进程都放入wouldEvict做裁决谁连接camera。
- 第三步:如果想打开camera的客户端进程在evicted列表中,就返回CAMERA_IN_USE(被人占用)或MAX_CAMERAS_IN_USE(没人占用,自己优先级低也不能打开)。开camera的客户端进程不在evicted列表,就表示打不开,当前进程优先级不够。
- 第三步:如果evicted列表只有已经连接camera的进程,遍历evicted列表,给每一个进程发送ERROR_CAMERA_DISCONNECTED,断开连接camera,然后执行clearCllingIdentity清空远程调用端的uid和pid,用cameraserver进程的uid和pid替代,下面执行disconnect时检查callingPid和调用者pid如果不一样就直接返回。
- 第四步:再遍历evicted列表,调用每个已经连接的Client的disconnect方法关闭Camera,通过restoreCallingIdentity恢复远程调用端的uid和pid,正好和clearCallingIdentity相反。调用waitUnitlRemoved等待所有evictedClientDisconnect完成。
- 最后,再次检查当前CameraId对应的Device是否可用。
3.3 ClientDescriptor
描述一颗CameraClient对象。
- KEY:当前CameraClient对应的CameraId;
- VALUE:当前CameraClient对象;
- cost:打开当前Camera需要耗费的resourceCost,用resourceCost描述打开相机需要的资源;
- conflictingKeys:与上面KEY的值必须相同,如果不同就表示不能打开camera,
- 比如:
- KEY=0,conflictingKeys=(1,2),表示当前进程已经打开了camera 0,想再打开camera 1、2,就打不开;
- 进程A:KEY=0,conflictingKeys=(1,2),进程B:KEY=2,表示进程B已经打开的camera 2涵盖在进程A想再打开的camera 1、2,这样也会冲突;
- score:打开当前Camera的客户端进程oom_adj score,这个值越大越容易被LMK干掉,前台进程这个值为0;
- ownerId:打开当前Camera的客户端进程pid;
- state:打开当前Camera的客户端进程的状态,值越小优先级越高;
- isVendorClient:打开当前Camera的客户端是否是Vendor进程;
3.4 ClientPriority
描述一颗CameraClient客户端进程的优先级。
- score:打开当前Camera的客户端进程oom_adj score,这个值越大越容易被LMK干掉,前台进程这个值为0;
- state:打开当前Camera的客户端进程的状态,值越小优先级越高;
- isVendorClient:打开当前Camera的客户端是否是Vendor进程;
这个类重载了比较运算符,比如 >,>=,<,<=,通过score和state来判断大小,ClientPriority值越小,优先级越高。
//小于运算符
bool operator< (const ClientPriority& rhs) const {if (this->mScore == rhs.mScore) {return this->mState < rhs.mState;} else {return this->mScore < rhs.mScore;}
}
4. Camera抢占逻辑
conflicting表示是否有冲突:当前进程想要打开的key和已经打开的curKey相等就有冲突;当前进程的client想要打开的key是否已经包含在已经打开camera的client的conflictingKeys里面。
bool conflicting = (curKey == key || i->isConflicting(key) ||client->isConflicting(curKey));
- 抢占逻辑:
- 想打开的camera与已打开camera存在冲突
- 如果是同一个进程打开camera有冲突;
- 在不同时间点想打开同一颗Camera,可以随时时打开;
- 想打开不同颗Camera,本来就有冲突,不能同时打开,用之前的camera;
- 如果是不同进程打开camera有冲突;
- 已打开camera进程优先级低,当前进程优先级高,可以打开camera;
- 已打开camera进程优先级高,当前进程想打开camera会失败,无法打开;
- 如果是同一个进程打开camera有冲突;
- 如果是同进程或者不同进程打开camera,想打开的camera与已打开的camera不存在冲突,就使用resourceCost做限制,最大resourceCost是100;
- 如果打开camera进程的Total cost超过最大值100,比如:进程A已经打开了camera0,使用的resourceCost=51,进程B想打开camera1,使用的resourceCost=50,这两个resourceCost之和是101,就判定这两个进程打开camera有冲突;
- 已打开camera进程优先级低,当前进程优秀级高,可以打开camera;
- 已打开camera进程优先级高,当前进程想打开camera会失败,无法打开;
- 如果Total cost未超过最大值,当前进程直接打开camera。比如:进程A已经打开了camera0,使用的resourceCost=40,进程B想打开camera1,使用的resourceCost=40,这两个resourceCost之和是80,就判定这两个进程打开camera没有冲突;
- 如果打开camera进程的Total cost超过最大值100,比如:进程A已经打开了camera0,使用的resourceCost=51,进程B想打开camera1,使用的resourceCost=50,这两个resourceCost之和是101,就判定这两个进程打开camera有冲突;
疑问:
- 同一进程能否重复打开同一颗Camera?Yes
- 同一进程能否同时打开不同颗Camera?Yes,如果打开的2颗camera不冲突,可以用resourceCost做限制,如果resourceCost超过100看进程优先级,resourceCost不超过100,能同时打开不同颗Camera。
- 不同进程能否重复打开同一颗Camera?Yes
- 不同进程能否同时打开不同颗Camera?Yes,如果打开的2颗camera不冲突,可以用resourceCost做限制,如果resourceCost超过100看进程优先级,resourceCost不超过100,能同时打开不同颗Camera。
5. CameraDeviceClient初始化
5.1 API2 makeClient流程
5.2 API2 CameraClient类图:CameraDeviceClient
- API2/API1 CameraClient各个类的职责:
- CameraDeviceClient:API2,负责处理与API2相关的业务逻辑;
- CameraDeviceClientBase:负责继承API2的ICameraDeviceUser;
- Camera2ClientBase:负责处理API1和API2共用的逻辑且与CameraDevice操作有关系;
- CameraService::BasicClient:负责处理API1和API2共用的逻辑且与CameraDevice操作无关;
- Camera2Client:负责处理与API1相关的业务逻辑;
- CameraService::Client:负责继承API1的ICamera(BnCamera);
5.3 API2 CameraDeviceClient成员变量
- mFrameProcessor::FrameProcessorBase:从cameraDevice获取每帧的ResultMetadata;
- mSupportedPhysicalRequestKeys::vector:PhysicalCamera支持设置的RequestKeys,上层送submitRequest时用于过滤掉不支持的Request设置;
- mStreamMap::KeyedVector<sp, StreamSurfaceId>:以Map方式存值,key是GraphicBufferProducer,相当于一个surface或者stream,value是StreamId和SurfaceId的组合,使用组合的原因是在sharedStream的情况,一个stream有多个surface,比如hal发送一个stream,cameraserver接收多个输出surfaceId;
- mConfiguredOutputs::KeyedVector<int32_t, OutputConfiguration>:上层APP下发配置的流时,每个流保存在OutputConfiguration列表,key是streamId,value是OutputConfiguration;
- mDynamicProfileMap::map<int64_t, int64_t>:key是profileId,value是SupportedDynamicProfiles BitMap,bitMap是多个profileId用或连接的,存放当前这颗camera支持的dynamicRangeProfiles,上层APP送submitRequest时会对设置的值做检查,做检查的原因是cameraserver不知道上层下发的dynamicRangeProfile是否合法,需要向hal查询是否支持,dynamicRangeProfile放在OutputConfiguration;
- mInputStream::InputStreamConfiguration:存放InputStream,上层APP把buffer回灌到hal,只支持一路InputStream;
- mStreamingRequestId::int32_t:存放最新Streaming的RequestId,每次调用submitRequestList后,cameraserver会有一个mRequestIdCounter++,用于判断当前stream或repeatingRequest是否处于Active;
- mRequestIdCounter::int32_t:submitRequestList时++,唯一标识当前的这次submitRequest行为;
- mPhysicalCameraIds::vector:存放当前这颗Camera支持的PhysicalCamera的Id,对logicalMultiCamera有效;
- mDeferredStreams::Vector:存放处于Defer状态的OutputStream,SurfaceReady后会move到mStreamMap,比如这条stream的serface没有ready,等ready后上层APP再重新送下来,一旦SurfaceReady就会把serface从mDeferredStreams删除,然后放入mStreamMap,有助于提高启动性能;
- mStreamInfoMap::map<int32_t, OutputStreamInfo>:key是streamId,value是outputStreamInfo的map,记录每路outputStream的info;
- mHighResolutionCameraIdToStreamIdSet::map<std::string, std::unordered_set>:key是高分辨率(>=24M)的camera id (logical/physical) ,value是list of stream ids,检查Request里面设置的SensorPixelModel与OutputConfiguration里面的SensorPixelMode是否一致;
- mHighResolutionSensors::set:用于判断是否支持高分辨率Stream的Camera,用ULTRA_HIGH_RESOLUTION_SENSOR的capability;
- mCompositeStreamMap::KeyedVector<sp, sp>:用于合成流再给回APP,等价于mStreamMap,存放3中需要合成的Stream:HEIC,JPEG_DEPTH(Jpeg with XMP depth metadata),JpegR(Jpeg with Recovery map);
- mProviderManager::CameraProviderManager:存放CameraProviderManager的实例,用于判断是否是logical multi-cam和isSessionConfigurationSupported;
- mOverrideForPerfClass::bool:是否要Override the camera characteristics for performance class primary cameras,在isSessionConfigurationSupported使用;
- mUserTag::string:上层送request时执行CaptureRequest.setTag记录最新设置的mUserTag,记录在event log里面;
- mVideoStabilizationMode::int:记录最新的VideoStabilizationMode,记录在event log里面;
5.4 API2 CameraDeviceClient与Stream的变量
- outPutStream:
- mConfiguredOutputs:保存streamId映射 OutputConfiguration,OutputConfiguration是上层app下发的stream信息,上层要求的stream格式;
- mStreamMap:保存IGraphicsBufferProducer binder映射streamId和surfaceId;
- mStreamInfoMap:保存streamId映射OutputStreamInfo,OutputStreamInfo是指cameraserver要求的stream格式;
- mDeferredStreams:保存streamId;
- InputSream:
- mInputStream
5.5 API2 CameraDeviceClientBase成员变量
- mRemoteCallback::ICameraDeviceCallbacks:保存给App进程的回调对象实例;
5.6 API2 Camera2ClientBase成员变量
- mSharedCameraCallbacks::SharedCameraCallbacks:保存回调到App的对象;
- mInitialClientPid::pid_t:记录初始化CameraClient时传递的ClientPID;
- mOverrideForPerfClass::bool:是否要Override the camera characteristics for performance class primary cameras;
- mLegacyClient::bool:Client是否是API1;
- mCameraServiceProxyWrapper::CameraServiceProxyWrapper:CameraServiceProxy对象,用于与之交互;
- mDevice::CameraDeviceBase:存放CameraDeviceBase的实例;
- mDeviceActive::bool:标识当前CameraDevice是否处于Active状态;
- mApi1CameraId::int:API1的Camera ID,如果是API2,这个值为-1;
- mCameraServiceWatchdog::CameraServiceWatchdog:CameraClient的WatchDog,监控disconnect是否timeout;
5.7 API2 CameraService::BasicClient成员变量
- sCameraService::CameraService:保存CameraService的实例,用于Client回调CameraService;
- mCameraIdStr::String8:CameraID;
- mCameraFacing::int:Camera的面向,前置或者后置;
- mOrientation::int:Camera sensor的安装角度;
- mClientPackageName::String16:客户端进程的package name;
- mSystemNativeClient::bool:是否是SystemNativeClient,如果UID小于AID_APP_START的Native进程;
- mClientFeatureId::String16:Client进程的feature id,上层app设置的mContext.getAttributionTag(),调用AppOpsManager使用;
- mClientPid::pid_t:Client的PID;
- mClientUid::uid_t:Client的UID;
- mServicePid::pid_t:CameraService的PID;
- mDisconnected::bool:当前Client是否处于Disconnect状态;
- mUidIsTrusted::bool:UID是否是可信的,白名单,这些可信mediaserver, cameraserver, telephony;
- mOverrideToPortrait::bool:是否要将Stream通过Rotate和Crop成Portrait,兼容性考虑;
- mAudioRestriction::int32_t:对Audio的限制策略;
- mRemoteBinder::IBinder:保存给App进程的回调对象实例;
- mAppOpsManager::AppOpsManager:AppOpsManager实例,用于检查Client是否有Camera操作权限;
- mOpsCallback::OpsCallback:AppOps的回调,用于通知App的操作权限变化;
- mOpsActive::bool:是否开始监听CameraOps;
- mOpsStreaming::bool:是否开始执行CameraOps;
5.8 API2 clientPackageName赋值逻辑
调用者进程的包名
- openCamera时,上层Java层APP会传递Client package name到CameraService;
- 如果是NativeClient,传递的package name为空字符串,cameraservice会主动获取包名;
- connectHelper是API1和API2通用的逻辑;
5.9 AppOpsManager处理逻辑
AppOpsManager是应用程序执行某个操作权限的管理类,有两个目的
- 运行时的访问权限控制,比如某个APP是否有权限执行某个操作;
- 运行时的访问权限跟踪,比如某个APP在使用camera的过程中发生camera操作权限的变更,允许openCamera但在使用过程中不允许使用camera,比如分屏时一个屏幕显示预览,另一个屏幕操作settings把camera权限关掉;
- 第一步:检查是否是mSystemNativeClient,如果不是mSystemNativeClient创建mAppOpsManager,如果是mSystemNativeClient后面的步骤可以不用操作;
- 第二步:initialize时执行notifyCameraOpening,告诉AppOpsManager调用者客户端需要openCamera,检查客户端是否有openCamera的权限,开始跟踪操作camera的权限;
- startWatchingMode:开始监听调用者APP进程在使用过程中是否有操作权限的变化;
- checkOp:检查调用者的uid和packagename是否能匹配;
- handleAppOpMode:下面说;
- 第三步:Preview Started,送request让hal上帧出图,执行startCameraStreamingOps;
- startOpNoThrow:执行更严格的检查,检查camera相关的全部权限,不符合就会返回appOpMode回来;
- 第四步:Preview Stopped,执行finishCameraStreamingOps,finishOp:告诉AppOpsManager上一次的start到到这执行结束;
- 第五步:Close Camera,执行finishCameraOps,stopWatchingMode,对应openCamera的startWatchingMode;
handleAppOpMode
- 第一步:针对MODE_ERRORED和MODE_IGNORED两种Mode做了处理;
- 如果mode是MODE_ERRORED,返回PERMISSION_DENIED,没有权限不允许openCamera;
- 如果mode是MODE_IGNORED,表示AppOpsManager忽略了检查或者检查不到,比如Client是native service,不属于上层java层APP,就会忽略检查返回MODE_IGNORED,如果是后台应用程序也会返回MODE_IGNORED;
- 第二步:检查mUidIsTrusted,如果uid不是Trusted,就读取isUidActive、isCameraPrivacyEnabled;
- isUidActive如果为true表示APP在前台,如果为false表示在后台;
- isCameraPrivacyEnabled如果为true表示camera的隐私权限被打开了,预览流的图像不能呈现给用户,但是可以openCamera,如果为false表示随便看camera预览图像;
- 第三步:如果Camera Privacy Enabled,这里趋向于继续让OpenCamera正常执行(不返回-EACCES),后续做mute动作;
监听Camera预览过程中操作权限发生改变
- 第一步:判断mAppOpsManager是否为空,如果不为空判断op是否为OP_CAMERA,如果是就调用checkOp获取到mode;
- 第二步:针对MODE_ERRORED、MODE_IGNORED和MODE_ALLOWED三种Mode做了处理;
- MODE_ERRORED在使用camera过程中不允许使用camera,block()关闭Camera;
- MODE_IGNORED下面说,mute camera或block camera或者什么都不做,mute意思是hal返回test pattern的图像或者一张黑图,block是会直接关闭Camera;
- MODE_ALLOWED表示opchange,之前不允许现在允许,设置override mute mode;
MODE_IGNORED
- 读取isUidActive、isCameraPrivacyEnabled,如果不是mUidIsTrusted,如果是isUidActive,如果隐私打开,检查是否支持mute.
5.10 UidPolicy控制逻辑
Android 如何查看进程的UID
- 可以通过ps –A来查看,一个UID下面可以有多个进程
- ps -A |grep com.android.camera
单用户情况
- 比如命令显示u0_a001表示该应用是use0下面的应用,user0是主用户,id是001
- 普通应用程序的UID都是从10000开始的,所以最终计算出的UID就是10001
多用户情况
- 比如命令显示可以看到其他用户u14_a001,userID是14,计算方式是:100000*14+10106=1410106
UidPolicy与AMS的交互
- UidPolicy类是CameraService创建的,用于监控Client UID的状态变化,当UID状态为IDLE时不允许使用Camera。
UidPolicy与AMS的交互逻辑,监控uid的变化:
- 第一步:CameraService起来后会用linkToDeath监控AMS是否有crash,registerUidObserverForUids告诉AMS需要监控哪些uid,第一次注册时发送的uid列表是空的;
- 第二步:有调用者client端开始addListener/openCamera就会执行registerMonitorUid,监控调用者client端;
- 第三步:在camera运行过程中AMS会回调uid状态的变化;
- 第四步:调用者client端不使用camera时removeListener/CloseCamera会调到removeUidFromObserver,最后调用者client结束时执行unregisterUidObserver/unlinkToDeath;
UidPolicy成员变量
- mRegistered:是否向AMS注册了监听uid,如果AMS比CameraService后启动或AMS突然挂了,这个变量可能会为False;
- mActiveUids:处于Active状态的uid列表;
- mMonitoredUids:正在监控的uid列表;
- mOverrideUids:保存UID的Override状态,用于debug,通过cmd命令设置;
UidPolicy方法
- registerSelf()/unregisterSelf():注册/注销UID Observer,CameraService::onFirstRef call registerSelf,CameraService::~CameraService call unregisterSelf;
- isUidActive(uid_t uid, String16 callingPackage):判断当前UID是否处于Active状态;
- getProcState(uid_t uid):获取当前UID的ProcState;
- IUidObserver的回调方法:处理UID状态发生变化;
- addOverrideUid/removeOverrideUid:设置/移除某个UID的Override状态,修改mOverrideUids列表,用于debug;
- registerMonitorUid/unregisterMonitorUid:注册/注销监听某个Uid的状态变化;
- onServiceRegistration:监听AMS服务注册上了,有可能AMS比CameraService起来得慢一些/AMS挂掉重启,因此需要AMS启动后才能去注册监听UID状态;
- binderDied:AMS服务挂掉了,等AMS重启后要重新注册;
IUidObserver回调接口
- void onUidGone(int uid, boolean disabled);:当前UID的所有进程没有运行;
- void onUidActive(int uid);:当前UID的所有进程在前台运行,处于Active状态;
- void onUidIdle(int uid, boolean disabled);:当前UID处于IDLE状态,UID的进程在后台运行了一段时间了或者UID的进程都未运行,需要把client和cameraservice block,因为IDLE状态的client禁止使用camera;
- void onUidStateChanged(int uid, int procState, long procStateSeq, int capability);:当前UID的procState发生变化;
- void onUidProcAdjChanged(int uid, int adj);:当前UID的所有进程oom adj值发生变化;
onUidIdle处理流程
- 当Camera App从前台切到后台时,如果没有close camera,onUidIdle回调会被调用,如果uid没在mActiveUids里面,执行blockClientsForUid,阻止调用者client端使用cameraservice,从而防止在后台使用Camera;
onUidStateChanged处理流程
- UID的所有进程ProcState发生变化,就会执行onUidStateChanged,如果从mMonitoredUids检查当前UID的所有进程ProcState发生变化,会通知所有客户端的onCameraAccessPrioritiesChanged;
- onCameraAccessPrioritiesChanged:如果其他调用者客户端收到这个接口的回调,可以重新再openCamera,可能之前和其他进程抢占某颗camera没有成功,自己进程优先级低,可以再次重新连接这颗camera;
- onCameraAccessPrioritiesChanged:如果其他调用者客户端收到这个接口的回调,可以重新再openCamera,可能之前和其他进程抢占某颗camera没有成功,自己进程优先级低,可以再次重新连接这颗camera;
onUidProcAdjChanged处理流程
- 当ProcAdj发生变化时,判断当前uid的进程是否在mMonitoredUids,判断当前uid的进程是否在使用camera,如果在使用camera,将自己及adj小于自己的UID放在notifyUidSet,会通知放在notifyUidSet里面Listener的onCameraAccessPrioritiesChanged;
5.11 SensorPrivacyPolicy
SensorPrivacyPolicy的作用
- SensorPrivacyPolicy用于控制sensor隐私,SensorPrivacy和CameraPrivacy;
- SensorPrivacy: 启用后,不允许所有App使用Camera,包括正在使用Camera的App,会强制关闭/不允许打开Camera;
- CameraPrivacy: 启用后,先判断这颗Camera是否支持mute,如果支持MuteCamera则直接Mute,返回黑图,否则会关闭Camera/不允许打开Camera;
SensorPrivacyPolicy与SensorPrivacyManager的交互
- 第一步:CameraService::onFirstRef起来时,执行linkToDeath连接systemserver监听systemserver挂掉,调用addSensorPrivacyListener监听systemserver的Litener,如果调用者客户端断开连接CameraService,CameraService销毁时会调用removeSensorPrivacyListener;CameraService::onFirstRef起来时也会执行isSensorPrivacyEnabled,表示监听的Sensor有一个SensorPrivacyEnabled就返回true;
- 第二步:在CameraService::connectHelper时会主动判断camera的SensorPrivacy是否Enabled,如果有enable,在connectHelper时会走CameraSensorPrivacy的逻辑,如果在使用过程中,SensorPrivacy发生改变,更新mSensorPrivacyEnabled,如果隐私权限打开了关闭所有camera;
SensorPrivacyPolicy方法详解
- registerSelf()/unregisterSelf():注册/注销SensorPrivacyListener;
- isSensorPrivacyEnabled():判断是否有一个SensorPrivacy是否使能了;
- isCameraPrivacyEnabled():判断是否有一个CameraPrivacy是否使能了;
- onSensorPrivacyChanged:SPM回调通知sensorPrivacy发生变化了;
- onServiceRegistration:如果SPM挂掉或者比cameraservice后起来,会执行onServiceRegistration,重新注册SPM;
- binderDied:SPM服务挂掉了,等SPM重启后要重新注册;
5.12 CameraDeviceClient
CameraDeviceClient初始化
- 第一步: Camera2ClientBase初始化:创建CameraDeviceBase,startCameraOps,启动Camera2ClientBaseWatchdog监控Camera2ClientBase;
- 第二步:FrameProcessor初始化;
- 第三步:CameraDeviceClient用到的静态Metadata初始化;
Camera2ClientBase初始化
-
第一步:根据providerTransport拿到是HIDL/AIDL创建HidlCamera3Device/AidlCamera3Device,执行mDevice->initialize;
-
第二步:执行startCameraOps和AppOpsManager交互,再次检查调用者客户端是否有使用Camera的权限,如果没有权限还要closeCamera;
-
第三步:mDevice->setNotifyCallback将NotificationListener设置给CameraDevice,CameraDevice通知回调;
-
第四步:启动Camera2ClientBase的Watchdog,监听disconnect是否超时;
-
NotificationListener给CameraDevice回调通知
-
notifyError:通知错误,比如hal发生错误,不能生成buffer、hal crash,回调到Camera2Client这边,在回调到调用者Client APP;
-
notifyPhysicalCameraChange:如果使用logical multi-camera,通知回调当前哪颗physical camera目前处于Active状态;
-
notifyActive:通知CameraDevice处于Active出流状态;
-
notifyIdle:通知CameraDevice处于IDLE不出流状态;
-
notifyShutter:只有API2才有通知每帧的shutter事件;
-
notifyPrepared:通知某路流prepare结束,prepare是指提前申请streambuffer;
-
notifyRequestQueueEmpty:通知RequestQueue空了;
-
notifyAutoFocus/notifyAutoExposure/notifyAutoWhitebalance:只有API1使用,FrameProcessor通知3A信息;
-
notifyRepeatingRequestError:对Repeating用的Surface发生abandon了,abandon是指Surface消费端,比如serfaceflinger、appEncoder主动把bufferqueue释放掉了,cameraservice就不能送buffer;
FrameProcessor初始化
- FrameProcessor处理回调的Metadata的架构
- FrameProcessorBase启动一个线程调用FrameProducer,Camera3Device继承FrameProducer,就是调到Camera3Device的waitForNextFrame和getNextResult从ResultQueue里面获取可用的CaptureResult;
FrameProcessorBase.hstruct FilteredListener: virtual public RefBase {virtual void onResultAvailable(const CaptureResult &result) = 0;};
- FrameProcessor用RangeListener封装filteredListener,来管理每个客户端对Metadata的需求;
FrameProcessorBase.h
struct RangeListener {int32_t minId;int32_t maxId;wp<FilteredListener> listener;bool sendPartials;
};
List<RangeListener> mRangeListeners;
- 如果是API1,FrameProcessor的RangeListener可以同时注册多个Listener客户端,如果是API2会调用CameraDeviceClient注册一个listener到FrameProcessorBase;
CameraDeviceClient用到的静态Metadata初始化
- mSupportedPhysicalRequestKeys:如果是logical multi-camera,它对应的PhysicalCamera支持哪些RequestKeys,上层submitRequest时,把某颗PhysicalCamera不支持的Request参数remove掉;
- mDynamicProfileMap:针对hdr,key:profile id, value:Supported dynamic profiles bit map,存放支持的DynamicRangeProfiles,submitRequest时会对设置的值做检查;
- mHighResolutionSensors:支持高分辨率流的CameraDevice,前提要有ULTRA_HIGH_RESOLUTION_SENSOR capability,上层submitRequest时会对CONTROL_SENSOR_PIXEL_MODE做检查,要求Request和configure时填的值是一样的;
5.13 Camera3Device
Camera3Device架构
- client和device是一对一的关系,一个Camera2Client或者CameraDeviceClient就对应一个Camera3Device;
- 第一步:上层调用端使用cameraserver API先到client这边,如果需要client操作device,就会使用CameraDeviceBase,如果device有状态回调到client,通过FrameProducer主动调用,也可以用Camera3Device持有的NotificationListener回调;
- 第二步:Camera3Device调用hal时使用AidlCamera3Device或者HidlCamera3Device,都是在创建device时判断接口类型是AIDL/HIDL。AidlCamera3Device依赖AidlCameraDeviceCallbacks,HidlCamera3Device继承ICameraDeviceCallback;
- 第三步:hal回调返回的数据,如果是数据流,Camera3Device里面的outputStream可以调用stream的接口,比如returnbuffer,把buffer送到consumer端;如果是metadata,返回给client,再送给上层调用者APP;
Camera3Device核心内部类
Camera3Device::RequestThread:用于维护送给HAL的CaptureRequest的线程;
Camera3Device::HalInterface:Camera HAL ICameraDeviceSession类的封装;
Camera3Device::Camera3DeviceInjectionMethods:Inject Camera使用,意思是把外部的camera替换到内部camera,把HalInterfaceh对象换成mInjectedCamHalInterface从而调用ICameraInjectionSession。
- ICameraInjectionSession:提供了一种机制,允许外部Camera设备无缝地替代内部Camera,同时保持与原有Camera配置的兼容性。
- 这对于需要临时使用外部Camera(如USB Camera)替代内置Camera的场景非常有用。
CameraDeviceBase成员变量
- mImageDumpMask::bool:用于debug,如果是true,表示dump某个image,
dumpsys media.camera
会使用,可以把mImageDumpMask设置为turue,设置给Output Stream,用于标识是否打开Jpeg Image Dump功能; - mStreamUseCaseOverrides::vector<int64_t>:用于debug,
dumpsys media.camera
会使用,设置给Output Stream,用于记录Stream的Usecase覆盖列表;
ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES如下:
system/media/camera/include/system/camera_metadata_tags.h
typedef enum camera_metadata_enum_android_scaler_available_stream_use_cases {ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_DEFAULT = 0x0, // HIDL v3.8ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW = 0x1, // HIDL v3.8ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_STILL_CAPTURE = 0x2, // HIDL v3.8ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_RECORD = 0x3, // HIDL v3.8ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_PREVIEW_VIDEO_STILL = 0x4, // HIDL v3.8ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VIDEO_CALL = 0x5, // HIDL v3.8ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_CROPPED_RAW = 0x6, // HIDL v3.9ANDROID_SCALER_AVAILABLE_STREAM_USE_CASES_VENDOR_START = 0x10000, // HIDL v3.8
} camera_metadata_enum_android_scaler_available_stream_use_cases_t;
Camera3Device成员变量
- mCameraServiceProxyWrapper::CameraServiceProxyWrapper:在Camer3Device中使用这个的目的: 1. 用于产生唯一的logId,调用AIDL HAL configureStreams时使用;2. 用于记录reconfigureCamera的耗时;
- mId::String8:当前Camera3Device的ID;
- mLegacyClient::bool:表示是否是Camera API1的Client;
- mOperatingMode::int:Configure streams带下来的OperationMode;
- mSessionParams::CameraMetadataNative:ConfigureStreams带下来的SessionParameter;
- mIsConstrainedHighSpeedConfiguration::bool:标识是否是HighSpeedConfiguration,有一些逻辑需要特殊处理;
- mInterface::HalInterface:Camera HAL ICameraDeviceSession类的封装;
- mDeviceInfo::CameraMetadata:存放当前Camera的静态信息;
- mPhysicalDeviceInfoMap::unordered_map<std::string, CameraMetadata>:key是pysicalCameraId,如果是Logical multi-cam,存放每个PhysicalCamera的静态信息;
- mSupportNativeZoomRatio::bool:是否支持通过ZoomRatio来控制Zoom;
- mIsCompositeJpegRDisabled::bool:是否支持JPEG_R的Stream。 JPEG_R结合了传统的JPEG压缩图像和嵌入式恢复映射(recovery map)。这种格式主要用于支持Ultra HDR(高动态范围)图像。
- mRequestTemplateCache::CameraMetadata:缓存默认的CaptureRequest,可存放不同Template的CaptureRequest;
- mStatus::enum Status:记录当前CameraDevice的状态;
- mRecentStatusUpdates::Vector:记录最近更新的Status,在waitUntilStateThenRelock方法使用;
- mOutputStreams::StreamSet:当前CameraDevice配置的输出流;
- mInputStream::Camera3Stream:当前CameraDevice配置的输入流;
- mSessionStatsBuilder::SessionStatsBuilder:统计Stream的Stats,产生直方图,可以分析黑屏问题;
- mGroupIdPhysicalCameraMap::std::map<int32_t, std::set>:Stream GroupID与Physical Camera ID的映射关系 针对Multi Resolution的Stream才有GroupID,请求Physical Camera Stream时使用;
- mNextStreamId::int:单调递增,用于产生Stream ID;
- mNeedConfig::bool:标识是否需要执行config stream,如果条件未变,不重复configure;
- mFakeStreamId::int:针对configure stream时mOutputStreams size为0的规避解法,解决bug时使用;
- mPauseStateNotify::bool:用于内部做reconfiguration时,skip掉state更新通知,比如session parameters改变时需要做reconfiguration;
- mDeletedStreams::Vector<sp< camera3::Camera3StreamInterface>>:持有待删除的Stream,直到configure结束。有可能在configure的过程中发生Flush,这时也需要对被即将Delete的Stream做Flush;
- mUsePartialResult::bool:标识HAL是否使用Partial Result,就是hal是否把Result拆成多包回调;
- mNumPartialResults::uint32_t:有多少包PartialResult,cameraserver会把PartialResult缓存下来,默认值是1;
- mDeviceTimeBaseIsRealtime::bool:TimestampSource是否是Realtime,如果是需要对timestamp进行矫正;
- mTimestampOffset::nsecs_t:MonotonicTime到BootTime的偏移值;
- mRequestThread::sp:处理下发Request的线程;
- mInFlightMap::InFlightRequestMap:送给HAL,正在被HAL处理的RequestList;
- mExpectedInflightDuration::nsecs_t:用于判断HAL处理request是否发生Timeout,最小5秒;
- mStatusTracker::wp:跟踪Camera3Device的状态切换;
- mBufferManager::sp:管理OutputStream的GraphicBuffer,OutputStream不是通过bufferqueue申请,是由cameraserver通过Graphic接口申请,,一个Camera3Device只有一个BufferManager。为了优化内存用量而使用,比如configStream有16;
- mPreparerThread::sp:用于执行streamPrepare的线程;
- mResultQueue::std::list:用于存放HAL送上来的CaptureResult;
- mListener::wp:用于Camera3Device回调Client;
- mDistortionMappers::std::unordered_map<std::string, camera3::DistortionMapper>:对于支持畸变矫正的Camera,对CaptureRequest和CaptureResult进行修正;
- mZoomRatioMappers::std::unordered_map<std::string, camera3::ZoomRatioMapper>:处理Zoom Ration与Crop Region之间的转换,对CaptureRequest和CaptureResult进行修正;
- mUHRCropAndMeteringRegionMappers::std::unordered_map<std::string, camera3::UHRCropAndMeteringRegionMapper>:对于支持ULTRA HIGH RESOLUTION的Camera,对CaptureRequest进行修正;
- mRotateAndCropMappers::std::unordered_map<std::string, camera3::RotateAndCropMapper>:对于支持Auto rotate-and-crop的Camera,对CaptureRequest和CaptureResult进行修正;
- mRotateAndCropOverride::camera_metadata_enum_android_scaler_rotate_and_crop_t:
dumpsys media.camera
Debug使用,强制设置RotateAndCrop Mode; - mTagMonitor::TagMonitor:Debug使用,用于跟踪CaptureRequest/CaptureResult中的Metadata变化情况;
- mVendorTagId::metadata_vendor_id_t:标识Vendor Tag的ID,不同Camera可以有不同的Vendor Tag ID,用于操作Vendor Tag;
- mLastTemplateId::int:存放最后一次获取默认CaptureRequest的Template ID,如果configure streams没有带session parameters,则以这个CaptureRequest设置为session parameters;
- mAutoframingOverride::camera_metadata_enum_android_control_autoframing:
dumpsys media.camera
Debug使用,强制设置Autoframing Mode; - mActivePhysicalId::std::string:如果当前使用的是Logical Multicam的情况,记录目前正在使用的Physical Camera ID;
- mInjectionMethods::sp:Inject Camera时使用;
5.14 Camera3Device初始化
Camera API2 Open
CameraAPP调用CameraManager的openCamera方法,调用到CameraService的connectDevice,然后创建CameraDeviceClient,在Camera2ClientBase的initializeImpl中创建AidlCamera3Device,然后在AidlCamera3Device的initialize方法中调用CameraProviderManager的openAidlSession方法,进而通过ICameraDevice的open方法调用到HAL去执行openCamera动作。
AidlCamera3Device::initialize()
- 创建Session:与HAL交互打开Camera;
- CAMERA CHARACTERISTICS:获取静态Metadata,判断是否支持mSupportNativeZoomRatio、mIsCompositeJpegRDisabled;
- LOGICAL MULTI-CAMERA CONFIGURATION:如果是LogicalMulticam,则对mPhysicalDeviceInfoMap、mDistortionMappers、mZoomRatioMappers、mUHRCropAndMeteringRegionMappers进行相应的赋值;
- METADATA QUEUES:初始化MetadataQueue,MetadataQueue包含request和result,通过FMQ (Fast Message Queue) 用共享内存的方式来传递CaptureRequest和CaptureResultMetadataBuffer,共享内存更快,不能用IPC机制拷贝,太慢了;
Camera3Device::initializeCommonLocked()
CameraDevice线程管理:
- StatusTracker:监控request状态和device状态;
- RequestThread:送request,包括从里面拿buffer,比如bufferqueue没有buffer,再去获取buffer就会被block;
- PreparerThread:送request之前把某一路buffer,提前Preparer出来,能优化整个性能;
- CameraServiceWatchdog:监控cameraDevice;