android sse 人脸识别,基于Android Camera2之openCamera 流程

简介

frameworks\base\core\java\android\hardware\camera2

Camera2在Android 5.0上首次出现,主要重新定义了一套Camera 的使用接口API,设计思想出现了变化,具体的可自行搜索,此处主要介绍下Camera2的常见类以及使用流程。

CameraCaptureSession 类 会话类,即用户发起操作Camera设备的动作类,如录像拍照等

CaptureRequest类 请求类,用户对Camera发起请求的抽象封装类

CameraDevice类 Camera抽象类,类似于Camaera的一个客户端

CameraCharacteristics类 相机参数类,比如相机支持哪些特性,如分辨率集合等

除此之外这些类中还会存在内部类,内部类的作用是Camera Framework 层完成配置异步返回结果的抽象类

以上几个主要的类都在base/core下面,在对外发布API的时候App均可使用

frameworks\base\media

ImageReader类 相机采集回来的数据承载类,即相机的YUV元数据承载类

在APP层使用相机拍照 录制视频 等过程中上述主要类均离不开,本系列主要围绕关键类,介绍其关键流程,本文主要介绍openCamera流程

1: openCamera 基本流程

Framework层流程也是针对上诉几个关键步骤进行分析的,我们逐个往下分析

首先看下App层在openCamera的时候Framework层发生了什么,做了什么

frameworks\base\core\java\android\hardware\camera2\CameraManager.java

@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);

}

检查参数

public void openCameraForUid(@NonNull String cameraId,

@NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler,

int clientUid)

throws CameraAccessException {

if(TdDeviceManager.disallowOp(TdDeviceManager.DISABLED_CAMERA)) {

throw new IllegalArgumentException("camera is disabled by MDM");

}

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, clientUid);

}

关键方法

/**

* Helper for opening a connection to a camera with the given ID.

*

* @param cameraId The unique identifier of the camera device to open

* @param callback The callback for the camera. Must not be null.

* @param handler The handler to invoke the callback on. Must not be null.

* @param uid The UID of the application actually opening the camera.

* Must be USE_CALLING_UID unless the caller is a service

* that is trusted to open the device on behalf of an

* application and to forward the real UID.

*

* @throws CameraAccessException if the camera is disabled by device policy,

* too many camera devices are already open, or the cameraId does not match

* any currently available camera device.

*

* @throws SecurityException if the application does not have permission to

* access the camera

* @throws IllegalArgumentException if callback or handler is null.

* @return A handle to the newly-created camera device.

*

* @see #getCameraIdList

* @see android.app.admin.DevicePolicyManager#setCameraDisabled

*/

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

//[HSM]

if(!HwSystemManager.allowOp(HwSystemManager.PERMISSION_CAMERA)) {

ServiceSpecificException e = new ServiceSpecificException(ICameraService.ERROR_DISABLED);

throwAsPublicException(e);

}

Log.i(TAG, "open camera: " + cameraId + ", package name: " + mContext.getOpPackageName());

HwSystemManager.notifyBackgroundMgr(mContext.getOpPackageName(),

Binder.getCallingPid(),

Binder.getCallingUid(),

HwSystemManager.CAMARA_SERVICE_NOTIFY,

HwSystemManager.BACKGROUND_POLICY_OPEN);

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) {

if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {

throw new AssertionError("Should've gone down the shim path");

} else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||

e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||

e.errorCode == ICameraService.ERROR_DISABLED ||

e.errorCode == ICameraService.ERROR_DISCONNECTED ||

e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {

// Received one of the known connection errors

// The remote camera device cannot be connected to, so

// set the local camera to the startup error state

deviceImpl.setRemoteFailure(e);

if (e.errorCode == ICameraService.ERROR_DISABLED ||

e.errorCode == ICameraService.ERROR_DISCONNECTED ||

e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {

// Per API docs, these failures call onError and throw

throwAsPublicException(e);

}

} else {

// Unexpected failure - rethrow

throwAsPublicException(e);

}

} catch (RemoteException e) {

// Camera service died - act as if it's a CAMERA_DISCONNECTED case

ServiceSpecificException sse = new ServiceSpecificException(

ICameraService.ERROR_DISCONNECTED,

"Camera service is currently unavailable");

deviceImpl.setRemoteFailure(sse);

throwAsPublicException(sse);

}

// 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:创建了Camera Client 即 deviceImpl,此对象也就是返回APP进程中的对象

android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =new android.hardware.camera2.impl.CameraDeviceImpl(cameraId, callback,handler,characteristics,mContext.getApplicationInfo().targetSdkVersion);

2:将第一步创建的Client 和Framework 的Camera Service 联系起来,并且注册了一个回调,在物理Camera实际有什么状态时,及时通知到App层

cameraUser = cameraService.connectDevice(callbacks, cameraId,

mContext.getOpPackageName(), uid);

3:将deviceImpl 和ICameraDeviceUser cameraUser联系起来,即App用户提过deviceImpl下发指令,deviceImpl 通过cameraUser 操作Framework层的 Camera,并且将Framework层的Camera的客户端返回给高层

deviceImpl.setRemoteDevice(cameraUser);

2:openCamera关键步骤

关键步骤1:

在CameraManager openCamera的时候就创建了给APP 用的Client,此Client初始化的参数关注下即可,主要是传了camera 的id(哪个摄像头),摄像头的回调接口callback,此接口在Camera创建完成就返回给APP进程了,handler是App处理相机打卡回调的接收者,此处关键就是Framework 返回App的是CameraDeviceImpl 对象,但是实际接口返回的要求是一个CameraDevice对象,如下:

/**

* The method called when a camera device has finished opening.

*

*

At this point, the camera device is ready to use, and

* {@link CameraDevice#createCaptureSession} can be called to set up the first capture

* session.

*

* @param camera the camera device that has become opened

*/

public abstract void onOpened(@NonNull CameraDevice camera); // Must implement

关键步骤2:

此步骤是打开Camera的最关键的一步,首先是获取Framework层的Camera Service,即

ICameraService cameraService

ICameraService cameraService = CameraManagerGlobal.get().getCameraService();

然后就通过 cameraService

cameraUser = cameraService.connectDevice(callbacks, cameraId,

mContext.getOpPackageName(), uid);

主要传了 callback(Cameraservice 回调App的接口),Camera的id 进程号 和包名(下面代码删除了部分,主要说明此回调作用)

public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub {

@Override

public IBinder asBinder() {

return this;

}

@Override

public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {

}

@Override

public void onRepeatingRequestError(long lastFrameNumber) {

}

@Override

public void onDeviceIdle() {

}

@Override

public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) {

}

@Override

public void onResultReceived(CameraMetadataNative result,

}

@Override

public void onPrepared(int streamId) {

}

@Override

public void onRequestQueueEmpty() {

}

}

Callback对象,根据此对象定义可知是通过Binder传递过来的

通过Binder 调用Camera Service的connectDevice,Camera Service是Camera 进程初始化注册到ServicesManager中的,服务的承载代码即CameraService.cpp,因此查看下:

Status CameraService::connectDevice(

const sp<:camera2::icameradevicecallbacks>& cameraCb,

const String16& cameraId,

const String16& clientPackageName,

int clientUid,

/*out*/

sp<:camera2::icameradeviceuser>* device) {

ATRACE_CALL();

Status ret = Status::ok();

String8 id = String8(cameraId);

sp client = nullptr;

ret = connectHelper<:camera2::icameradevicecallbacks>(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;

}

String8 pid = String8::format("%d", getCallingPid());

POWERPUSH(129, clientName8.string(), id.string(), pid.string());//define in LogPower.java, 129 stand for camera start now

*device = client;

//add for send msg to nfc

char needSendMsg[255];

property_get("ro.config.hw_camera_nfc_switch",needSendMsg,"");

ALOGI("NFC polling %s", needSendMsg);

if (0 == strcmp(needSendMsg, "true")) {

String8 isOpen = String8::format("false");

android::allowNfcPolling(isOpen);

}

ALOGI("%s(), exit.", __FUNCTION__);

return ret;

}

关键函数connectHelper

template

Status CameraService::connectHelper(const sp& cameraCb, const String8& cameraId,

int halVersion, const String16& clientPackageName, int clientUid, int clientPid,

apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,

/*out*/sp& device) {

binder::Status ret = binder::Status::ok();

String8 clientName8(clientPackageName);

int originalClientPid = 0;

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(effectiveApiLevel));

sp client = nullptr;

{

// Acquire mServiceLock and prevent other clients from connecting

std::unique_ptr lock =

AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);

if (lock == nullptr) {

ALOGE("CameraService::connect (PID %d) rejected (too many other clients connecting)."

, clientPid);

return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,

"Cannot open camera %s for \"%s\" (PID %d): Too many other clients connecting",

cameraId.string(), clientName8.string(), clientPid);

}

// Enforce client permissions and do basic sanity checks

if(!(ret = validateConnectLocked(cameraId, clientName8,

/*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {

return ret;

}

// Check the shim parameters after acquiring lock, if they have already been updated and

// we were doing a shim update, return immediately

if (shimUpdateOnly) {

auto cameraState = getCameraState(cameraId);

if (cameraState != nullptr) {

if (!cameraState->getShimParams().isEmpty()) return ret;

}

}

status_t err;

sp clientTmp = nullptr;

std::shared_ptr<:clientdescriptor sp>>> partial;

if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,

IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,

/*out*/&partial)) != NO_ERROR) {

switch (err) {

case -ENODEV:

return STATUS_ERROR_FMT(ERROR_DISCONNECTED,

"No camera device with ID \"%s\" currently available",

cameraId.string());

case -EBUSY:

return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,

"Higher-priority client using camera, ID \"%s\" currently unavailable",

cameraId.string());

default:

return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,

"Unexpected error %s (%d) opening camera \"%s\"",

strerror(-err), err, cameraId.string());

}

}

if (clientTmp.get() != nullptr) {

// Handle special case for API1 MediaRecorder where the existing client is returned

device = static_cast(clientTmp.get());

return ret;

}

// give flashlight a chance to close devices if necessary.

mFlashlight->prepareDeviceOpen(cameraId);

int facing = -1;

int deviceVersion = getDeviceVersion(cameraId, /*out*/&facing);

if (facing == -1) {

ALOGE("%s: Unable to get camera device \"%s\" facing", __FUNCTION__, cameraId.string());

return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,

"Unable to get camera device \"%s\" facing", cameraId.string());

}

sp 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(tmp.get());

ALOGI("%s(), make client for '%s'.", __FUNCTION__, String8{clientPackageName}.string());

LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",

__FUNCTION__);

err = client->initialize(mCameraProviderManager);

if (err != OK) {

ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);

// Errors could be from the HAL module open call or from AppOpsManager

switch(err) {

case BAD_VALUE:

return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,

"Illegal argument to HAL module for camera \"%s\"", cameraId.string());

case -EBUSY:

return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,

"Camera \"%s\" is already open", cameraId.string());

case -EUSERS:

return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,

"Too many cameras already open, cannot open camera \"%s\"",

cameraId.string());

case PERMISSION_DENIED:

return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,

"No permission to open camera \"%s\"", cameraId.string());

case -EACCES:

return STATUS_ERROR_FMT(ERROR_DISABLED,

"Camera \"%s\" disabled by policy", cameraId.string());

case -ENODEV:

default:

return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,

"Failed to initialize camera \"%s\": %s (%d)", cameraId.string(),

strerror(-err), err);

}

}

// Update shim paremeters for legacy clients

if (effectiveApiLevel == API_1) {

// Assume we have always received a Client subclass for API1

sp shimClient = reinterpret_cast(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) {

// If only updating legacy shim parameters, immediately disconnect client

mServiceLock.unlock();

client->disconnect();

mServiceLock.lock();

} else {

// Otherwise, add client to active clients list

finishConnectLocked(client, partial);

}

} // lock is destroyed, allow further connect calls

device = client;

return ret;

}

关键函数makeClient

Status CameraService::makeClient(const sp& cameraService,

const sp& 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* 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:

if (effectiveApiLevel == API_1) { // Camera1 API route

sp tmp = static_cast(cameraCb.get());

*client = new CameraClient(cameraService, tmp, packageName, cameraIdToInt(cameraId),

facing, clientPid, clientUid, getpid(), legacyMode);

} else { // Camera2 API route

ALOGW("Camera using old HAL version: %d", deviceVersion);

return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,

"Camera device \"%s\" HAL version %d does not support camera2 API",

cameraId.string(), deviceVersion);

}

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:

case CAMERA_DEVICE_API_VERSION_3_4:

if (effectiveApiLevel == API_1) { // Camera1 API route

sp tmp = static_cast(cameraCb.get());

*client = new Camera2Client(cameraService, tmp, packageName, cameraIdToInt(cameraId),

facing, clientPid, clientUid, servicePid, legacyMode);

} else { // Camera2 API route

sp<:camera2::icameradevicecallbacks> tmp =

static_cast<: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 {

// A particular HAL version is requested by caller. Create CameraClient

// based on the requested HAL version.

if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&

halVersion == CAMERA_DEVICE_API_VERSION_1_0) {

// Only support higher HAL version device opened as HAL1.0 device.

sp tmp = static_cast(cameraCb.get());

*client = new CameraClient(cameraService, tmp, packageName, cameraIdToInt(cameraId),

facing, clientPid, clientUid, servicePid, legacyMode);

} else {

// Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.

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 STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,

"Camera device \"%s\" (HAL version %d) cannot be opened as HAL version %d",

cameraId.string(), deviceVersion, halVersion);

}

}

return Status::ok();

}

在此处有2 个关键步骤

步骤1:创建Camera 的客户端 Client,根据调用出可知是 CameraDeviceClient,创建时同时传入了一个Hal层回调的状态对象,为ICameraDeviceCallbacks 分别对应上面2个函数

makeClient 函数 会根据传入的HAL版本号halVersion 和设备版本号deviceVersion 进行初始化以及API的版本号,初始化了一个CamDeviceClien对象

查看构造函数发现初始化了父类Camera2ClientBase

CameraDeviceClient::CameraDeviceClient(const sp& cameraService,

const sp<:camera2::icameradevicecallbacks>& remoteCallback,

const String16& clientPackageName,

const String8& cameraId,

int cameraFacing,

int clientPid,

uid_t clientUid,

int servicePid) :

Camera2ClientBase(cameraService, remoteCallback, clientPackageName,

cameraId, cameraFacing, clientPid, clientUid, servicePid),

mInputStream(),

mStreamingRequestId(REQUEST_ID_NONE),

mRequestIdCounter(0) {

ATRACE_CALL();

ALOGI("CameraDeviceClient %s: Opened", cameraId.string());

}

继续查看最终发现是初始化了一个 Camera3Device对象,这个就是java APP

在打开 Cmaera 时真正创建的Frameowok 层对象,属于真正干活的

template

Camera2ClientBase::Camera2ClientBase(

const sp& cameraService,

const sp& remoteCallback,

const String16& clientPackageName,

const String8& cameraId,

int cameraFacing,

int clientPid,

uid_t clientUid,

int servicePid):

TClientBase(cameraService, remoteCallback, clientPackageName,

cameraId, cameraFacing, clientPid, clientUid, servicePid),

mSharedCameraCallbacks(remoteCallback),

mDeviceVersion(cameraService->getDeviceVersion(TClientBase::mCameraIdStr)),

mDeviceActive(false)

{

ALOGI("Camera %s: Opened. Client: %s (PID %d, UID %d)", cameraId.string(),

String8(clientPackageName).string(), clientPid, clientUid);

mInitialClientPid = clientPid;

mDevice = new Camera3Device(cameraId);

LOG_ALWAYS_FATAL_IF(mDevice == 0, "Device should never be NULL here.");

}

步骤二:

对此CameraDeviceClient 进行初始化,初始化的时候传入了mCameraProviderManager,即

client = static_cast(tmp.get());

ALOGI("%s(), make client for '%s'.", __FUNCTION__, String8{clientPackageName}.string());

LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",

__FUNCTION__);

err = client->initialize(mCameraProviderManager);

sp mCameraProviderManager,此对象在CameraService 初始化的时候就构造出来了,主要工作之一也是连接HAI层

mCameraProviderManager 是CameraServics 构造函数初始化的时候赋值的

if (nullptr == mCameraProviderManager.get()) {

mCameraProviderManager = new CameraProviderManager();

res = mCameraProviderManager->initialize(this);

if (res != OK) {

ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",

__FUNCTION__, strerror(-res), res);

return res;

}

}

3:通知APP层Camera状态

frameworks\base\core\java\android\hardware\camera2\impl\CameraDeviceImpl.java

通知到APP Camera 已经打开,即在nataive 创建了CameraClient 完成之后CameraManager将native camera device设到java 的CameraDevice 之后即通知了APP,Camera创建好了

deviceImpl.setRemoteDevice(cameraUser);

device = deviceImpl;

/**

* Set remote device, which triggers initial onOpened/onUnconfigured callbacks

*

*

This function may post onDisconnected and throw CAMERA_DISCONNECTED if remoteDevice dies

* during setup.

*

*/

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);

}

}

private final Runnable mCallOnOpened = new Runnable() {

@Override

public void run() {

StateCallbackKK sessionCallback = null;

synchronized(mInterfaceLock) {

if (mRemoteDevice == null) return; // Camera already closed

sessionCallback = mSessionStateCallback;

}

if (sessionCallback != null) {

sessionCallback.onOpened(CameraDeviceImpl.this);

}

mDeviceCallback.onOpened(CameraDeviceImpl.this);

}

};

此处是在App层定义了AIDL 接口,但是服务是native层的,为了双方能通信,Aidl的调用客户端是使用java 实现,服务端采用c++实现的,确保了binder通信正常,此处用到的Binder服务关键函数为

connectDevice,因此connectDevice 的通信方式再此跟踪下:

frameworks\av\camera\aidl\android\hardware\ICameraService.aidl

/**

* Open a camera device through the new camera API

* Only supported for device HAL versions >= 3.2

*/

ICameraDeviceUser connectDevice(ICameraDeviceCallbacks callbacks,

String cameraId,

String opPackageName,

int clientUid);

03954ac5f1ac

aidl_java.png

03954ac5f1ac

aidl_java2.png

服务端实现此函数收到函数请求,如下:

class BpCameraService : public ::android::BpInterface {

public:

explicit BpCameraService(const ::android::sp<::android::ibinder>& _aidl_impl);

virtual ~BpCameraService() = default;

::android::binder::Status getNumberOfCameras(int32_t type, int32_t* _aidl_return) override;

::android::binder::Status getCameraInfo(int32_t cameraId, ::android::hardware::CameraInfo* _aidl_return) override;

::android::binder::Status connect(const ::android::sp<::android::hardware::icameraclient>& client, int32_t cameraId, const ::android::String16& opPackageName, int32_t cl

::android::binder::Status connectDevice(const ::android::sp<::android::hardware::camera2::icameradevicecallbacks>& callbacks, const ::android::String16& cameraId, const

::android::binder::Status connectLegacy(const ::android::sp<::android::hardware::icameraclient>& client, int32_t cameraId, int32_t halVersion, const ::android::String16&

::android::binder::Status addListener(const ::android::sp<::android::hardware::icameraservicelistener>& listener, ::std::vector<::android::hardware::camerastatus>* _aidl

::android::binder::Status removeListener(const ::android::sp<::android::hardware::icameraservicelistener>& listener) override;

::android::binder::Status getCameraCharacteristics(const ::android::String16& cameraId, ::android::hardware::camera2::impl::CameraMetadataNative* _aidl_return) override;

::android::binder::Status getCameraVendorTagDescriptor(::android::hardware::camera2::params::VendorTagDescriptor* _aidl_return) override;

::android::binder::Status getCameraVendorTagCache(::android::hardware::camera2::params::VendorTagDescriptorCache* _aidl_return) override;

::android::binder::Status getLegacyParameters(int32_t cameraId, ::android::String16* _aidl_return) override;

::android::binder::Status supportsCameraApi(const ::android::String16& cameraId, int32_t apiVersion, bool* _aidl_return) override;

::android::binder::Status setTorchMode(const ::android::String16& cameraId, bool enabled, const ::android::sp<::android::ibinder>& clientBinder) override;

::android::binder::Status notifySystemEvent(int32_t eventId, const ::std::vector& args) override;

}; // class BpCameraService

}

03954ac5f1ac

services2.png

Status CameraService::connectDevice(

const sp<:camera2::icameradevicecallbacks>& cameraCb,

const String16& cameraId,

const String16& clientPackageName,

int clientUid,

/*out*/

sp<:camera2::icameradeviceuser>* device) {

ATRACE_CALL();

Status ret = Status::ok();

String8 id = String8(cameraId);

sp client = nullptr;

ret = connectHelper<:camera2::icameradevicecallbacks>(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;

}

String8 pid = String8::format("%d", getCallingPid());

POWERPUSH(129, clientName8.string(), id.string(), pid.string());//define in LogPower.java, 129 stand for camera start now

*device = client;

//add for send msg to nfc

char needSendMsg[255];

property_get("ro.config.hw_camera_nfc_switch",needSendMsg,"");

ALOGI("NFC polling %s", needSendMsg);

if (0 == strcmp(needSendMsg, "true")) {

String8 isOpen = String8::format("false");

android::allowNfcPolling(isOpen);

}

ALOGI("%s(), exit.", __FUNCTION__);

return ret;

}

简单捋顺下调用过程:

CameraManager.Java的connectDevice  ICameraService.java(系统编译)的onTransact-

ICameraService.cpp(系统编译)的BpCameraService::connectDevice()ICameraService.cpp(系统编译)的::android::status_t BnCameraService::onTransact-

CameraService.cpp的CameraService::connectDevice()

APP 进程在打开之后就等待nataive 层运行结束,native层直到上节分析的创建成功

CameraDevice对象之后由CameraManager进行给java层的CameraDeviceIml 设置

setRemoteDevice,APP进程打开设备成功,得到了framework给到的CameraDeviceIml对象,可以后续通过此对Camera进行操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/502392.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fetch 不是xhr_春招|前端2019应届春招:不是被大厂选,而是选大厂(字节跳动,美团,网易)...

作者&#xff1a;Thescavenger链接&#xff1a;https://www.nowcoder.com/discuss/163165来源&#xff1a;牛客网你需要的前端面经个人情况本科&#xff0c;成都双非大学&#xff0c;大三开始正式学习前端&#xff0c;主攻 react&#xff0c;目前大四。已拿美团、字节跳动 offe…

vscode编辑python_VSCode+Python开发环境

准备开始转向用VSCode做开发&#xff0c;所以把一些常用的开发环境转移到VSCode上。 这次搭建的是Python3的开发环境。 其他相关博文&#xff1a; 一、测试环境 Windows 10 VSCode v1.11.1 Python v3.6.1 二、安装Visual Studio Code 三、安装Python这一步&#xff0c;记得…

多帧点云数据拼接合并_PCL点云处理实践(二):点云的处理和拼接

滤除背景我们获得的点云可能包含一部分背景的点云。要去除背景&#xff0c;只保留人体信息&#xff0c;最简单的方式是使用直通滤波器滤除较远点。这部分代码如下&#xff1a;123456pcl::PassThrough<:pointxyz>pass; //设置滤波器对象pass.setInputCloud(cloud); //设置…

html5 css3浏览器,五大主流浏览器CSS3和HTML5兼容性大比拼

五大主流浏览器CSS3和HTML5兼容性大比拼出处&#xff1a;快科技 2011-05-26 16:15:42 编辑&#xff1a;萧萧[爆料] 收藏文章各大主流浏览器对CSS3和HTML5的支持越来越完善&#xff0c;曾经让多少前端开发人员心碎的IE系也开始拥抱标准。就在前几天&#xff0c;W3C的HTML5社…

自学python 编程基础知识_python学习-基础知识-1

1、计算机历史 计算机使用高低电压的两种状态来描述信息。计算机可以理解的只有二进制数据即010100011....&#xff0c;1个比特位可以表示的状态只有2种&#xff0c;n个比特位可以表示的状态有2的n次方种。 所以如果想要描述天气状态&#xff1a;天晴、下雨、刮风、下雪、霜冻&…

comparator 字符串比较大小_Java中Comparable和Comparator实现对象比较

当需要排序的集合或数组不是单纯的数字型时&#xff0c;通常可以使用Comparator或Comparable&#xff0c;以简单的方式实现对象排序或自定义排序。A comparison function, which imposes a total ordering on some collection of objects. Comparators can be passed to a sort…

html中属性的作用,html的标签中 unselectable=on 属性的作用

在IE浏览器中&#xff0c;当input获得焦点时&#xff0c;点击有unselectable"on"属性的标签时&#xff0c;不会触发onblur事件。加上该属性的元素不能被选中。< !DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">< html>< h…

一个控制器怎么转发到另外一个控制器_楼宇自动化系统(BAS),DDC,一个最核心的控制器...

楼宇自动化系统(BAS)&#xff0c;一个熟悉又陌生的系统楼宇自控系统(BAS系统)设有一个中央监控中心&#xff0c;系统配置一个或多个网络控制器&#xff0c;由多条总线或计算机网络将各种功能的控制器与中央工作站相连&#xff0c;完成对空调、给排水、通风、电梯等子系统的监控…

秒表计时器怎么读_秒表怎么读数

展开全部秒表的大圈为秒&#xff0c;小圈为分。若大圈是30分格(顶上写的是30&#xff0c;可能有60格&#xff0c;表明精度到半秒)&#xff0c;小圈里62616964757a686964616fe59b9ee7ad9431333431366239一分钟就分为两小格&#xff0c;读完整的几分&#xff0c;若过了一小格&…

html封装windows,windows 系统封装,打造一份属于自己的系统!

在电脑的使用过程中&#xff0c;由于我们每个人的使用习惯和使用方式不同&#xff0c;所以我们都会对Windows系统进行自己的设置&#xff0c;尤其是一些搞数码软件的&#xff0c;如果不小心系统坏了&#xff0c;重装系统后&#xff0c;还得一一去进行重新设置&#xff0c;非常麻…

daoi php_聊聊这些年用过的AOI

外面下着雨&#xff0c;我在家里宅&#xff0c;听着歌喝着去年的茶&#xff0c;无聊的很&#xff0c;开个话题聊下这些年用过的AOI。某年进入AOI这行&#xff0c;我的很多老同事都早已转行了&#xff0c;由于我没什么过人之处&#xff0c;只会死干&#xff0c; 现在还在做AOI。…

python语言例子_【Python】SimPy的使用示例-Go语言中文社区

使用SimPY进行离散事件仿真 SimPY是一个Python下的第三方库&#xff0c;可以方便的进行离散事件的仿真。仿真速度比较快。下面记录一下我的一点心得&#xff0c;不保证完全正确&#xff0c;供参考。 安装 $ pip install -U simpy pycharm可以再File | Settings | Project: Simu…

所有的图放到一个html,拖放是HTML5标准的组成部分,若想要把drag1图片放入d

dataTransfer 对象主要有两个方法&#xff1a;getData() 和 setData()&#xff0c;用来取值和保存值。setData() 方法的第一个参数&#xff0c;也是 getData() 方法唯一的一个参数&#xff0c;是一个字符串&#xff0c;表示保存的数据类型。IE只定义了"text" 或 &quo…

vue变量传值_VUE 学习——父组件传值给子组件

在我们编写前端代码时&#xff0c;经常遇到的一种场景&#xff0c;子组件需要使用父组件的值&#xff0c;这种情况下&#xff0c;我们可以使用props帮助我们进行父子组件间的通信。这里我们先模拟一个场景&#xff0c;展示如何使用。场景&#xff1a;在父组件修改值&#xff0c…

matlab 最小二乘法拟合_Scripy实现最小二乘法与股票K线回归

python的Scripy提供了丰富的数学工具&#xff0c;python的科学计算包scipy的里面提供了一个函数&#xff0c;可以求出任意的想要拟合的函数的参数。那就是scipy.optimize包里面的leastsq函数。函数原型是&#xff1a;leastsq(func, x0, args(), DfunNone, full_output0, col_de…

html 调高德地图 导航,在H5页面内通过地址调起高德地图实现导航

项目中用到的一个功能是要通过点击地址来实现打开地图app实现地址导航。如下图&#xff1a;实现思路就是在H5页面内通过点击marker图标然后进行当前位置与页面上地址的路程规划与导航。由于项目中用到的是高德地图&#xff0c;所以这里用到的是调起高德地图APP来实现该功能。首…

.jar文件如何打开_ofd发票文件如何打开

有时候大家查找文件的时候会不会觉得很心烦&#xff0c;因为经常能碰到OFD格式的文件&#xff0c;但是我们却不知道怎么打开&#xff0c;造成了很多困扰。我以前也常常遇到这样的情况&#xff0c;但是最近我发现了一个好办法&#xff0c;迫不及待地想分享给大家了&#xff0c;可…

印刷体是什么意思_家长晒出4年级小学霸课前笔记,字迹堪比“印刷体”,老师都羡慕...

目前&#xff0c;很多小学生都在家里上网课&#xff0c;为了达到最佳学习效果&#xff0c;要提前做好预习工作&#xff0c;尤其是语文这一学科&#xff0c;更需要预习。这不就有一位4年级学霸的家长晒出了孩子日常课前预习笔记。他不仅对文章进行了合理的布置和预习&#xff0c…

不使用自带函数求区域的周长_Excel表格中最强大求和函数______DSUM函数

在Excel表格中说起求和函数&#xff0c;朋友们首先会想到的是sum、sumif、和sumifs函数。这篇文章为朋友们分享最强大求和函数&#xff0c;数据库函数之DSUM函数。这个函数不仅能完成各种要求的求和&#xff0c;还可以用于查找。一.DSUM函数说明&#xff1a;1.语法&#xff1a;…

python 用if判断一个数是不是整数_Python基础教程07-函数和模块的使用

在讲解本章节的内容之前&#xff0c;我们先来研究一道数学题&#xff0c;请说出下面的方程有多少组正整数解。x1x2x3x48事实上&#xff0c;上面的问题等同于将8个苹果分成四组每组至少一个苹果有多少种方案。想到这一点问题的答案就呼之欲出了。可以用Python的程序来计算出这个…