跳到主要内容Android Camera Framework 层调用流程深度解析 | 极客日志Javajava
Android Camera Framework 层调用流程深度解析
Android Camera Framework 层调用流程从应用层开始,经过 CameraUtil、CameraHolder 到达 Framework 的 Camera 类。随后通过 JNI 调用本地方法连接 CameraService 服务。服务端通过 Binder 通信处理 CONNECT 请求,创建 Client 实例并连接 HAL 层。详细分析了从 Java 接口到 C++ 服务再到硬件抽象层的完整链路,涵盖权限校验、IPC 通信及客户端初始化过程。
禅心0 浏览 Android Camera Framework 层调用流程深度解析
1. 概述
Android 相机系统架构复杂,涉及应用层、Framework 层、JNI 层、CameraService 服务以及 HAL 层。本文重点分析从应用层调用到 Framework 层打开相机的完整链路,涵盖 Java API 调用、Binder 通信及服务端处理逻辑。
2. 应用层调用
在 Android Kitkat 原生 Camera2 应用中(packages/apps/Camera2/),PhotoModule、VideoModule 等模块通过 CameraUtil.open() 方法来打开相机。
CameraHolder 的 open() 方法
AndroidCameraManagerImpl 的 cameraOpen() 方法
CameraHandler 的 handleMessage()(消息为 OPEN_CAMERA)
- 最终调用 Framework Camera 类(frameworks/base/core/java/android/hardware/Camera.java)的
open() 方法。
2.1 应用层代码示例
mCameraDevice = CameraUtil.openCamera(
mActivity,
mCameraId,
mHandler,
mActivity.getCameraOpenErrorCallback()
);
在 CameraUtil 类中,主要逻辑包括检查相机是否被禁用,并委托给 CameraHolder。
public class CameraUtil {
public static CameraManager.CameraProxy openCamera(
Activity activity, final int cameraId,
Handler handler, final CameraManager.CameraOpenErrorCallback cb) {
try {
throwIfCameraDisabled(activity);
return CameraHolder.instance().open(handler, cameraId, cb);
} catch (CameraDisabledException ex) {
handler.post(new Runnable() {
@Override
public void run() {
cb.onCameraDisabled(cameraId);
}
});
}
return null;
}
}
3. Framework 层处理
CameraHolder 负责管理相机实例的生命周期。当 mCameraDevice 为空时,会请求 AndroidCameraManagerFactory 获取管理器并执行打开操作。
public class CameraHolder {
public synchronized CameraProxy open(
Handler handler, int cameraId,
CameraManager.CameraOpenErrorCallback cb) {
if (mCameraDevice == null) {
Log.v(TAG, "open camera " + cameraId);
if (mMockCameraInfo == null) {
mCameraDevice = CameraManagerFactory
.getAndroidCameraManager().cameraOpen(handler, cameraId, cb);
}
}
mCameraOpened = true;
mHandler.removeMessages(RELEASE_CAMERA);
return mCameraDevice;
}
}
AndroidCameraManagerImpl 将打开请求封装为 Message 发送给 CameraHandler。
class AndroidCameraManagerImpl implements CameraManager {
public CameraManager.CameraProxy cameraOpen(
Handler handler, int cameraId, CameraOpenErrorCallback callback) {
mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0,
CameraOpenErrorCallbackForward.getNewInstance(
handler, callback)).sendToTarget();
}
}
CameraHandler 收到消息后,调用底层 android.hardware.Camera.open()。
private class CameraHandler extends Handler {
@Override
public void handleMessage(final Message msg) {
try {
switch (msg.what) {
case OPEN_CAMERA:
mCamera = android.hardware.Camera.open(msg.arg1);
break;
}
}
}
}
4. JNI 层与本地方法
Framework Camera 类 API 调用本地方法,这些方法注册到 JNI。在打开相机的过程中,Camera 类的 open() 方法调用本地方法 native_setup()。
4.1 Java 侧实现
public class Camera {
public static Camera open(int cameraId) {
return new Camera(cameraId);
}
Camera(int cameraId) {
String packageName = ActivityThread.currentPackageName();
native_setup(new WeakReference<Camera>(this), cameraId, packageName);
}
}
4.2 JNI 注册
在 C++ 侧,native_setup 方法被注册到 JNI。
static JNINativeMethod camMethods[] = {
{ "native_setup",
"(Ljava/lang/Object;ILjava/lang/String;)V",
(void*)android_hardware_Camera_native_setup }
};
4.3 Native 实现
android_hardware_Camera_native_setup 函数负责连接 CameraService 服务。
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jstring clientPackageName)
{
sp<Camera> camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID);
}
5. CameraService 服务连接(IPC 通信)
JNI 调用 Camera::connect() 请求 CameraService 服务。Camera 类继承模板类 CameraBase 和 BnCameraClient。
5.1 客户端发起连接
首先调用模板类的 connect() 函数,向 ServiceManager 获取 Camera 服务信息,生成 BpCameraService 代理,然后通过 Binder 通信发送 CONNECT 命令。
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid)
{
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
status_t status = NO_ERROR;
const sp<ICameraService>& cs = getCameraService();
if (cs != 0) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
c->mCamera);
}
if (status == OK && c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
ALOGW("An error occurred while connecting to camera: %d", cameraId);
c.clear();
}
return c;
}
5.2 BpCameraService 发送请求
BpCameraService 将参数写入 Parcel,通过 transact() 发送消息。
class BpCameraService: public BpInterface<ICameraService>{
virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
const String16 &clientPackageName, int clientUid,
sp<ICamera>& device)
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
data.writeStrongBinder(cameraClient->asBinder());
data.writeInt32(cameraId);
data.writeString16(clientPackageName);
data.writeInt32(clientUid);
remote()->transact(BnCameraService::CONNECT, data, &reply);
if (readExceptionCode(reply)) return -EPROTO;
status_t status = reply.readInt32();
if (reply.readInt32() != 0) {
device = interface_cast<ICamera>(reply.readStrongBinder());
}
return status;
}
}
5.3 BnCameraService 服务端处理
服务端收到 CONNECT 命令后,解包 Parcel 并执行请求。
- 使用 Camera 的 Binder 对象生成 Camera 客户代理
BpCameraClient 实例。
- 将生成的
BpCameraClient 对象作为参数传递到 CameraService 的 connect() 函数中。
- 返回
BpCamera 实例。
status_t BnCameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case CONNECT: {
CHECK_INTERFACE(ICameraService, data, reply);
sp<ICameraClient> cameraClient =
interface_cast<ICameraClient>(data.readStrongBinder());
int32_t cameraId = data.readInt32();
const String16 clientName = data.readString16();
int32_t clientUid = data.readInt32();
sp<ICamera> camera;
status_t status = connect(cameraClient, cameraId,
clientName, clientUid, camera);
reply->writeNoException();
reply->writeInt32(status);
if (camera != NULL) {
reply->writeInt32(1);
reply->writeStrongBinder(camera->asBinder());
} else {
reply->writeInt32(0);
}
return NO_ERROR;
} break;
}
}
6. CameraService 内部逻辑
CameraService::connect() 函数是核心逻辑所在,负责验证权限、创建 Client 实例并连接 HAL。
6.1 权限与状态校验
首先验证连接权限,检查相机 ID 是否合法,并更新相机状态(如从 PRESENT 变为 NOT_AVAILABLE)。
6.2 Client 实例创建
根据 HAL 不同 API 的版本创建不同的 Client 实例。Legacy Camera API 对应 CameraClient,Camera2 API 对应 Camera2Client。
status_t CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
sp<ICamera>& device) {
sp<Client> client;
{
Mutex::Autolock lock(mServiceLock);
sp<BasicClient> clientTmp;
if (!canConnectUnsafe(cameraId, clientPackageName,
cameraClient->asBinder(),
clientTmp)) {
return -EBUSY;
}
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid());
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
client = new Camera2Client(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid(),
deviceVersion);
break;
default:
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return INVALID_OPERATION;
}
status_t status = connectFinishUnsafe(client, client->getRemote());
if (status != OK) {
updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
return status;
}
mClient[cameraId] = client;
}
device = client;
return OK;
}
7. 补充说明
7.1 权限配置
在 AndroidManifest.xml 中必须声明相机权限:
<uses-permission android:name="android.permission.CAMERA" />
对于 Android 6.0+,还需要在运行时动态申请权限。
7.2 生命周期管理
- Open: 初始化 Camera 对象,连接 Service。
- Preview: 设置预览 Surface。
- Capture: 触发拍照或录像。
- Release: 释放资源,断开与服务器的连接,允许其他应用访问相机。
7.3 Camera2 与 Legacy 区别
- Legacy: 基于
android.hardware.Camera,API 较旧,功能受限。
- Camera2: 基于
CameraManager 和 CameraCharacteristics,提供更细粒度的控制,支持 RAW 格式输出及高级图像处理管线。
8. 总结
本文详细分析了 Android Camera Framework 层的调用流程。从应用层调用开始,经过 JNI 桥接,通过 Binder IPC 机制与 CameraService 通信,最终由 Service 创建 Client 并连接 HAL 层。理解这一流程有助于排查相机无法打开、权限错误及设备占用等问题。在实际开发中,建议优先使用 Camera2 API 以获得更好的兼容性和扩展性。
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online