基于MTK Camera框架进行了App -> FrameWork -> CameraService的时序流程的整理,本篇对其中的一些细节进行一下梳理和重点突出。
1.MTK Open Camer时序图
2.应用层OpenCamera需要check的点
从应用层角度来讲,openCamera层层递进、下发的流程还是比较清晰的;应用层需要特别关注的是openCamera结束后,底层传给应用层的状态,去check Camera是否open成功。Camera2DeviceImpl传给FrameWork层的第二个参数mStateCallback,就可以用来接收底层的open回调状态。
private final StateCallback mStateCallback = new StateCallback() {
@Override
public void onOpened(CameraDevice camera) {
LogHelper.i(mRespondTag, "[onOpened] camera = " + camera);
mRetryCount = 0;
createHandlerAndProxy(camera);
notifyStateCallback();
}
@Override
public void onClosed(CameraDevice camera) {
super.onClosed(camera);
if (mCameraDevice != null && mCameraDevice == camera) {
LogHelper.d(mRespondTag, "[onClosed] camera = " + camera);
mOpenStateCallback.onClosed(mCamera2Proxy);
mCameraDevice = null;
mCamera2Proxy = null;
}
}
@Override
public void one rror(CameraDevice camera, final int error) {
LogHelper.e(mRespondTag, "[onError] camera = " + camera + " error = " + error);
notifyStateCallback();
mOpenStateCallback.onError(mCamera2Proxy, error);
if (mRequestHandler != null) {
mRequestHandler.closeCamera();
}
if (mCameraDevice != null) {
mCameraDevice.close();
}
mCameraDevice = null;
mCamera2Proxy = null;
}
@Override
public void onDisconnected(CameraDevice camera) {
LogHelper.d(mRespondTag, "[onDisconnected] camera = " + camera);
if (mCameraDevice != null && mCameraDevice == camera) {
mOpenStateCallback.onDisconnected(mCamera2Proxy);
mCameraDevice = null;
mCamera2Proxy = null;
}
}
};
private void createHandlerAndProxy(CameraDevice camera) {
if (camera != mCameraDevice) {
mCameraDevice = camera;
mThreadLock.lock();
mRequestHandler = new Camera2Handler(mCameraId, mRequestThread.getLooper(),
mRespondHandler, camera, mDeviceInfoListener);
mThreadLock.unlock();
//根据FrameWork层传上来的CameraDevice初始化应用层的代理Camera2Proxy
mCamera2Proxy = new Camera2Proxy(
mCameraId, camera, mRequestHandler, mRespondHandler);
mRequestHandler.updateCamera2Proxy(mCamera2Proxy);
}
}
另外在应用层Device2Controller里面继承了Camera2Proxy.StateCallback,用于进行各个模块拿到需要的信息之后的管理。
public class DeviceStateCallback extends Camera2Proxy.StateCallback {
@Override
public void onOpened(@Nonnull Camera2Proxy camera2proxy) {
mModeHandler.obtainMessage(MSG_DEVICE_ON_CAMERA_OPENED,
camera2proxy).sendToTarget();
}
@Override
public void onClosed(@Nonnull Camera2Proxy camera2Proxy) {
mModeHandler.obtainMessage(MSG_DEVICE_ON_CAMERA_CLOSED,
camera2Proxy).sendToTarget();
}
@Override
public void onDisconnected(@Nonnull Camera2Proxy camera2proxy) {
mModeHandler.obtainMessage(MSG_DEVICE_ON_CAMERA_DISCONNECTED,
camera2proxy).sendToTarget();
}
@Override
public void one rror(@Nonnull Camera2Proxy camera2Proxy, int error) {
mModeHandler.obtainMessage(MSG_DEVICE_ON_CAMERA_ERROR, error, 0,
camera2Proxy).sendToTarget();
}
}
private class ModeHandler extends Handler {
public ModeHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DEVICE_ON_CAMERA_OPENED:
//对应调用到各个Mode拿到open 成功的回调信息之后的处理
doCameraOpened((Camera2Proxy) msg.obj);
break;
case MSG_DEVICE_ON_CAMERA_CLOSED:
doCameraClosed((Camera2Proxy) msg.obj);
break;
case MSG_DEVICE_ON_CAMERA_DISCONNECTED:
doCameraDisconnected((Camera2Proxy) msg.obj);
break;
case MSG_DEVICE_ON_CAMERA_ERROR:
doCameraError((Camera2Proxy) msg.obj, msg.arg1);
break;
default:
break;
}
}
}
下面以Photo模块为例,分析一下拿到camera open成功的回调之后应用层会做些什么样的处理。
@Override
public void doCameraOpened(@Nonnull Camera2Proxy camera2proxy) {
try {
if (CameraState.CAMERA_OPENING == getCameraState()
&& camera2proxy != null && camera2proxy.getId().equals(mCurrentCameraId)) {
mCamera2Proxy = camera2proxy;
mFirstFrameArrived = false;
if (mModeDeviceCallback != null) {
mModeDeviceCallback.onCameraOpened(mCurrentCameraId);
}
//更新相关的标志位为打开Camera成功
updateCameraState(CameraState.CAMERA_OPENED);
//更新拍照按钮为可拍照状态
updateShutterState(true);
//更新setting里面的参数属性 mSettingDevice2Configurator.setCameraCharacteristics(mCameraCharacteristics);
//更新预览size
updatePreviewSize();
//更新拍照size
updatePictureSize();
if (mPreviewSizeCallback != null) {
mPreviewSizeCallback.onPreviewSizeReady(new Size(mPreviewWidth,
mPreviewHeight));
}
if (mNeedSubSectionInitSetting) {
//创建Session通道
configureSession(true);
} else {
mSettingController.addViewEntry();
mSettingController.refreshViewEntry();
}
}
} catch (RuntimeException e) {
e.printStackTrace();
}
}
3.FrameWork层OpenCamera需要check的点
FrameWork层用于接收HAL层CameraDeviceClient的接口为ICameraDeviceUser,而FrameWork层返回给应用层的接口为CameraDevice,而应用层用Camera2Proxy来接收。
另外需要注意的是CameraManager里面的三方Camera apk,如Whatsapp、google Lens等走的openCamera的流程是一样的,通过cameraService.connectDevice后俩个参数mContext.getOpPackageName()和uid来进行区分处理。
private CameraDevice openCameraDeviceUserAsync(String cameraId,
CameraDevice.StateCallback callback, Executor executor, 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,
executor,
characteristics,
mContext.getApplicationInfo().targetSdkVersion);
ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
try {
// 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");
}
//FrameWork层用于接收HAL层CameraDevice的接口
cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), uid);
} 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 one rror 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.
//将HAL层的返回与CameraDeviceImpl绑定起来,FrameWork层返回到应用层的接口为CameraDeviceImpl
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
}
return device;
}
小结:
openCamera的流程看起来算是简单的,但是相机的应用场景却很复杂,很多模式切换需不需要closeCamera再openCamera等之类的问题在实际项目中是问题很多的。更重要的是需要配合Session流等一系列的操作,很可能open成功,因为一些其他原因又让你失败了,属实头疼。