[Android O] HAL3 之 Open Camera2 流程(一)—— 从 App 到 CameraService

从 Application 连接到 CameraService,这涉及到 Android 架构中的三个层次:App 层,Framework 层,Runtime 层。
其中,App 层直接调用 Framework 层所封装的方法,而 Framework 层需要通过 Binder 远程调用 Runtime 中 CameraService 的函数。

这一部分主要的函数调用逻辑如下图所示。

 


下面开始分析相关代码。

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.java

最初的入口就是 CameraManager 的 openCamera 方法。
但通过代码可以看到,它仅仅是调用了 openCameraForUid 方法。

@RequiresPermission(android.Manifest.permission.CAMERA)
public void openCamera(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
throws CameraAccessException {

openCameraForUid(cameraId, callback, handler, USE_CALLING_UID);
}
1
2
3
4
5
6
7
下面的代码忽略掉了一些参数检查相关操作,最终主要调用了 openCameraDeviceUserAsync 方法。

public void openCameraForUid(@NonNull String cameraId,
@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler,
int clientUid)
throws CameraAccessException {
/* Do something in*/
......
/* Do something out*/
openCameraDeviceUserAsync(cameraId, callback, handler, clientUid);
}
1
2
3
4
5
6
7
8
9
分析下面的代码:

第 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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
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);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
简图总结
根据上面的流程追踪,我们可以描绘一个比较简单直观的连路框架图,如下。
其中黑色虚线表示下行(控制)路线,红色虚线表明上行(状态、数据)路线。

 

 

需要注意的是:

CameraManagerGlobal 是真正的实现层,它与 JAVA 层的 CameraService 创建连接,从而创建相机的连路。
CameraDeviceImpl 相当于运行上下文,它取代了 Android N 之前的 JNI 层。
---------------------
作者:StoneDemo
来源:CSDN
原文:https://blog.csdn.net/qq_16775897/article/details/81537710
版权声明:本文为博主原创文章,转载请附上博文链接!

posted @ 2019-05-12 20:31  zzzxzzz  阅读(1070)  评论(0)    收藏  举报