打开相机的起点从 CameraManager 类 openCamera(…) 方法开始。
打开具有给定 ID 的相机连接。
使用 getCameraIdList 获取可用相机设备的列表。请注意,即使列出了 ID,但如果在对 getCameraIdList 和 openCamera 的调用之间断开了设备的连接,或者如果优先级更高的相机 API 客户端开始使用相机设备,则打开可能会失败。
从 API 级别 23 开始,由于优先级较低的后台相机 API 客户端正在使用该设备,因此已调用 AvailabilityCallback#onCameraUnavailable(String) 回调的设备仍可以通过调用此方法,来打开当调用相机 API 客户端的优先级高于使用此设备的当前相机 API 客户端时。通常,如果最顶层的前台活动正在您的应用程序进程中运行,则在访问相机时,将为您的进程赋予最高优先级,并且即使另一个相机 API 客户端正在使用相机设备,此方法也会成功。以此方式失去控制权的所有低优先级应用程序都将收到 android.hardware.camera2.CameraDevice.StateCallback#onDisconnected 回调。
成功打开相机后,将使用新打开的 CameraDevice 调用 CameraDevice.StateCallback#onOpened。然后可以通过调用 CameraDevice#createCaptureSession 和 CameraDevice#createCaptureRequest 设置相机设备进行操作。
由于相机设备将以异步方式打开,因此对返回的 CameraDevice 实例执行的所有异步操作都将排队,直到设备启动完成并调用回调的 CameraDevice.StateCallback#onOpened 方法为止。然后按顺序处理挂起的操作。
如果在此函数调用返回后初始化期间相机断开连接,则 CameraDevice.StateCallback#onDisconnected 的 CameraDevice 处于断开状态(并且 CameraDevice.StateCallback#onOpened 将被跳过)。
如果打开相机设备失败,则将调用设备回调的 CameraDevice.StateCallback#onError 方法,并且在相机设备上进行的后续调用将引发 CameraAccessException。
@param cameraId 要打开的相机设备的唯一标识符
@param callback 打开相机后调用的回调
@param handler 应该在其上调用回调的 Handler,或者是 null 以使用当前线程的 android.os.Looper
openCamera(…) 首先做了必要的参数检查,最后直接调用 openCameraDeviceUserAsync(…) 处理真正的打开相机流程。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......@RequiresPermission(android.Manifest.permission.CAMERA)public void openCamera(@NonNull String cameraId,@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)throws CameraAccessException {
if (cameraId == null) {
throw new IllegalArgumentException("cameraId was null");} else if (callback == null) {
throw new IllegalArgumentException("callback was null");} else if (handler == null) {
if (Looper.myLooper() != null) {
handler = new Handler();} else {
throw new IllegalArgumentException("Handler argument is null, but no looper exists in the calling thread");}}openCameraDeviceUserAsync(cameraId, callback, handler);}......
}
帮助打开与给定 ID 的相机连接。
- 创建 CameraDeviceImpl 对象,它继承自 CameraDevice
- 假设支持 Camera2Api,获取 CameraService
- 调用 CameraService connectDevice 方法连接相机设备
- 获取 CameraDeviceUser
- CameraDeviceImpl 对象上调用 setRemoteDevice(…) 方法
- 返回 CameraDeviceImpl 对象
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......private CameraDevice openCameraDeviceUserAsync(String cameraId,CameraDevice.StateCallback callback, Handler handler)throws CameraAccessException {
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);CameraDevice device = null;try {
synchronized (mLock) {
ICameraDeviceUser cameraUser = null;android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =new android.hardware.camera2.impl.CameraDeviceImpl(cameraId,callback,handler,characteristics);BinderHolder holder = new BinderHolder();ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();int id = Integer.parseInt(cameraId);try {
if (supportsCamera2ApiLocked(cameraId)) {
// 使用 cameraservice 的 cameradeviceclient 实现 HAL3.2+ 设备ICameraService cameraService = CameraManagerGlobal.get().getCameraService();if (cameraService == null) {
throw new CameraRuntimeException(CameraAccessException.CAMERA_DISCONNECTED,"Camera service is currently unavailable");}cameraService.connectDevice(callbacks, id,mContext.getOpPackageName(), USE_CALLING_UID, holder);cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());} else {
// 对 HAL1 设备使用旧版相机实现Log.i(TAG, "Using legacy camera HAL.");cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);}} catch (CameraRuntimeException e) {
......} catch (RemoteException e) {
......}// TODO: factor out callback to be non-nested, then move setter to constructor// 目前,调用 setRemoteDevice 将触发初始的 onOpened/onUnconfigured 回调。deviceImpl.setRemoteDevice(cameraUser);device = deviceImpl;}} catch (NumberFormatException e) {
......} catch (CameraRuntimeException e) {
......}return device;} ......
}
HAL2.1+ CameraDevice 实现。使用 CameraManager#open 实例化。
- 获取 TAG
- 获取 partialCount
REQUEST_PARTIAL_RESULT_COUNT 定义结果将由多少个子组件组成。
为了消除流水线延迟,可以在部分结果可用时立即将其从相机设备传递到应用程序层。
可选的; 默认值为 1。值 1 表示不支持部分结果,并且相机设备将仅生成最终的 TotalCaptureResult。一个典型的用例可能是:请求自动对焦(AF)锁定后,新的 AF 状态在整个管道中可能有 50% 可用。然后,相机设备可以通过部分结果立即将状态分发给应用程序,其余的元数据则通过以后的部分结果进行分发。
frameworks/base/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
public class CameraDeviceImpl extends CameraDevice {
......public CameraDeviceImpl(String cameraId, StateCallback callback, Handler handler,CameraCharacteristics characteristics) {
if (cameraId == null || callback == null || handler == null || characteristics == null) {
throw new IllegalArgumentException("Null argument given");}mCameraId = cameraId;mDeviceCallback = callback;mDeviceHandler = handler;mCharacteristics = characteristics;final int MAX_TAG_LEN = 23;String tag = String.format("CameraDevice-JV-%s", mCameraId);if (tag.length() > MAX_TAG_LEN) {
tag = tag.substring(0, MAX_TAG_LEN);}TAG = tag;Integer partialCount =mCharacteristics.get(CameraCharacteristics.REQUEST_PARTIAL_RESULT_COUNT);if (partialCount == null) {
// 1 means partial result is not supported.mTotalPartialCount = 1;} else {
mTotalPartialCount = partialCount;}} ......
}
现在了解一下 CameraDevice 类。
CameraDevice 类代表连接到 Android 设备的单个相机的表示形式,允许以高帧率对图像捕获和后处理进行细粒度控制。
应用必须在其清单中声明 android.Manifest.permission#CAMERA Camera 权限,才能访问相机设备。
给定的相机设备可以提供以下两个级别之一的支持:受限或完全支持。 如果设备仅支持有限级别,则 Camera2 会公开一个功能集,该功能集与旧版 android.hardware.Camera Camera API 大致相同,尽管接口更加简洁高效。与旧版相机 API 相比,实现全面支持的设备提供了显着改进的功能。 针对有限级别设备的应用程序将在完整级别设备上保持不变;如果应用程序需要完整级别的设备才能正常运行,请在清单中声明 “ android.hardware.camera.level.full” 功能。
frameworks/base/core/java/android/hardware/camera2/CameraDevice.java
public abstract class CameraDevice implements AutoCloseable {
......
}
获取 CameraService 相机服务具体可以参见《Android 源码 Camera2 获取 CameraId 列表》一节。继续分析调用 CameraService connectDevice 方法。这会调到 BpCameraService 同名方法。
frameworks/av/camera/ICameraService.cpp
class BpCameraService: public BpInterface<ICameraService>
{
public:virtual status_t connectDevice(const sp<ICameraDeviceCallbacks>& cameraCb,int cameraId,const String16& clientPackageName,int clientUid,/*out*/sp<ICameraDeviceUser>& device){
Parcel data, reply;data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());data.writeStrongBinder(IInterface::asBinder(cameraCb));data.writeInt32(cameraId);data.writeString16(clientPackageName);data.writeInt32(clientUid);status_t status;status = remote()->transact(BnCameraService::CONNECT_DEVICE, data, &reply);if (status != OK) return status;if (readExceptionCode(reply)) return -EPROTO;status = reply.readInt32();if (reply.readInt32() != 0) {
device = interface_cast<ICameraDeviceUser>(reply.readStrongBinder());}return status;}
}
接着在 BnCameraService onTransact(…) 方法中接收 Client 发来的消息,调用它的 connectDevice(…) 具体实现。
frameworks/av/camera/ICameraService.cpp
status_t BnCameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
......case CONNECT_DEVICE: {
CHECK_INTERFACE(ICameraService, data, reply);sp<ICameraDeviceCallbacks> cameraClient =interface_cast<ICameraDeviceCallbacks>(data.readStrongBinder());int32_t cameraId = data.readInt32();const String16 clientName = data.readString16();int32_t clientUid = data.readInt32();sp<ICameraDeviceUser> camera;status_t status = connectDevice(cameraClient, cameraId,clientName, clientUid, /*out*/camera);reply->writeNoException();reply->writeInt32(status);if (camera != NULL) {
reply->writeInt32(1);reply->writeStrongBinder(IInterface::asBinder(camera));} else {
reply->writeInt32(0);}return NO_ERROR;} break;......}......
}
CameraService::connectDevice(…) 主要调用了 connectHelper(…) 方法。
frameworks/av/services/camera/libcameraservice/CameraService.cpp
status_t CameraService::connectDevice(const sp<ICameraDeviceCallbacks>& cameraCb,int cameraId,const String16& clientPackageName,int clientUid,/*out*/sp<ICameraDeviceUser>& device) {
ATRACE_CALL();status_t ret = NO_ERROR;String8 id = String8::format("%d", cameraId);sp<CameraDeviceClient> client = nullptr;ret = connectHelper<ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, API_2, false, false,/*out*/client);if(ret != NO_ERROR) {
logRejected(id, getCallingPid(), String8(clientPackageName),String8::format("%s (%d)", strerror(-ret), ret));return ret;}device = client;return NO_ERROR;
}
下面重点关注获取 BasicClient 和 从 HAL 模块初始化客户端。
frameworks/av/services/camera/libcameraservice/CameraService.h
template<class CALLBACK, class CLIENT>
status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,int halVersion, const String16& clientPackageName, int clientUid,apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,/*out*/sp<CLIENT>& device) {
status_t ret = NO_ERROR;String8 clientName8(clientPackageName);int clientPid = getCallingPid();ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) for HAL version %s and ""Camera API version %d", clientPid, clientName8.string(), cameraId.string(),(halVersion == -1) ? "default" : std::to_string(halVersion).c_str(),static_cast<int>(effectiveApiLevel));sp<CLIENT> client = nullptr;{
// 获取 AutoConditionLock 并阻止其他客户端连接std::unique_ptr<AutoConditionLock> lock =AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);if (lock == nullptr) {
ALOGE("CameraService::connect X (PID %d) rejected (too many other clients connecting).", clientPid);return -EBUSY;}// 强制执行客户端权限并进行基本的健全性检查if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) {
return ret;}// 在获取锁后检查 shim 参数,如果它们已经被更新并且我们正在进行 shim 更新,立即返回if (shimUpdateOnly) {
auto cameraState = getCameraState(cameraId);if (cameraState != nullptr) {
if (!cameraState->getShimParams().isEmpty()) return NO_ERROR;}}sp<BasicClient> clientTmp = nullptr;std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;if ((ret = handleEvictionsLocked(cameraId, clientPid, effectiveApiLevel,IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,/*out*/&partial)) != NO_ERROR) {
return ret;}if (clientTmp.get() != nullptr) {
// 处理 API1 MediaRecorder 的特殊情况,其中返回了现有客户端device = static_cast<CLIENT*>(clientTmp.get());return NO_ERROR;}// 如果有必要,让手电筒有机会关闭设备。mFlashlight->prepareDeviceOpen(cameraId);// TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDsint id = cameraIdToInt(cameraId);if (id == -1) {
ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__,cameraId.string());return BAD_VALUE;}int facing = -1;int deviceVersion = getDeviceVersion(id, /*out*/&facing);sp<BasicClient> tmp = nullptr;// 获取 BasicClientif((ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid,clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,/*out*/&tmp)) != NO_ERROR) {
return ret;}client = static_cast<CLIENT*>(tmp.get());LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",__FUNCTION__);// 从 HAL 模块初始化客户端if ((ret = client->initialize(mModule)) != OK) {
ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);return ret;}// 更新旧版客户端的 shim 参数if (effectiveApiLevel == API_1) {
// 假设我们一直收到 API1 的 Client 子类sp<Client> shimClient = reinterpret_cast<Client*>(client.get());String8 rawParams = shimClient->getParameters();CameraParameters params(rawParams);auto cameraState = getCameraState(cameraId);if (cameraState != nullptr) {
cameraState->setShimParams(params);} else {
ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.",__FUNCTION__, cameraId.string());}}if (shimUpdateOnly) {
// 如果仅更新旧的 shim 参数,请立即断开客户端连接mServiceLock.unlock();client->disconnect();mServiceLock.lock();} else {
// 否则,将客户端添加到活动客户端列表finishConnectLocked(client, partial);}} // 锁被销毁,允许进一步连接调用// 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 NO_ERROR;
}
假设走分支 Camera2 API 路由,这会创建 CameraDeviceClient 对象。
frameworks/av/services/camera/libcameraservice/CameraService.cpp
status_t 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) {
// TODO: Update CameraClients + HAL interface to use strings for Camera IDsint id = cameraIdToInt(cameraId);if (id == -1) {
ALOGE("%s: Invalid camera ID %s, cannot convert to integer.", __FUNCTION__,cameraId.string());return BAD_VALUE;}if (halVersion < 0 || halVersion == deviceVersion) {
// 默认路径:调用者未指定 HAL 版本,根据 HAL 报告的设备版本创建 CameraClient。switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:if (effectiveApiLevel == API_1) {
// Camera1 API routesp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());*client = new CameraClient(cameraService, tmp, packageName, id, facing,clientPid, clientUid, getpid(), legacyMode);} else {
// Camera2 API routeALOGW("Camera using old HAL version: %d", deviceVersion);return -EOPNOTSUPP;}break;case CAMERA_DEVICE_API_VERSION_2_0:case CAMERA_DEVICE_API_VERSION_2_1: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:if (effectiveApiLevel == API_1) {
// Camera1 API 路由sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());*client = new Camera2Client(cameraService, tmp, packageName, id, facing,clientPid, clientUid, servicePid, legacyMode);} else {
// Camera2 API 路由sp<ICameraDeviceCallbacks> tmp =static_cast<ICameraDeviceCallbacks*>(cameraCb.get());*client = new CameraDeviceClient(cameraService, tmp, packageName, id,facing, clientPid, clientUid, servicePid);}break;default:// Should not be reachableALOGE("Unknown camera device HAL version: %d", deviceVersion);return INVALID_OPERATION;}} else {
// 调用者要求特定的 HAL 版本。根据请求的 HAL 版本创建 CameraClient。if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
// 只支持高 HAL 版本设备打开为 HAL1.0 设备。sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());*client = new CameraClient(cameraService, tmp, packageName, id, facing,clientPid, clientUid, servicePid, legacyMode);} else {
// 目前尚不支持其他组合(例如,以HAL2.x 打开的 HAL3.x)。ALOGE("Invalid camera HAL version %x: HAL %x device can only be"" opened as HAL %x device", halVersion, deviceVersion,CAMERA_DEVICE_API_VERSION_1_0);return INVALID_OPERATION;}}return NO_ERROR;
}
CameraDeviceClient 构造函数中创建了 Camera2ClientBase 对象。
frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
CameraDeviceClient::CameraDeviceClient(const sp<CameraService>& cameraService,const sp<ICameraDeviceCallbacks>& remoteCallback,const String16& clientPackageName,int cameraId,int cameraFacing,int clientPid,uid_t clientUid,int servicePid) :Camera2ClientBase(cameraService, remoteCallback, clientPackageName,cameraId, cameraFacing, clientPid, clientUid, servicePid),mInputStream(),mRequestIdCounter(0) {
ATRACE_CALL();ALOGI("CameraDeviceClient %d: Opened", cameraId);
}
Camera2ClientBase 构造器是一个模板函数,TClientBase 会被 CameraDeviceClientBase 替换,会先构造一个 CameraDeviceClientBase 对象。
frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp
template <typename TClientBase>
Camera2ClientBase<TClientBase>::Camera2ClientBase(const sp<CameraService>& cameraService,const sp<TCamCallbacks>& remoteCallback,const String16& clientPackageName,int cameraId,int cameraFacing,int clientPid,uid_t clientUid,int servicePid):TClientBase(cameraService, remoteCallback, clientPackageName,cameraId, cameraFacing, clientPid, clientUid, servicePid),mSharedCameraCallbacks(remoteCallback),mDeviceVersion(cameraService->getDeviceVersion(cameraId)),mDeviceActive(false)
{
ALOGI("Camera %d: Opened. Client: %s (PID %d, UID %d)", cameraId,String8(clientPackageName).string(), clientPid, clientUid);mInitialClientPid = clientPid;mDevice = CameraDeviceFactory::createDevice(cameraId);LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");
}
CameraDeviceClientBase 构造器中又构造了一个 BasicClient 对象。
frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
CameraDeviceClientBase::CameraDeviceClientBase(const sp<CameraService>& cameraService,const sp<ICameraDeviceCallbacks>& remoteCallback,const String16& clientPackageName,int cameraId,int cameraFacing,int clientPid,uid_t clientUid,int servicePid) :BasicClient(cameraService,IInterface::asBinder(remoteCallback),clientPackageName,cameraId,cameraFacing,clientPid,clientUid,servicePid),mRemoteCallback(remoteCallback) {
}
BasicClient 定义在 CameraService.cpp 中。
frameworks/av/services/camera/libcameraservice/CameraService.cpp
CameraService::BasicClient::BasicClient(const sp<CameraService>& cameraService,const sp<IBinder>& remoteCallback,const String16& clientPackageName,int cameraId, int cameraFacing,int clientPid, uid_t clientUid,int servicePid):mClientPackageName(clientPackageName), mDisconnected(false)
{
mCameraService = cameraService;mRemoteBinder = remoteCallback;mCameraId = cameraId;mCameraFacing = cameraFacing;mClientPid = clientPid;mClientUid = clientUid;mServicePid = servicePid;mOpsActive = false;mDestructionStarted = false;
}
回到 Camera2ClientBase 构造器,CameraDeviceFactory::createDevice(…) 会创建 CameraDevice。
- 由 CameraService 弱引用提升为强引用
- 根据 HAL 版本去创建不同的 Camera2Device 或 Camera3Device 对象
frameworks/av/services/camera/libcameraservice/CameraDeviceFactory.cpp
sp<CameraDeviceBase> CameraDeviceFactory::createDevice(int cameraId) {
sp<CameraService> svc = sService.promote();if (svc == 0) {
ALOGE("%s: No service registered", __FUNCTION__);return NULL;}int deviceVersion = svc->getDeviceVersion(cameraId, /*facing*/NULL);sp<CameraDeviceBase> device;switch (deviceVersion) {
case CAMERA_DEVICE_API_VERSION_2_0:case CAMERA_DEVICE_API_VERSION_2_1:device = new Camera2Device(cameraId);break;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:device = new Camera3Device(cameraId);break;default:ALOGE("%s: Camera %d: Unknown HAL device version %d",__FUNCTION__, cameraId, deviceVersion);device = NULL;break;}ALOGV_IF(device != 0, "Created a new camera device for version %d",deviceVersion);return device;
}
假设工厂方法创建了 Camera3Device。
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
Camera3Device::Camera3Device(int id):mId(id),mIsConstrainedHighSpeedConfiguration(false),mHal3Device(NULL),mStatus(STATUS_UNINITIALIZED),mStatusWaiters(0),mUsePartialResult(false),mNumPartialResults(1),mNextResultFrameNumber(0),mNextReprocessResultFrameNumber(0),mNextShutterFrameNumber(0),mNextReprocessShutterFrameNumber(0),mListener(NULL)
{
ATRACE_CALL();camera3_callback_ops::notify = &sNotify;camera3_callback_ops::process_capture_result = &sProcessCaptureResult;ALOGV("%s: Created device for camera %d", __FUNCTION__, id);
}
现在来回看从 HAL 模块初始化客户端。这会首先调用 CameraDeviceClient::initialize(…) 方法。
- 调用 Camera2ClientBase::initialize(…) 方法进一步初始化
- 创建 FrameProcessorBase 对象,并 run 起来,然后注册一些 RangeListener。FrameProcessorBase 类代表输出帧元数据处理线程。这个线程等待来自设备的新帧,并在必要时分析它们。
RangeListener 为一系列 ID [minId,maxId)注册一个监听器。多个监听者可以监听同一范围。使用相同范围的 ID 注册相同的监听器无效。sendPartials 控制是否发送部分结果。
frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
status_t CameraDeviceClient::initialize(CameraModule *module)
{
ATRACE_CALL();status_t res;res = Camera2ClientBase::initialize(module);if (res != OK) {
return res;}String8 threadName;mFrameProcessor = new FrameProcessorBase(mDevice);threadName = String8::format("CDU-%d-FrameProc", mCameraId);mFrameProcessor->run(threadName.string());mFrameProcessor->registerListener(FRAME_PROCESSOR_LISTENER_MIN_ID,FRAME_PROCESSOR_LISTENER_MAX_ID,/*listener*/this,/*sendPartials*/true);return OK;
}
Camera2ClientBase 类 initialize(…) 方法最终调用了 Camera3Device initialize(…) 方法。
frameworks/av/services/camera/libcameraservice/common/Camera2ClientBase.cpp
template <typename TClientBase>
status_t Camera2ClientBase<TClientBase>::initialize(CameraModule *module) {
ATRACE_CALL();ALOGV("%s: Initializing client for camera %d", __FUNCTION__,TClientBase::mCameraId);status_t res;// 验证操作权限res = TClientBase::startCameraOps();if (res != OK) {
return res;}if (mDevice == NULL) {
ALOGE("%s: Camera %d: No device connected",__FUNCTION__, TClientBase::mCameraId);return NO_INIT;}res = mDevice->initialize(module);if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",__FUNCTION__, TClientBase::mCameraId, strerror(-res), res);return res;}res = mDevice->setNotifyCallback(this);return OK;
}
初始化的时候和 camera HAL 关联了起来。
frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
status_t Camera3Device::initialize(CameraModule *module)
{
ATRACE_CALL();Mutex::Autolock il(mInterfaceLock);Mutex::Autolock l(mLock);ALOGV("%s: Initializing device for camera %d", __FUNCTION__, mId);if (mStatus != STATUS_UNINITIALIZED) {
CLOGE("Already initialized!");return INVALID_OPERATION;}/** 打开 HAL device */status_t res;String8 deviceName = String8::format("%d", mId);camera3_device_t *device;ATRACE_BEGIN("camera3->open");res = module->open(deviceName.string(),reinterpret_cast<hw_device_t**>(&device));ATRACE_END();if (res != OK) {
SET_ERR_L("Could not open camera: %s (%d)", strerror(-res), res);return res;}/** 交叉检查设备版本 */if (device->common.version < CAMERA_DEVICE_API_VERSION_3_0) {
SET_ERR_L("Could not open camera: ""Camera device should be at least %x, reports %x instead",CAMERA_DEVICE_API_VERSION_3_0,device->common.version);device->common.close(&device->common);return BAD_VALUE;}camera_info info;res = CameraService::filterGetInfoErrorCode(module->getCameraInfo(mId, &info));if (res != OK) return res;if (info.device_version != device->common.version) {
SET_ERR_L("HAL reporting mismatched camera_info version (%x)"" and device version (%x).",info.device_version, device->common.version);device->common.close(&device->common);return BAD_VALUE;}/** 使用回调函数初始化设备 */ATRACE_BEGIN("camera3->initialize");res = device->ops->initialize(device, this);ATRACE_END();if (res != OK) {
SET_ERR_L("Unable to initialize HAL device: %s (%d)",strerror(-res), res);device->common.close(&device->common);return BAD_VALUE;}/** 启动状态跟踪器线程 */mStatusTracker = new StatusTracker(this);res = mStatusTracker->run(String8::format("C3Dev-%d-Status", mId).string());if (res != OK) {
SET_ERR_L("Unable to start status tracking thread: %s (%d)",strerror(-res), res);device->common.close(&device->common);mStatusTracker.clear();return res;}bool aeLockAvailable = false;camera_metadata_ro_entry aeLockAvailableEntry;res = find_camera_metadata_ro_entry(info.static_camera_characteristics,ANDROID_CONTROL_AE_LOCK_AVAILABLE, &aeLockAvailableEntry);if (res == OK && aeLockAvailableEntry.count > 0) {
aeLockAvailable = (aeLockAvailableEntry.data.u8[0] ==ANDROID_CONTROL_AE_LOCK_AVAILABLE_TRUE);}/** 启动请求队列线程 */mRequestThread = new RequestThread(this, mStatusTracker, device, aeLockAvailable);res = mRequestThread->run(String8::format("C3Dev-%d-ReqQueue", mId).string());if (res != OK) {
SET_ERR_L("Unable to start request queue thread: %s (%d)",strerror(-res), res);device->common.close(&device->common);mRequestThread.clear();return res;}mPreparerThread = new PreparerThread();/** Everything is good to go */mDeviceVersion = device->common.version;mDeviceInfo = info.static_camera_characteristics;mHal3Device = device;internalUpdateStatusLocked(STATUS_UNCONFIGURED);mNextStreamId = 0;mDummyStreamId = NO_STREAM;mNeedConfig = true;mPauseStateNotify = false;// HAL是否会发送早期的部分结果元数据?if (mDeviceVersion >= CAMERA_DEVICE_API_VERSION_3_2) {
camera_metadata_entry partialResultsCount =mDeviceInfo.find(ANDROID_REQUEST_PARTIAL_RESULT_COUNT);if (partialResultsCount.count > 0) {
mNumPartialResults = partialResultsCount.data.i32[0];mUsePartialResult = (mNumPartialResults > 1);}} else {
camera_metadata_entry partialResultsQuirk =mDeviceInfo.find(ANDROID_QUIRKS_USE_PARTIAL_RESULT);if (partialResultsQuirk.count > 0 && partialResultsQuirk.data.u8[0] == 1) {
mUsePartialResult = true;}}camera_metadata_entry configs =mDeviceInfo.find(ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS);for (uint32_t i = 0; i < configs.count; i += 4) {
if (configs.data.i32[i] == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED &&configs.data.i32[i + 3] ==ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_INPUT) {
mSupportedOpaqueInputSizes.add(Size(configs.data.i32[i + 1],configs.data.i32[i + 2]));}}return OK;
}
CameraModule::open(…) 方法内部调用了 camera_module 结构体 common 成员,这是一个 hw_module_t 结构体,其内部定义了 hw_module_methods_t 结构体,hw_module_methods_t 结构体内部又定义了 open 函数指针。这部分需要遵守 HAL 层定义。
frameworks/av/services/camera/libcameraservice/common/CameraModule.cpp
int CameraModule::open(const char* id, struct hw_device_t** device) {
int res;ATRACE_BEGIN("camera_module->open");res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));ATRACE_END();return res;
}
我们以 moto Nexus 6 HAL device/moto/shamu/camera/QCamera2/ 为例进行分析。QCamera2Hal.cpp 中给 hw_module_t 结构体 camera_common 进行了赋值,methods 中定义了 open(…) 方法。
device/moto/shamu/camera/QCamera2/QCamera2Hal.cpp
#include "QCamera2Factory.h"
#include "HAL3/QCamera3VendorTags.h"static hw_module_t camera_common = {
tag: HARDWARE_MODULE_TAG,module_api_version: CAMERA_MODULE_API_VERSION_2_4,hal_api_version: HARDWARE_HAL_API_VERSION,id: CAMERA_HARDWARE_MODULE_ID,name: "QCamera Module",author: "Qualcomm Innovation Center Inc",methods: &qcamera::QCamera2Factory::mModuleMethods,dso: NULL,reserved: {
0},
};
open 函数指针实际指向 QCamera2Factory::camera_device_open(…) 函数。
device/moto/shamu/camera/QCamera2/QCamera2Factory.cpp
struct hw_module_methods_t QCamera2Factory::mModuleMethods = {
open: QCamera2Factory::camera_device_open,
};
QCamera2Factory::camera_device_open(…) 方法内部做了入参检查,然后调用 QCamera2Factory::cameraDeviceOpen(…) 方法。gQCamera2Factory 是在 QCamera2Factory::get_number_of_cameras() 方法中构造的。
device/moto/shamu/camera/QCamera2/QCamera2Factory.cpp
int QCamera2Factory::camera_device_open(const struct hw_module_t *module, const char *id,struct hw_device_t **hw_device)
{
if (module != &HAL_MODULE_INFO_SYM.common) {
ALOGE("Invalid module. Trying to open %p, expect %p",module, &HAL_MODULE_INFO_SYM.common);return INVALID_OPERATION;}if (!id) {
ALOGE("Invalid camera id");return BAD_VALUE;}return gQCamera2Factory->cameraDeviceOpen(atoi(id), hw_device);
}
假设我们走 HAL3 分支,这里会创建 QCamera3HardwareInterface 对象,接着调用其 openCamera(…) 方法。
device/moto/shamu/camera/QCamera2/QCamera2Factory.cpp
int QCamera2Factory::cameraDeviceOpen(int camera_id,struct hw_device_t **hw_device)
{
int rc = NO_ERROR;if (camera_id < 0 || camera_id >= mNumOfCameras)return -ENODEV;if ( NULL == mHalDescriptors ) {
ALOGE("%s : Hal descriptor table is not initialized!", __func__);return NO_INIT;}if ( mHalDescriptors[camera_id].device_version == CAMERA_DEVICE_API_VERSION_3_0 ) {
QCamera3HardwareInterface *hw = new QCamera3HardwareInterface(mHalDescriptors[camera_id].cameraId,mCallbacks);if (!hw) {
ALOGE("Allocation of hardware interface failed");return NO_MEMORY;}rc = hw->openCamera(hw_device);if (rc != 0) {
delete hw;}} else if (mHalDescriptors[camera_id].device_version == CAMERA_DEVICE_API_VERSION_1_0) {
......} else {
ALOGE("%s: Device version for camera id %d invalid %d",__func__,camera_id,mHalDescriptors[camera_id].device_version);return BAD_VALUE;}return rc;
}
QCamera3HardwareInterface 构造函数如下:
device/moto/shamu/camera/QCamera2/HAL3/QCamera3HWI.cpp
QCamera3HardwareInterface::QCamera3HardwareInterface(int cameraId,const camera_module_callbacks_t *callbacks): mCameraId(cameraId),mCameraHandle(NULL),mCameraOpened(false),mCameraInitialized(false),mCallbackOps(NULL),mMetadataChannel(NULL),mPictureChannel(NULL),mRawChannel(NULL),mSupportChannel(NULL),mRawDumpChannel(NULL),mFirstRequest(false),mFlush(false),mParamHeap(NULL),mParameters(NULL),m_bIsVideo(false),m_bIs4KVideo(false),mEisEnable(0),mLoopBackResult(NULL),mMinProcessedFrameDuration(0),mMinJpegFrameDuration(0),mMinRawFrameDuration(0),m_pPowerModule(NULL),mMetaFrameCount(0),mCallbacks(callbacks),mCaptureIntent(0)
{
getLogLevel();mCameraDevice.common.tag = HARDWARE_DEVICE_TAG;mCameraDevice.common.version = CAMERA_DEVICE_API_VERSION_3_3;mCameraDevice.common.close = close_camera_device;mCameraDevice.ops = &mCameraOps;mCameraDevice.priv = this;gCamCapability[cameraId]->version = CAM_HAL_V3;// TODO: hardcode for now until mctl add support for min_num_pp_bufs//TBD - To see if this hardcoding is needed. Check by printing if this is filled by mctl to 3gCamCapability[cameraId]->min_num_pp_bufs = 3;pthread_cond_init(&mRequestCond, NULL);mPendingRequest = 0;mCurrentRequestId = -1;pthread_mutex_init(&mMutex, NULL);for (size_t i = 0; i < CAMERA3_TEMPLATE_COUNT; i++)mDefaultMetadata[i] = NULL;#ifdef HAS_MULTIMEDIA_HINTSif (hw_get_module(POWER_HARDWARE_MODULE_ID, (const hw_module_t **)&m_pPowerModule)) {
ALOGE("%s: %s module not found", __func__, POWER_HARDWARE_MODULE_ID);}
#endifchar prop[PROPERTY_VALUE_MAX];property_get("persist.camera.raw.dump", prop, "0");mEnableRawDump = atoi(prop);if (mEnableRawDump)CDBG("%s: Raw dump from Camera HAL enabled", __func__);
}
QCamera3HardwareInterface::openCamera(…) 在内部调用了无入参的重载方法,实际工作是由 camera_open(…) 函数完成的。mm_camera_vtbl_t 是包含相机句柄和操作表的虚拟表。
device/moto/shamu/camera/QCamera2/HAL3/QCamera3HWI.cpp
int QCamera3HardwareInterface::openCamera(struct hw_device_t **hw_device)
{
int rc = 0;if (mCameraOpened) {
*hw_device = NULL;return PERMISSION_DENIED;}rc = openCamera();if (rc == 0) {
*hw_device = &mCameraDevice.common;} else*hw_device = NULL;#ifdef HAS_MULTIMEDIA_HINTSif (rc == 0) {
if (m_pPowerModule) {
if (m_pPowerModule->powerHint) {
m_pPowerModule->powerHint(m_pPowerModule, POWER_HINT_VIDEO_ENCODE,(void *)"state=1");}}}
#endifreturn rc;
}int QCamera3HardwareInterface::openCamera()
{
int rc = 0;ATRACE_CALL();if (mCameraHandle) {
ALOGE("Failure: Camera already opened");return ALREADY_EXISTS;}rc = QCameraFlash::getInstance().reserveFlashForCamera(mCameraId);if (rc < 0) {
ALOGE("%s: Failed to reserve flash for camera id: %d",__func__,mCameraId);return UNKNOWN_ERROR;}mCameraHandle = camera_open(mCameraId);if (!mCameraHandle) {
ALOGE("camera_open failed.");return UNKNOWN_ERROR;}mCameraOpened = true;rc = mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle,camEvtHandle, (void *)this);if (rc < 0) {
ALOGE("%s: Error, failed to register event callback", __func__);/* Not closing camera here since it is already handled in destructor */return FAILED_TRANSACTION;}return NO_ERROR;
}
camera device 打开是由 mm_camera_open(…) 函数完成的。
device/moto/shamu/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
mm_camera_vtbl_t * camera_open(uint8_t camera_idx)
{
int32_t rc = 0;mm_camera_obj_t* cam_obj = NULL;CDBG("%s: E camera_idx = %d\n", __func__, camera_idx);if (camera_idx >= g_cam_ctrl.num_cam) {
CDBG_ERROR("%s: Invalid camera_idx (%d)", __func__, camera_idx);return NULL;}pthread_mutex_lock(&g_intf_lock);/* opened already */if(NULL != g_cam_ctrl.cam_obj[camera_idx]) {
/* Add reference */g_cam_ctrl.cam_obj[camera_idx]->ref_count++;pthread_mutex_unlock(&g_intf_lock);CDBG("%s: opened alreadyn", __func__);return &g_cam_ctrl.cam_obj[camera_idx]->vtbl;}cam_obj = (mm_camera_obj_t *)malloc(sizeof(mm_camera_obj_t));if(NULL == cam_obj) {
pthread_mutex_unlock(&g_intf_lock);CDBG("%s: no mem", __func__);return NULL;}/* initialize camera obj */memset(cam_obj, 0, sizeof(mm_camera_obj_t));cam_obj->ctrl_fd = -1;cam_obj->ds_fd = -1;cam_obj->ref_count++;cam_obj->my_hdl = mm_camera_util_generate_handler(camera_idx);cam_obj->vtbl.camera_handle = cam_obj->my_hdl; /* set handler */cam_obj->vtbl.ops = &mm_camera_ops;pthread_mutex_init(&cam_obj->cam_lock, NULL);rc = mm_camera_open(cam_obj);if(rc != 0) {
CDBG_ERROR("%s: mm_camera_open err = %d", __func__, rc);pthread_mutex_destroy(&cam_obj->cam_lock);g_cam_ctrl.cam_obj[camera_idx] = NULL;free(cam_obj);cam_obj = NULL;pthread_mutex_unlock(&g_intf_lock);return NULL;}else{
CDBG("%s: Open succeded\n", __func__);g_cam_ctrl.cam_obj[camera_idx] = cam_obj;pthread_mutex_unlock(&g_intf_lock);return &cam_obj->vtbl;}
}
到这里才真正的打开了设备节点,到此为止,如果继续深入分析,则要进入驱动程序。
device/moto/shamu/camera/QCamera2/stack/mm-camera-interface/src/mm_camera.c
int32_t mm_camera_open(mm_camera_obj_t *my_obj)
{
char dev_name[MM_CAMERA_DEV_NAME_LEN];int32_t rc = 0;int8_t n_try=MM_CAMERA_DEV_OPEN_TRIES;uint8_t sleep_msec=MM_CAMERA_DEV_OPEN_RETRY_SLEEP;unsigned int cam_idx = 0;CDBG("%s: begin\n", __func__);if (NULL == my_obj) {
goto on_error;}snprintf(dev_name, sizeof(dev_name), "/dev/%s",mm_camera_util_get_dev_name(my_obj->my_hdl));sscanf(dev_name, "/dev/video%u", &cam_idx);CDBG_HIGH("%s: dev name = %s, cam_idx = %d", __func__, dev_name, cam_idx);do{
n_try--;errno = 0;// 这里真正打开相机设备节点my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK);CDBG("%s: ctrl_fd = %d, errno == %d", __func__, my_obj->ctrl_fd, errno);if((my_obj->ctrl_fd >= 0) || (errno != EIO && errno != ETIMEDOUT) || (n_try <= 0 )) {
CDBG_HIGH("%s: opened, break out while loop", __func__);break;}ALOGE("%s:Failed with %s error, retrying after %d milli-seconds",__func__, strerror(errno), sleep_msec);usleep(sleep_msec * 1000);}while (n_try > 0);if (my_obj->ctrl_fd < 0) {
CDBG_ERROR("%s: cannot open control fd of '%s' (%s)\n",__func__, dev_name, strerror(errno));rc = -1;goto on_error;}/* 打开 domain socket*/n_try = MM_CAMERA_DEV_OPEN_TRIES;do {
n_try--;my_obj->ds_fd = mm_camera_socket_create(cam_idx, MM_CAMERA_SOCK_TYPE_UDP);CDBG("%s: ds_fd = %d, errno = %d", __func__, my_obj->ds_fd, errno);if((my_obj->ds_fd >= 0) || (n_try <= 0 )) {
CDBG("%s: opened, break out while loop", __func__);break;}CDBG("%s:failed with I/O error retrying after %d milli-seconds",__func__, sleep_msec);usleep(sleep_msec * 1000);} while (n_try > 0);if (my_obj->ds_fd < 0) {
CDBG_ERROR("%s: cannot open domain socket fd of '%s'(%s)\n",__func__, dev_name, strerror(errno));rc = -1;goto on_error;}pthread_mutex_init(&my_obj->msg_lock, NULL);pthread_mutex_init(&my_obj->cb_lock, NULL);pthread_mutex_init(&my_obj->evt_lock, NULL);pthread_cond_init(&my_obj->evt_cond, NULL);CDBG("%s : Launch evt Thread in Cam Open",__func__);mm_camera_cmd_thread_launch(&my_obj->evt_thread,mm_camera_dispatch_app_event,(void *)my_obj);/* 启动事件轮询线程* 我们将在用户首次注册 evt 时将 evt fd 添加到事件轮询线程中*/CDBG("%s : Launch evt Poll Thread in Cam Open", __func__);mm_camera_poll_thread_launch(&my_obj->evt_poll_thread,MM_CAMERA_POLL_TYPE_EVT);mm_camera_evt_sub(my_obj, TRUE);CDBG("%s: end (rc = %d)\n", __func__, rc);/* 我们不需要在返回之前在这里解锁cam_lock,* 因为对于打开,它是在intf_lock中完成的 */return rc;on_error:if (NULL == my_obj) {
CDBG_ERROR("%s: Invalid camera object\n", __func__);rc = -1;} else {
if (my_obj->ctrl_fd >= 0) {
close(my_obj->ctrl_fd);my_obj->ctrl_fd = -1;}if (my_obj->ds_fd >= 0) {
mm_camera_socket_close(my_obj->ds_fd);my_obj->ds_fd = -1;}}/* 我们不需要在返回之前在这里解锁cam_lock,* 因为对于打开,它是在intf_lock中完成的 */return rc;
}