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 結構圖

camera 結構圖

1. 啟動CameraServer

1.1 注冊media.camera服務

將media.camera注冊到ServiceManager。
在這里插入圖片描述

1.2 構造CameraService

  1. AttributionAndPermissionUtilsEncapsulator:
  2. mCameraServiceProxyWrapper:
  3. mEventLog:打開或者關閉camera的event log;
  4. mNumberOfCameras:camera的數量;
  5. mNumberOfCamerasWithoutSystemCamera:剔除systemCamera以后得數量;
  6. mSoundRef:控制mAudioRestriction;
  7. 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代碼:
在這里插入圖片描述
主要接口:
在這里插入圖片描述
作用:

  1. ICameraProvider:由CameraHALProvider實現,幫助cameraserver調到CameraHALProvider;管理多個ICameraDevice;
  2. ICameraProviderCallback:由CameraServer實現,幫助CameraHALProvider調到cameraserver;
  3. ICameraDevice:代表并管理某一個CameraDevice(Physical Camera、Logical Camera);
  4. ICameraDeviceSession:打開camera后,hal device操作device;
  5. 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初始化

  1. 什么時候調用enumerateProviders

    • CameraServer進程啟動時調用CameraService::onFirstRef;
    • CameraServer進程啟動后,有新的Provider注冊到ServiceManager時調用CameraService::onNewProviderRegistered;
  2. enumerateProviders

    • 創建CameraProviderManager,并調用initialize完成初始化;
    • 初始化VendorTags;
    • 初始化Flashlight,完成枚舉動作;
    • 獲取所有deviceId,把deviceId設置成PRESENT,即設置成可用狀態;
    • 針對前/后攝,為SPerfClass過濾CameraCharacteristics;
      • SPerfClass是為不同安卓手機定義的Performmance的級別,為了滿足CDD要求過濾CameraCharacteristics;
  3. CameraHALProvider初始化流程
    在這里插入圖片描述
    Add Hidl Provider重要流程:

    1. 在registerForNotifications方法中,向hwservicemanager/ServiceManager.cpp注冊ICameraProvider的HidlService的Notification,如果HidlService注冊到hwservicemanager;
      • registerForNotifications的回調方法是onRegistration,如果收到onRegistration回調通知,會調到CameraServer::onNewProviderRegistered,告訴CameraServer注冊成功,也會做addHidlProviderLocked操作;
    2. 用listServices方法查找hwservicemanager中有多少是ICameraProvider的HidlService,然后做addHidlProviderLocked操作,創建HidlProviderInfo;
  • registerForNotifications方法的作用:
    • CameraServer監聽Provider,防止hal進程比CameraServer啟動慢;
    • 防止hal進程發生crash重啟,hal進程會重啟并重新注冊到HwServiceManager,CameraServer會收到hal進程重新注冊回調;

1.4.1 initializeHidlProvider:HIDL Provider初始化

HidlProviderInfo::initializeHidlProvider

  1. castFrom:判斷ICameraProvider的mMinorVersion;
  2. setCallback:Cameraserver接收hal的ICameraProviderCallback的回調;
  3. linkToDeath:這是監聽HidlService掛掉,上面的onRegistration是監聽注冊成功,在HidlProviderInfo::serviceDied方法處理HidlService掛掉后的異常,從mProviders 中刪掉Provider;
  4. notifyDeviceStateChange:通知HAL進程,當前攝像頭的狀態(NORMAL/BACK_COVERED被蓋住/FRONT_COVERED前置被蓋住/FOLDED折疊狀態,可以一次性通知多個狀態),只有在Provider 2.5及之后的版本才有;
  5. setUpVendorTags:調用ICameraProvider的getVendorTags方法拿到VendorTagSection,然后創建VendorTagDescriptor,通過VendorTagDescriptor就能知道有哪些Vendor Tag了;
  6. interface->getCameraIdList:獲取當前Provider有多少Camera Device,解析出Camera ID存放在mProviderPublicCameraIds(interface = ICameraProvider);
  7. getConcurrentCameraIdsInternalLocked:如果Provider >= 2.6,獲取哪些Camera可以同時做ConfigureStream,存放在mConcurrentCameraIdCombinations;
  8. interface->isSetTorchModeSupported:判斷是否支持手電筒,結果存放在mSetTorchModeSupported;
  9. initializeProviderInfoCommon:完成Device的初始化;

1 initializeProviderInfoCommon

CameraProviderManager::ProviderInfo::initializeProviderInfoCommon
在這里插入圖片描述

主要完成2件事情:

  1. 調用addDevice將CameraDevice保持在mDevices中;
  2. 處理cachedStatus回調,就是初始化Provider過程中,Device狀態發生變化,先把狀態緩存起來,初始化Provider結束后再做狀態變化操作;

1.4.2 addDevice:HIDL Device初始化

CameraProviderManager::ProviderInfo::addDevice

  1. 檢查CameraDevice的版本是否正確:
    1. 根據device的name解析出的Camera ID、MajorVersion、IPCTransport都必須唯一;
    2. IPCTransport::HIDL的對應的Device MajorVersion必須為3,IPCTransport::AIDL的對應的Device MajorVersion必須為1;
  2. initializeDeviceInfo:初始化Camera Device Info,由AIDLProviderInfo/HIDLProviderInfo實現;(重點)
  3. notifyDeviceStateChange:根據手機狀態去更新ANDROID_SENSOR_ORIENTATION,這里的DeviceState不是手機攝像頭狀態,是指手機狀態;
  4. 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

  1. 獲取到ICameraDevice的實例:調用ICameraProvider的getCameraDeviceInterface_V3_x獲取到ICameraDevice的實例,不會每次都調用Provider接口,HidlDeviceInfo3會緩存ICameraDevice實例;
  2. cameraInterface->getResourceCost:調用ICameraDevice的getResourceCost獲取到ResourceCost,ResourceCost是指統計打開camera消耗的資源得分,超過100就禁止打開;
  3. new HidlDeviceInfo3:處理靜態信息,比如獲取SystemCameraKind和修復/更新mCameraCharacteristics(重點)
1.4.2.2 new HidlDeviceInfo3
  1. 獲取CameraCharacteristics:調用getCameraCharacteristics獲取metadata放入mCameraCharacteristics(Characteristics:靜態信息)
  2. 獲取DeviceStateOrientationMap:獲取 ANDROID_INFO_DEVICE_STATE_ORIENTATIONS的值,保存在mDeviceStateOrientationMap
  3. 獲取到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
  4. 修復/更新mCameraCharacteristics:fixupMonochromeTags、addDynamicDepthTags、deriveHeicTags、addRotateCropTags、addPreCorrectionActiveArraySize、overrideZoomRatioTags、fixupTorchStrengthTags、queryPhysicalCameraIds(重點)
  5. 修復/更新未Public出去的PhysicalCameraCharacteristics: overrideZoomRatioTags(重點)
1.4.2.3 修復/更新 mCameraCharacteristics
  1. 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個通道設為同一個值。
  1. 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
  1. 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
  1. CameraProviderManager::ProviderInfo::DeviceInfo3::addRotateCropTags
  • 如果ANDROID_SCALER_AVAILABLE_ROTATE_AND_CROP_MODES沒有填,則至少填一個值:ANDROID_SCALER_ROTATE_AND_CROP_NONE
  1. ameraProviderManager::ProviderInfo::DeviceInfo3::addPreCorrectionActiveArraySize
  • 如果ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE沒有填,則獲取ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE的值填進去
  1. 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
  1. CameraProviderManager::ProviderInfo::DeviceInfo3::fixupTorchStrengthTags
  • 如果沒有填ANDROID_FLASH_INFO_STRENGTH_DEFAULT_LEVEL,則填成1
  • 如果沒有填ANDROID_FLASH_INFO_STRENGTH_MAXIMUM_LEVEL,則填成1
  1. CameraProviderManager::ProviderInfo::DeviceInfo3::queryPhysicalCameraIds
  • 如果支持LogicalCamera,則從ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS獲取到PhysicalCameraIds放到mPhysicalIds
  1. 修復/更新 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

  1. APP只能看見LogicalCameraId或者LogicalCameraDevice,如果APP看到的是LogicalMultiCamera,邏輯上是一個CameraDevice,但是有多個CameraDevice硬件;

  2. logical 和 physical有值的對應關系。

    1. 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:

  1. initializeProviderInfoCommon主要完成2件事情:

    • 調用addDevice將CameraDevice保持在mDevices中;
    • 處理CachedStatus回調;
      前面的課程已經介紹了addDevice的邏輯,這里介紹處理Cached Status回調。
  2. 什么時候會有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

  1. 在mDevices中根據cameraDeviceName找到對應的DeviceInfo;
    • 如果找到,狀態為NOT_PRESENT,執行removeDevice;
    • 如果沒有找到,狀態為PRESENT,執行addDevice;
  2. reCacheConcurrentStreamingCameraIdsLocked;
  3. 返回cameraId;

4 onDeviceStatusChanged
CameraService::onDeviceStatusChanged

  1. getCameraState(cameraId):獲取cameraDevice的狀態;
    • 如果獲取的state為空,執行addStates、updateStatus;
  2. 如果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;

CameraService::onDeviceStatusChanged,兩個參數的方法是logical使用。

5 updateStatus
CameraService::updateStatus

  1. 獲取cameraId狀態
  2. getSystemCameraKind:是系統分區的camera,還是vender分區的camera;
  3. getCameraCharacteristics;
  4. 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對象,步驟:
  1. mCameraProviderManager->getResourceCost;
  2. mCameraProviderManager->getSystemCameraKind;
  3. mCameraProviderManager->isLogicalCamera;
  4. 執行updateCameraNumAndIds,更新mCameraStates、mTorchStatusMap、mNumberOfCameras、mNormalDeviceIds: 能兼容api1和api2;
  5. logDeviceAdded: 打印event log;

7 removeStates
CameraService::removeStates

  1. updateCameraNumAndIds:更新cameraNumber、cameraId;
    • mCameraProviderManager->getCameraCount();
    • 更新mNumberOfCameras、mNormalDeviceIds;
  2. 從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;

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

  1. 每個AIDL Provider都要注冊一次sm->registerForNotifications,多個HIDL只會注冊一次;
  2. tryToInitializeAidlProviderLocked–>initializeAidlProvider;
  3. initializeAidlProvider:
    1. 不需要像HIDL判斷版本,aidl只有一個版本,直接調用setCallback方法,接收ICameraProvider的回調;
    2. 調用AIBinder_linkToDeath方法,監聽binderDied方法,處理Hal進程掛掉后的異常;HIDL是監聽serviceDied方法處理hal掛掉后的異常;
    3. notifyDeviceStateChange:更新state
    4. setUpVendorTags
    5. getCameraIdList
    6. getConcurrentCameraIdsInternalLocked
    7. 直接將mSetTorchModeSupported = true;HIDL調用isSetTorchModeSupported,判斷是否有一個cameraDevice是否支持TorchMode,AIDL不需要,因為在各自的device會判斷是否支持touch;
    8. initializeProviderInfoCommon

AIDL CameraDevice初始化

AidlProviderInfo::initializeDeviceInfo,AIDL初始化CameraDevice和HIDL初始化CameraDevice的流程一樣。

  1. 獲取ICameraDevice的實例:調用ICameraProvider的getCameraDeviceInterface獲取到ICameraDevice的實例;
    • startDeviceInterface–>interface->getCameraDeviceInterface
  2. 調用ICameraDevice的getResourceCost獲取到ResourceCost;
  3. 創建AidlDeviceInfo3:處理靜態信息,比如獲取SystemCameraKind和修復/更新mCameraCharacteristics;

創建AidlDeviceInfo3完成5件事情

AidlDeviceInfo3::AidlDeviceInfo3

  1. 獲取CameraCharacteristics:調用getCameraCharacteristics對mCameraCharacteristics賦值;
  2. 獲取DeviceStateOrientationMap:獲取ANDROID_INFO_DEVICE_STATE_ORIENTATIONS的值,保存在mDeviceStateOrientationMap;
  3. 獲取到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
  4. 修復/更新 mCameraCharacteristics:fixupMonochromeTags、addDynamicDepthTags、deriveHeicTags、addRotateCropTags、addPreCorrectionActiveArraySize、overrideZoomRatioTags、fixupTorchS
  5. 修復/更新 未Public 出去的PhysicalCamera Characteristics:
  6. 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之間的關系:

keyvalue
vendorId1VendorTagDescriptor1

2 Flashlight初始化

主要工作:判斷每顆camera里面是否有flashUnit這個硬件單元。

CameraServer通過CameraFlashlight來管理各個CameraDevice的Flashligh:
在這里插入圖片描述

通過CameraFlashlight::findFlashUnits完成Flashlight的初始化,流程如下:
CameraFlashlight::findFlashUnits:

  1. mProviderManager->getCameraDeviceIds:拿到所有支持的Id;
  2. 遍歷所有cameraIds,如果cameraId在mHasFlashlightMap不存在,執行createFlashlightControl;
    1. createFlashlightControl:查詢CameraProviderManager是否支持設置TorchMode,如果支持則創建ProviderFlashControl;
    2. 執行mFlashControl->hasFlashUnit(id, &hasFlash):判斷是否支持Flash,更新hasFlash,最終是從ProviderInfo的mCameraCharacteristics讀取ANDROID_FLASH_INFO_AVAILABLE來給mHasFlashUnit賦值;
    3. 執行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
流程:

  1. 初始化firstRearCameraSeen、firstFrontCameraSeen
  2. 遍歷mNormalDeviceIdsWithoutSystemCamera,去掉SystemCamera
    1. getDeviceVersion獲取到Facing
    2. 如果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主要的接口詳解:

  1. int getNumberOfCameras(int type);
    • 獲取當前平臺支持多少顆Camera,廢棄;
  2. CameraInfo getCameraInfo(int cameraId);
    • 獲取某顆Camera的基本信息(facing和orientation),API2不使用該API;
  3. ICamera connect()
    • Open某顆Camera,獲取到ICamera 實例,API2不使用該API;
  4. 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里去;
  5. CameraStatus[] addListener(ICameraServiceListener listener);
    • 注冊Listener,監聽CameraService狀態變化,比如CameraDevice、Torch變化;
  6. ConcurrentCameraIdCombination[] getConcurrentCameraIds();
    • 獲取可以并發訪問的Camera ID組合;
  7. boolean isConcurrentSessionConfigurationSupported( in CameraIdAndSessionConfiguration[] sessions, int targetSdkVersion);
    • 同時使用多顆Camera時,判斷并發SessionConfiguration是否支持;
  8. void removeListener(ICameraServiceListener listener);
    • 刪除Listener,取消監聽CameraService狀態變化;
  9. CameraMetadataNative getCameraCharacteristics(String cameraId, int targetSdkVersion);
    • 獲取指定Camera的靜態CameraMetadata;
  10. VendorTagDescriptor getCameraVendorTagDescriptor();
    • 獲取VendorTagDescriptor,在CameraMetadataNative解析Vendor Tag時需要用到;
  11. VendorTagDescriptorCache getCameraVendorTagCache();
    • 獲取VendorTagDescriptorCache,其中存放不同VendorID的VendorTagDescriptor,在CameraMetadataNative解析Vendor Tag時需要用到
  12. boolean supportsCameraApi(String cameraId, int apiVersion);
    • 判斷當前平臺是否支持HAL3;
  13. boolean isHiddenPhysicalCamera(String cameraId);
    • 判斷指定的Camera是否是隱藏的PhysicalCamera,針對隱藏的PhysicalCamera,CamcorderProfile可能不可用,因此使用Stream configurationMap來獲取最大錄像size(MandatoryStreamCombination)。
  14. ICameraInjectionSession injectCamera(String packageName, String internalCamId, String externalCamId, in ICameraInjectionCallback CameraInjectionCallback);
    • 注入外部Camera來取代內部Camera,同一顆CameraID可以在Internal或External Camera間切換。
  15. void setTorchMode(String cameraId, boolean enabled, IBinder clientBinder);
    • 控制手電筒模式的ON/OFF
  16. void turnOnTorchWithStrengthLevel(String cameraId, int strengthLevel, IBinder clientBinder);
    • 調整手電筒的強度;
  17. int getTorchStrengthLevel(String cameraId);
    • 獲取當前手電筒模式的強度。
  18. oneway void notifySystemEvent(int eventId, in int[] args);
    • 向CameraService通知系統操作事件(多用戶切換、USB設備插拔事件),CameraServiceProxy調用。
  19. oneway void notifyDisplayConfigurationChange();
    • 向CameraService通知Display窗口配置發生變化,CameraServiceProxy調用;
  20. 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接口詳解

  1. oneway void onTorchStatusChanged(int status, String cameraId)
    • 回調通知FlashTorch模式的狀態變化;
  2. oneway void onTorchStrengthLevelChanged(String cameraId, int newTorchStrength)
    • 回調通知FlashTorch的強度發生變化;
  3. oneway void onCameraAccessPrioritiesChanged()
    • 當進程的adj或前后臺狀態發生變化時,會回調該方法,CameraService的任何一個client進程。
  4. oneway void onCameraOpened(String cameraId, String clientPackageId)
    • 回調通知某個client打開了某顆Camera,每一個client都有包名。
    • client需要有android.permission.CAMERA_OPEN_CLOSE_LISTENER權限。
  5. 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:

  1. void waitUntilIdle();
    • createCaptureSession時會先調stopRepeating,然后用該API等待上一次Session為IDLE;
  2. void beginConfigure()
    • 開始創建Session;
  3. int createStream(in OutputConfiguration outputConfiguration);
    • 根據OutputConfiguration創建OutputStream;
  4. void deleteStream(int streamId);
    • 根據streamId刪除未配置的Stream;
  5. int createInputStream(int width, int height, int format, boolean isMultiResolution);
    • 在Reprocess流程中,根據寬/高/format等信息創建Input Stream;
  6. int[] endConfigure(int operatingMode, in CameraMetadataNative sessionParams, long startTimeMs);
    • 結束創建Session;
    • 這是createCaptureSession最耗時的一步,傳給把參數傳給NativeFramework,然后完成真正的Session創建;

ICameraDeviceUser中與Buffer有關的API:

  1. boolean isSessionConfigurationSupported(in SessionConfiguration sessionConfiguration);
    • 對應CameraDevice的isSessionConfigurationSupported;
    • 判斷指定的SessionConfiguration是否支持,可以在創建Session之前判斷config的寬高、format、buffer的路數是否支持,找到底層支持的;sessionConfiguration;
  2. void prepare(int streamId);
    • 對應CameraCaptureSession的prepare;
    • 預申請某路流的Buffers, 這樣能提升第一幀到來的性能;
  3. void prepare2(int maxCount, int streamId);
    • 對應CameraCaptureSession的prepare;
    • 預申請某路流的Buffers,可以指定最大張數;prepare2是對prepare的補充;
  4. void updateOutputConfiguration(int streamId, in OutputConfiguration outputConfiguration);
    • 對應CameraCaptureSession的updateOutputConfiguration;
    • 更新OutputConfiguration;
  5. void finalizeOutputConfigurations(int streamId, in OutputConfiguration outputConfiguration);
    • 對應CameraCaptureSession的finalizeOutputConfigurations;
    • 最終決定OutputConfiguration;
  6. 對應CameraMetadataNative createDefaultRequest(int templateId);
    • CameraDevice的createCaptureRequest;
    • 根據templateId創建默認的CaptureRequest;
  7. SubmitInfo submitRequestList(in CaptureRequest[] requestList, boolean streaming)
    • 對應CameraCaptureSession的capture/captureBurst/setRepeatingRequest/setRepeatingBurst;
    • 向Framework送CaptureRequests;
  8. long cancelRequest(int requestId)
    • 對應CameraCaptureSession的stopRepeating;
    • 停止CaptureRequests,取消正在repeating的CaptureRequest,已經送到hal的繼續執行;
  9. long flush();
    • 對應CameraCaptureSession的abortCaptures;
    • 放棄正在處理隊列中,未被處理的Requests,Framework還在排隊準備送hal的session,送到hal還沒有處理的request也能結束;

ICameraDeviceUser中與OfflineSession和AudioRestriction相關的API:

  1. ICameraOfflineSession switchToOffline(in ICameraDeviceCallbacks callbacks, in int[] offlineOutputIds);
    • 對應CameraCaptureSession的switchToOffline;
    • 將當前的CameraCaptureSession切換到后臺繼續運行,應對快拍需求;
  2. Surface getInputSurface();
    • 對應CameraCaptureSession的getInputSurface;
    • 在Reprocess流程中,創建接受Input Buffer的Surface;
    • 意思是上層APP給底層送buffer,需要給APP提供一個InputSurface,APP往InputSurface quee buffer,底層就能收到;
  3. void setCameraAudioRestriction(int mode);
    • 對應CameraDevice 的 setCameraAudioRestriction;
    • 設置當前CameraDevice的Audio限制策略;
  4. int getGlobalAudioRestriction();
    • 對應CameraDevice的getCameraAudioRestriction;
    • 獲取當前CameraDevice的Audio限制策略;
  5. void disconnect()
    • 對應CameraDevice#close;
    • 關閉CameraDevice;

2.4 ICameraDeviceCallbacks.aidl詳解

1 ICameraDeviceCallbacks是什么
ICameraDeviceCallbacks是ICameraDeviceUser的回調類,回調以下信息給App:

  • CameraDevice的狀態;
  • 每一個CaptureRequest的狀態以及回調CaptureResult;

2 ICameraDeviceCallbacks.aidl類圖
在這里插入圖片描述

3 ICameraDeviceCallbacks.aidl接口詳解

  1. oneway void onPrepared(int streamId)
    • prepare/prepare2的回調函數,說明執行streamId的Stream已經prepare完成;
  2. oneway void onCaptureStarted( in CaptureResultExtras resultExtras, long timestamp);
    • 通知App,HAL開始處理一個CaptureRequest, 其中resultExtras存放的sequenceId,frameNumber等信息;timestamp是sencer開始曝光的時間點。
  3. 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;
  4. 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的生命周期出現問題;
  5. oneway void onRequestQueueEmpty();
    • CameraServer的Repeating的RequestQueue隊列為空,通知給App;
    • CameraServer有一個是Repeating的RequestQueue:拍照使用,另一個是Repeating的RequestQueue:預覽使用;
  6. oneway void onDeviceError( int errorCode, in CaptureResultExtras resultExtras)
    • 通知CameraApp,CameraDevice出現error,具體的error在errorCode里面描述;
  7. 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的類:

  1. impl/CameraMetadataNative.aidl
    • CameraMetadataNative.java
    • CameraMetadata.cpp
  2. impl/CaptureResultExtras.aidl
    • CaptureResultExtras.java
    • CaptureResult.cpp
  3. impl/PhysicalCaptureResultInfo.aidl
    • PhysicalCaptureResultInfo.java
    • CaptureResult.cpp
  4. params/OutputConfiguration.aidl
    • OutputConfiguration.java
    • OutputConfiguration.cpp
  5. params/SessionConfiguration.aidl
    • SessionConfiguration.java
    • SessionConfiguration.cpp
  6. params/VendorTagDescriptor.aidl
    • VendorTagDescriptor.java
    • VendorTagDescriptor.cpp
  7. params/VendorTagDescriptorCache.aidl
    • VendorTagDescriptorCache.java
    • VendorTagDescriptor.cpp
  8. utils/CameraIdAndSessionConfiguration.aidl
    • CameraIdAndSessionConfiguration.java
    • ConcurrentCamera.cpp
  9. utils/ConcurrentCameraIdCombination.aidl
    • ConcurrentCameraIdCombination.java
    • ConcurrentCamera.cpp
  10. utils/SubmitInfo.aidl
    • SubmitInfo.java
    • SubmitInfo.cpp
  11. CaptureRequest.aidl
    • CaptureRequest.java
    • CaptureRequest.cpp

為什么要自己寫Parcel對象的Java/C++端代碼

  • writeToParcel、readFromParcel邏輯復雜,無法通過代碼生成;
  • 在Java/C++端,Parcel對象中有非Binder通信調用的方法;

上面的Parcel對象主要用途:

  1. CameraMetadataNative
    • 本質上是CameraMetadata,封裝成camera_metadata_t;
  2. CaptureResultExtras
    • 存放CaptureResult各種索引信息,比如partialResultCount, requestId,回調給APP時會使用;
  3. PhysicalCaptureResultInfo
    • 把PhysicalCamera和PhysicalCameraMetadata做一個映射關系;
  4. OutputConfiguration
    • 描述一個OutputStream的配置信息(比如寬/高/是否shared等);
  5. SessionConfiguration
    • Session配置信息;
  6. VendorTagDescriptor
    • VendorTag的描述信息,Java端的沒有使用;
  7. VendorTagDescriptorCache
    • 按VendorID存放VendorTagDescriptor,Java端的沒有使用;
  8. CameraIdAndSessionConfiguration
    • 并行多顆Camera做ConfigureSession使用,可以并行做ConfigureSession的ID和SessionConfiguration;
  9. ConcurrentCameraIdCombination
    • 描述可以并行ConfigureSession的ID;
  10. SubmitInfo
    • 包括RequestId和LastFrameNumber,是submitRequestList的返回信息;
  11. 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實例;

  • 使用步驟:

    1. 如果有OpenCamera動作,OpenCamera–>Client–>CameraDevice–>平臺選擇HIDL/AIDL–>HAL;
    2. 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主要交互邏輯

  1. java層調用c++層:提供接口給上層控制操作CameraDevice,主要接口是CameraDeviceBase;
    • 調用過程:APP先調用Client,然后通過CameraDeviceBase調用CameraDevice,最后調到HAL;
  2. 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

  1. CameraDeviceBase繼承FrameProducer,FrameProducer是獲取某一幀的ResultMetadata;
  2. CameraDeviceBase接口用于Client操作HAL2/HAL3 Device, Camera2Device是過渡產品,代碼已經廢棄;
  3. HidlCamera3Device對接HIDL HAL層接口,AidlCamera3Device對接AIDL HAL層接口,他們都繼承自Camera3Device;
    在這里插入圖片描述

2 c++層回調java層,回調部分的ResultMetadata架構–>FrameProcessor

  1. 核心是FrameProcessorBase,它相當一個線程循環的處理FrameProducer的waitForNextFrame和getNextResult從mResultQueue里面獲取CaptureResult
  2. Camera API2的ResultMetadata處理邏輯在FrameProcessorBase里面;
  3. Camera API1的ResultMetadata處理邏輯在FrameProcessor里面;
  • 處理流程:
    1. Camera3Device不停的往FrameProducer的mResultQueue插入ResultMetadata,FrameProcessorBase循環從FrameProducer的mResultQueue獲取ResultMetadata;
    2. FrameProcessorBase會調用FrameProducer的waitForNextFrame獲取下一幀,獲取到后調用getNextResult從mResultQueue里面獲取CaptureResult;
    3. 處理完幀后,調用FrameProcessorBase::FilteredListener,最終會調用API2的CameraDeviceClient,這里面實現了onResultAvailable,它會把CaptureResult返回到上層APP;
      在這里插入圖片描述

3 c++層回調java層,API2回調部分的ImageBuffer架構 -->CameraStream

  1. Camera3Device根據hal的配置信息決定創建Camera3InputStream、Camera3OutputStream、Camera3SharedOutputStream;
  2. camera_stream:是一個結構體,camera_stream裝載hel傳上來的buffer流,是和hal層的stream長得一樣的結構體;
  3. Camera3Stream:
    1. 是InputStream和OutputStream的基類,繼承camera_stream,能把hal層的stream轉換成c++層cameraservice的stream;
    2. 維護Stream的狀態機切換;
    3. 提供接口訪問Stream的信息,比如ID、width、height、usage、dataspace等等;
    4. 提供接口轉換成hal層的stream;
  4. Camera3IOStreamBase:是InputStream和OutputStream的基類,管理整個stream的buffer狀態,哪些在hal,哪些已經回給我了,維護當前這路stream,一個stream有很多張buffer;
  5. Camera3OutputStreamInterface:
    1. Camera3Device對InputStream和OutputStream操作的流程完全不一樣,所以將OutputStream的特殊操作抽象出來放到Camera3OutputStreamInterface;
    2. 對InputStream的操作還是放在Camera3Stream;
      在這里插入圖片描述

4 c++層回調java層,API1回調部分的ImageBuffer架構–>Processor

  • 上層使用API1時,hal把Buffer送到我們的Stream后,要么直接送給上層這三類直接送給上層:StreamingProcessor、JpegProcessor、帶surface的CallbackProcessor;要么送給Processor取出Buffer通過binder回調給上層java層。
  • Processor:
  1. StreamingProcessor:用于預覽,創建PreviewStream和RecordingStream,上層APP會創建一個surface傳給c++層cameraservice,當hal3把buffer填充到我們的Stream后,Processor把buffer從Stream取出來,把buffer送到上層APP的surface;
  2. JpegProcessor:用于Jpeg拍照,創建一路Jpeg的Stream接收hal3傳上來的JpegBuffer,取出來JpegBuffer回調到上層;
  3. CallbackProcessor:用于預覽Callback,和StreamingProcessor一樣,創建一路Callback的Stream接收hal3上傳buffer,取出來buffer回調到上層;
  4. ZslProcessor:用于拍照時可以選到靠前的用戶看到的那張圖,用zslQueue做緩存,當拍照時從隊列取出來;
    在這里插入圖片描述

3.4 C++層CameraService的API1和API2調用HAL3流程

1. API1 call HAL3,參數設置流程
在這里插入圖片描述

  • 第一步:上層APP調用Camera2Client的setParameters方法將參數送到C++層CameraService;
  • 第二步:創建默認CaptureRequest,Camera2Client會將參數送給StreamingProcessor,再交給Parameters把參數更新到CaptureRequest;
  • 第三步:更新后的CaptureRequest ,如mPreviewRequestmRecordingRequest,保存在StreamingProcessor中;

2. API1 call HAL3,startPreview流程
在這里插入圖片描述

  • 第一步:調用StreamingProcessor和JPEG/Callback/ZSL Processor的updateStream,創建OutputStream,StreamingProcessor是創建預覽流,JPEG/Callback/ZSL Processor是創建拍照流;
  • 第二步:再次更新mPreviewRequestmRecordingRequest
  • 第三步:調用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連接);
    步驟:
  1. 第一步:獲取調用者的PID/UID/SystemCameraKind/以及是否是systemClient;
  2. 第二步:如果是c++層cameraserver自己調用自己,則不拒絕,這種情況一般出現在hal調用c++層cameraserver再調用自己,不會拒絕;
  3. 第三步:如果是systemClient,則不拒絕,uid小于10000都是systemClient;
  4. 第四步:如果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);
      在這里插入圖片描述
  • 直接調用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打印耗時。
  • 綠色方框里面部分:
    1. 搶到mServiceLockWrapper這把鎖,超時時間是3s,保證同一時刻只有一個客戶端在openCamera,如果這里超時看一下上次openCamera時候這把鎖是不是沒有釋放,也有可能close卡主,mServiceLockWrapper被持有的地方比較多都要查;
    2. 檢查權限和CameraId:validateConnectLocked(重點);
    3. 處理搶占邏輯:handleEvictionsLocked(重點);
    4. 準備創建cameraClient,準備參數:
      • deviceVersionAndTransport:是指hidl的deviceVersion、Transport;
      • portaitRotation:旋轉多少度是豎屏;
      • facing:打開camera是前置還是后置;
      • orientation:設備角度;
      • overrideForPerfClass:對參數做的修改;
    5. 把準備的參數傳入makeClient,這里會區分API1或者API2,API1創建camera2Client,API2創建cameraDeviceClient,這里看API2;client->initialize,會傳入monitorTags,monitorTags:可以監聽每一幀里面的metadata變化,debug時使用,比如dumpsys media.camera。(重點)
    6. 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使用。
    7. finishConnectLocked:把打開后的CameraClient添加到ActiveClientManager中,ActiveClientManager監聽CameraClient進程是否掛掉;
      • logConnected:dumpsys 可以看到;linkToDeath:監聽調用者進程是否掛掉,調用者掛掉CameraService就會disconnect;
    8. 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不存在沖突,就使用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?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賦值邏輯
調用者進程的包名
在這里插入圖片描述

  1. openCamera時,上層Java層APP會傳遞Client package name到CameraService;
  2. 如果是NativeClient,傳遞的package name為空字符串,cameraservice會主動獲取包名;
  3. 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;
      在這里插入圖片描述

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;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/96134.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/96134.shtml
英文地址,請注明出處:http://en.pswp.cn/web/96134.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

MacOS 15.6 編譯SDL3 Android平臺多架構so庫

成功編譯輸出: 編譯: Android平臺多架構編譯腳本: sdl3_android_build.sh #!/bin/bash# 設置變量 macos 其他系統需要更改路徑 SDL_SOURCE_DIR=$(pwd)/SDL BUILD_DIR=${SDL_SOURCE_DIR}/../sdl3_build_android NDK_PATH=$HOME/Library/Android/Sdk/Ndk/25.2.9519653 CMAKE…

Real-IAD D3: A Real-World 2D/Pseudo-3D/3D Dataset for Industrial Anomaly

Real-IAD D: A Real-World 2D/Pseudo-3D/3D Dataset for Industrial Anomaly Detection Paper Github 摘要 隨著工業異常檢測&#xff08;Industrial Anomaly Detection, IAD&#xff09;復雜程度的不斷提升&#xff0c;多模態檢測方法已成為機器視覺領域的研究焦點。然而&a…

IT需求提示未讀信息查詢:深度技術解析與性能優化指南【類似:釘釘已讀 功能】

IT需求提示未讀信息查詢&#xff1a;深度技術解析與性能優化指南【類似&#xff1a;釘釘已讀 功能】 DROP TABLE IF EXISTS rs_kpi_it_need_tip; CREATE TABLE IF NOT EXISTS rs_kpi_it_need_tip (id bigint NOT NULL AUTO_INCREMENT COMMENT 主鍵ID&#xff…

Django中的軟刪除

軟刪除&#xff08;Soft Delete&#xff09;是一種數據刪除策略&#xff0c;它并不真正從數據庫中刪除記錄&#xff0c;而是通過標記&#xff08;如 is_deleted 字段&#xff09;來表示記錄已被刪除。 這樣做的好處是可以保留數據歷史&#xff0c;支持數據恢復和審計。 在 Djan…

JavaEE 進階第四期:開啟前端入門之旅(四)

專欄&#xff1a;JavaEE 進階躍遷營 個人主頁&#xff1a;手握風云 目錄 一、常用CSS 1.1. border 1.2. width/height 1.3. padding&#xff1a;內邊距 1.4. margin&#xff1a;外邊距 二、初始JavaScript 2.1. JavaScript是什么 2.2. 發展歷史 2.3. JavaScript 和 HT…

學習日記-SpringMVC-day49-9.4

知識點&#xff1a;1.RequestMapping&#xff08;3&#xff09;知識點核心內容重點RequestMapping注解的parameters屬性通過parameters指定請求參數條件&#xff08;如bookID&#xff09;&#xff0c;控制請求匹配規則&#xff08;必須包含/排除特定參數或值&#xff09;參數存…

【Day 50 】Linux-nginx反向代理與負載均衡

概述在現代 Web 架構中&#xff0c;Nginx 作為高并發、高性能的 HTTP 和反向代理服務器&#xff0c;被廣泛應用于提升服務性能、增強系統安全性和實現負載均衡。其中&#xff0c;反向代理能夠隱藏后端服務器信息并優化請求處理流程&#xff0c;負載均衡則可將請求分發到多個后端…

vue中配置 ts

在 Vue 項目中配置 TypeScript&#xff08;TS&#xff09;可以提升代碼的類型安全性和開發體驗。以下是在 Vue 項目&#xff08;基于 Vite&#xff09;中配置 TypeScript 的詳細步驟和關鍵配置&#xff1a; 一、創建支持 TypeScript 的 Vue 項目 如果是新建項目&#xff0c;推…

阿里云鏡像地址獲取,并安裝 docker的mysql和nginx等服務,java,python,ffmpeg,go等環境

阿里云那個鏡像地址獲取 阿里云鏡像加速器不是一個通用的 registry.cn-hangzhou.aliyuncs.com&#xff0c;而是你賬號專屬的&#xff0c;比如這樣&#xff1a; https://abcd1234.mirror.aliyuncs.com&#x1f449; 登錄阿里云控制臺獲取&#xff1a; 阿里云鏡像加速器 然后替…

conda環境導出

1. 激活你想要打包的環境首先&#xff0c;確保你激活了你要打包的 conda 環境&#xff1a;conda activate qwen2. 導出環境配置使用 conda 命令將當前環境的配置導出為一個 .yml 文件&#xff0c;記錄下環境中所有的依賴和版本&#xff1a;conda list --export > techgpt_en…

openEuler2403安裝部署Kafka

文章目錄 openEuler2403安裝部署Kafka with KRaft一、前言1.簡介2.架構3.環境 二、正文1.部署服務器2.基礎環境1&#xff09;JDK 安裝部署2&#xff09;關閉防火墻 3.單機部署1&#xff09;下載軟件包2&#xff09;修改配置文件3&#xff09;格式化存儲目錄4&#xff09;單機啟…

發布工業智能體,云從科技打造制造業AI“運營大腦”

近日&#xff0c;在2025世界智能產業博覽會重慶市工業智能體首發儀式現場&#xff0c;云從科技重磅發布經營決策-產線運營智能體&#xff0c;為制造業的智能化轉型提供了全新的解決方案。該智能體的亮相&#xff0c;不僅代表著人工智能技術在工業領域的深度應用&#xff0c;更標…

【Linux基礎】parted命令詳解:從入門到精通的磁盤分區管理完全指南

目錄 前言 1 parted命令概述 1.1 什么是parted 1.2 parted與fdisk的對比 1.3 parted的主要優勢 2 parted命令的安裝與基本語法 2.1 在不同Linux發行版中安裝parted 2.2 parted的基本語法 2.3 parted的工作模式 3 parted交互式命令詳解 3.1 交互式操作流程 3.2 主要…

如何在路由器上配置DHCP服務器?

在路由器上配置DHCP服務器的步驟因品牌&#xff08;如TP-Link、華為、小米、華碩等&#xff09;略有差異&#xff0c;但核心流程一致&#xff0c;主要包括登錄管理界面、開啟DHCP功能、設置IP地址池及相關參數。以下是通用操作指南&#xff1a; 一、準備工作 確保電腦/手機已連…

HTML和CSS學習

HTML學習 注釋 <!-- -->組成 告訴瀏覽器我是html文件<!DOCTYPE html> <title>瀏覽器標簽</title> <body> <!--- 其中是主要內容 ---> <p> 段落 </p> </body> </html> (結束點…

OpenTenBase vs MySQL vs Oracle,企業級應用數據庫實盤對比分析

摘要 因為工作久了的緣故&#xff0c;接觸過不少數據庫。公司的管理系統用的MySQL&#xff0c;財務系統用的Oracle。隨著時代發展&#xff0c;國產開源數據庫已經在性能上能與這些國際知名頂尖數據庫品牌相媲美&#xff0c;其中OpenTenBase以其開放環境和優越性能脫穎而出&…

Oracle 備份與恢復常見的七大問題

為了最大限度保障數據的安全性&#xff0c;同時能在不可預計災難的情況下保證數據的快速恢復&#xff0c;需要根據數據的類型和重要程度制定相應的備份和恢復方案。在這個過程中&#xff0c;DBA的職責就是要保證數據庫&#xff08;其它數據由其它崗位負責&#xff09;的高可用和…

StringBuilder類的數據結構和擴容方式解讀

目錄 StringBuilder是什么 核心特性&#xff1a; StringBuilder數據結構 1. 核心存儲結構&#xff08;基于父類 AbstractStringBuilder&#xff09; 2. 類定義與繼承關系 3. 數據結構的核心特點 StringBuilder數據結構的初始化方式 1. 無參構造&#xff1a;默認初始容量…

LangChain實戰(十七):構建與PDF/PPT文檔對話的AI助手

本文是《LangChain實戰課》系列的第十七篇,將專篇深入講解如何構建能夠與PDF和PPT文檔進行智能對話的AI助手。通過學習本文,您將掌握復雜格式文檔的解析技巧、文本與表格處理技術,以及實現精準問答的系統方法。 前言 在日常工作和學習中,PDF和PPT文檔是我們最常接觸的文檔…

魚眼相機模型

魚眼相機模型 最近涉及魚眼相機模型、標定使用等&#xff0c;作為記錄&#xff0c;更新很久不曾更新的博客。 文章目錄魚眼相機模型1 相機成像2 魚眼模型3 畸變3.1 適用針孔和MEI3.2 Kannala-Brandt魚眼模型4 代碼實現1 相機成像 針孔相機&#xff1a;所有光線從一個孔&#xf…