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;