相關文章
[Android O] Camera 服務啓動流程簡析
[Android O] HAL3 之 Open Camera2 流程(零)—— 概覽
[Android O] HAL3 之 Open Camera2 流程(一)—— 從 App 到 CameraService
[Android O] HAL3 之 Open Camera2 流程(二)—— 從 CameraService 到 HAL Service
[Android O] HAL3 之 Open Camera2 流程(三,完結)—— 從 HAL Service 到 Camera HAL
從 Application 鏈接到 CameraService,這涉及到 Android 架構中的三個層次:App 層,Framework 層,Runtime 層。
其中,App 層直接調用 Framework 層所封裝的方法,而 Framework 層須要經過 Binder 遠程調用 Runtime 中 CameraService 的函數。java
這一部分主要的函數調用邏輯以下圖所示。android
下面開始分析相關代碼。api
App
關於應用這方面,我只是略懂一二,具體的實現就無論它了。
在 App 中,須要調用打開相機的接口,以下。架構
其中:app
mCameraManager 是 CameraManager 類的實例。
currentCameraId 則是須要打開的相機設備號。
stateCallback 是 CameraDevice.StateCallback,是關於相機打開狀況的相關回調。
backgroundHandler 則是 StateCallback 須要調用的 Handler。
mCameraManager.openCamera(currentCameraId, stateCallback, backgroundHandler);
1
以上內容參考自掘金網的一篇文章。框架
Framework
CameraManager
文件路徑:/frameworks/base/core/java/android/hardware/camera2/CameraManager.javaide
最初的入口就是 CameraManager 的 openCamera 方法。
但經過代碼能夠看到,它僅僅是調用了 openCameraForUid 方法。函數
@RequiresPermission(android.Manifest.permission.CAMERA)
public void openCamera(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException {post
openCameraForUid(cameraId, callback, handler, USE_CALLING_UID);
}
分析下面的代碼:ui
第 11~17 行,首先實例化一個 CameraDeviceImpl。值得注意的是,構造時傳入了 CameraDevice.StateCallback 以及 Handler。
第 19 行,獲取 CameraDeviceCallback 實例,這是提供給遠端鏈接到 CameraDeviceImpl 的接口。
第 22~32 行,HAL3 中走的是這一部分邏輯,主要是從 CameraManagerGlobal 中獲取 CameraService 的本地接口,經過它遠端調用(採用 Binder 機制) connectDevice 方法鏈接到相機設備。注意返回的 cameraUser 實際上指向的是遠端 CameraDeviceClient 的本地接口。
爲了縮短篇幅,省略了捕獲異常的相關代碼。
第 56 行,將 CameraDeviceClient 設置到 CameraDeviceImpl 中進行管理。
private CameraDevice openCameraDeviceUserAsync(String cameraId,
CameraDevice.StateCallback callback, Handler handler, final int uid)
throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
synchronized (mLock) {
ICameraDeviceUser cameraUser = null;
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
new android.hardware.camera2.impl.CameraDeviceImpl(
cameraId,
callback,
handler,
characteristics,
mContext.getApplicationInfo().targetSdkVersion);
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
try {
if (supportsCamera2ApiLocked(cameraId)) {
// Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
if (cameraService == null) {
throw new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
}
cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), uid);
} else {
// Use legacy camera implementation for HAL1 devices
int id;
try {
id = Integer.parseInt(cameraId);
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+ cameraId);
}
Log.i(TAG, "Using legacy camera HAL.");
cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
}
} catch (ServiceSpecificException e) {
/* Do something in */
......
/* Do something out */
}
// TODO: factor out callback to be non-nested, then move setter to constructor
// For now, calling setRemoteDevice will fire initial
// onOpened/onUnconfigured callbacks.
// This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
// cameraUser dies during setup.
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
}
return device;
}
CameraDeviceImpl
文件路徑:/frameworks/base/core/java/android/hardware/camera2/Impl/CameraDeviceImpl.java
在繼續向下分析打開相機流程以前,先簡單看看調用到的 CameraDeviceImpl 中的方法。
setRemoteDevice 方法主要是將獲取到的遠端設備保存起來:
第 14 行,經過 ICameraDeviceUserWrapper 給遠端設備實例加上一層封裝。
第 16~28 行,是使用 Binder 機制的一些基本設置。
第 30、31 行,須要注意這個時間節點,此處觸發 onOpened 與 onUnconfigured 這兩個回調,每一個回調都是經過 mDeviceHandler 啓用一個新線程來調用的。
/**
* Set remote device, which triggers initial onOpened/onUnconfigured callbacks
*
* <p>This function may post onDisconnected and throw CAMERA_DISCONNECTED if remoteDevice dies
* during setup.</p>
*
*/
public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
synchronized(mInterfaceLock) {
// TODO: Move from decorator to direct binder-mediated exceptions
// If setRemoteFailure already called, do nothing
if (mInError) return;
mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
IBinder remoteDeviceBinder = remoteDevice.asBinder();
// For legacy camera device, remoteDevice is in the same process, and
// asBinder returns NULL.
if (remoteDeviceBinder != null) {
try {
remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
} catch (RemoteException e) {
CameraDeviceImpl.this.mDeviceHandler.post(mCallOnDisconnected);
throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
"The camera device has encountered a serious error");
}
}
mDeviceHandler.post(mCallOnOpened);
mDeviceHandler.post(mCallOnUnconfigured);
}
}
Runtime
經過 Binder 機制,咱們遠端調用了 connectDevice 方法(在 C++ 中稱爲函數,但說成方法可能更順口一些),這個方法實如今 CameraService 類中。
CameraService
文件路徑:/frameworks/av/services/camera/libcameraservice/CameraService.cpp
觀察 connectDevice 的實現:
第 13~17 行,此處調用的 connectHelper 方法才真正實現了鏈接邏輯(HAL1 時最終也調用到這個方法)。須要注意的是,設定的模板類型是 ICameraDeviceCallbacks 以及 CameraDeviceClient。
第 25 行,注意 client 指向的類型是 CameraDeviceClient,其實例則是最終的返回結果。
Status CameraService::connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const String16& cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {
ATRACE_CALL();
Status ret = Status::ok();
String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
clientUid, USE_CALLING_PID, API_2,
/*legacyMode*/ false, /*shimUpdateOnly*/ false,
/*out*/client);
if(!ret.isOk()) {
logRejected(id, getCallingPid(), String8(clientPackageName),
ret.toString8());
return ret;
}
*device = client;
return ret;
}
connectHelper 內容較多,忽略掉咱們還無需關注的地方分析:
第 14~19 行,調用 makeClient 生成 CameraDeviceClient 實例。
第 20~25 行,初始化 CLIENT 實例。注意此處的模板類型 CLIENT 便是 CameraDeviceClient,傳入的參數 mCameraProviderManager 則是與 HAL service 有關,這個相關內容以後再分析。
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int halVersion, const String16& clientPackageName, int clientUid, int clientPid,
apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
String8 clientName8(clientPackageName);
/* Do something in */
......
/* Do something out */
sp<BasicClient> tmp = nullptr;
if(!(ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid,
clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
/*out*/&tmp)).isOk()) {
return ret;
}
client = static_cast<CLIENT*>(tmp.get());
LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
__FUNCTION__);
err = client->initialize(mCameraProviderManager);
/* Do something in */
......
/* Do something out */
// Important: release the mutex here so the client can call back into the service from its
// destructor (can be at the end of the call)
device = client;
return ret;
}
makeClient 主要是根據 API 版本以及 HAL 版原本選擇生成具體的 Client 實例。對於 HAL3 且 CameraAPI2 的狀況,請看 24~29 行,實例化了 CameraDeviceClient 類做爲 Client(注意此處構造傳入了 ICameraDeviceCallbacks,這是鏈接到 CameraDeviceImpl 的遠端回調) 。
最終,這一 Client 就沿着前面分析下來的路徑返回到 CameraDeviceImpl 實例中,被保存到 mRemoteDevice。
至此,打開相機流程中,從 App 到 CameraService 的調用邏輯基本上就算走完了。
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client) {
if (halVersion < 0 || halVersion == deviceVersion) {
// Default path: HAL version is unspecified by caller, create CameraClient
// based on device version reported by the HAL.
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
/* Do something in */
......
/* Do something out */
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
case CAMERA_DEVICE_API_VERSION_3_2:
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_4:
if (effectiveApiLevel == API_1) { // Camera1 API route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName, cameraIdToInt(cameraId),
facing, clientPid, clientUid, servicePid, legacyMode);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
*client = new CameraDeviceClient(cameraService, tmp, packageName, cameraId,
facing, clientPid, clientUid, servicePid);
}
break;
default:
// Should not be reachable
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Camera device \"%s\" has unknown HAL version %d",
cameraId.string(), deviceVersion);
}
} else {
/* Do something in */
......
/* Do something out */
}
return Status::ok();
}
簡圖總結
根據上面的流程追蹤,咱們能夠描繪一個比較簡單直觀的連路框架圖,以下。
其中黑色虛線表示下行(控制)路線,紅色虛線代表上行(狀態、數據)路線。
須要注意的是:
CameraManagerGlobal 是真正的實現層,它與 C++ Framework 層的 CameraService 建立鏈接,從而建立相機的連路。 CameraDeviceImpl 至關於運行上下文,它取代了 Android N 以前的 JNI 層。