Media Module之Camera(二) 初始化
2. 初始化
初始化主要分为几个部分,SM注册service,app层和framework层去打开相机操作,底层的服务的绑定,底层server端的初始化,HAL层去open。
2.1 注册service
手机开机后,会走init.rc流程,init.rc会启动MediaServer Service。
system/core/rootdir/init.rc
service media /system/bin/mediaserver
class main
user media
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm qcom_diag
ioprio rt 4
在启动MediaServer之后会进入其main方法中:
frameworks\av\media\mediaserver\main_mediaserver.cpp
int main(int argc __unused, char** argv)
{
... ...
if (doLog && (childPid = fork()) != 0) {
... ...
} else {
CameraService::instantiate();
}
}
对于CameraService::instantiate()方法来说,是CameraService的父类BinderService来实现的:
frameworks\native\include\binder\BinderService.h
namespace android {
template<typename SERVICE>
class BinderService
{
public:
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
... ...
static void instantiate() { publish(); }
... ...
可以发现在publish()函数中,CameraService完成服务的注册 。SERVICE是个模板,这里是注册CameraService,所以可用CameraService代替
return sm->addService(String16(CameraService::getServiceName()), new CameraService());
这样,Camera就在ServiceManager完成服务注册,提供给client随时使用。因为由init.rc在启动时调用,所以在设备开机的时候Camera就会注册一个服务,用作binder通信。
2.2 从launcher进入相机
主要流程在onCreate 可以看到从SharedPreferences 文件中获取初始化的模式,根据SharedPreferences文件中的filterMode的值决定初始化模式是普通还是全景还是特效模式;
@Override
public void onCreate(Bundle state) {
super.onCreate(state);
System.out.println(888);
.................
.................
.................
/**
紧接着下面对其他应用访问相机根据其intent做了判断处理,如果拍照就进入拍照模式,录像就进入录像模式;
**/
int moduleIndex = -1;
if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())|| MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
moduleIndex = ModuleSwitcher.VIDEO_MODULE_INDEX;
} else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
|| MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
.getAction())) {
moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
if (prefs.getInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, -1) == ModuleSwitcher.GCAM_MODULE_INDEX && GcamHelper.hasGcamCapture()) {
moduleIndex = ModuleSwitcher.GCAM_MODULE_INDEX;
}
} else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
|| MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;//信息访问相机拍照(android.media.action.IMAGE_CAPTURE);
} else {
moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
}
setModuleFromIndex(moduleIndex);
mCurrentModule.init(this, mCameraModuleRootView) ;
.................
.................
.................
registerSDcardMountedReceiver();//注册SD卡挂载的监听,弹出提示是否保存到SD卡
MediaStore这个类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,android把所有的多媒体数据库接口进行了封装,所有的数据库不用自己进行创建,直接调用利用ContentResolver去调用那些封装好的接口就可以进行数据库的操作了。
oncreate中还注册了一些监听、观察者,动态注册SD卡是否挂载的广播;初始化一些服务;以及安全模式与非安全模式的查看已拍摄图片的一些处理;有兴趣自己可以查看;
安全模式:有密码锁屏;非安全模式:无密码设置;
初次进入默认的是moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
onCreate 调用setModuleFromIndex 方法, 根据传进来的ID进行模式初始化;
private void setModuleFromIndex(int moduleIndex) {
mCurrentModuleIndex = moduleIndex;
switch (moduleIndex) {
case ModuleSwitcher.VIDEO_MODULE_INDEX:
mCurrentModule = new VideoModule();
break;
case ModuleSwitcher.PHOTO_MODULE_INDEX:
mCurrentModule = new PhotoModule();
break;
.......
.......
.......
default:
// Fall back to photo mode.
mCurrentModule = new PhotoModule();
mCurrentModuleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
break;
}
}
photoModule.java
@Override
public void init(CameraActivity activity, View parent) {
System.out.println(151515);
mActivity = activity;
...........
...........
...........
if (mOpenCameraThread == null) {
mOpenCameraThread = new OpenCameraThread();
mOpenCameraThread.start();
}
mUI = new PhotoUI(activity, this, parent);
initializeControlByIntent();//根据传进来的intent进行初始化
...........
...........
...........
Storage.setSaveSDCard(
mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));//根据设置菜单的参数判断保存的位置是SD卡还是本机
mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
mRefocusSound = mSoundPool.load(mActivity, R.raw.camera_click_x5, 1);
}
photoModule.java
private void initializeControlByIntent() {
mUI.initializeControlByIntent();
if (mIsImageCaptureIntent) {
System.out.println("AAAA");
setupCaptureParams();
}
}
photoUI.java
public void initializeControlByIntent() {
System.out.println(171717);
mBattery = (ImageView) mRootView.findViewById(R.id.battery_img);
mBurstImg = (ImageView) mRootView.findViewById(R.id.burst_img);
mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
mThumbnail.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (!CameraControls.isAnimating()
&& mController.getCameraState() != PhotoController.SNAPSHOT_IN_PROGRESS)
mActivity.gotoGallery();//点击缩略图进入到图库
}
});
mMenuButton = mRootView.findViewById(R.id.menu);
mMenuButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(mMenu != null){
System.out.println(212121);
mMenu.openFirstLevel();
mVideoMenu.openFirstLevel();
}
}
});
if (mController.isImageCaptureIntent()) {//其他应用(信息)访问会走进这里
System.out.println(181818);
hideSwitcher();
mMenuButton.setVisibility(View.VISIBLE);
mTimerSwitcher.setVisibility(View.VISIBLE);
showTimerPickers();
//yanglei modify for bug 67085 20150708 start
// mSwitcher.setImageCaptureIntent(true);
//yanglei modify for bug 67085 20150708 end
ViewGroup cameraControls = (ViewGroup) mRootView.findViewById(R.id.camera_controls);
mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls);
mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
mReviewRetakeButton = mRootView.findViewById(R.id.btn_retake);
mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
mReviewCancelButton.setVisibility(View.VISIBLE);
mVideoButton.setVisibility(View.GONE);
mModelSwitcher.setVisibility(View.GONE);
mReviewDoneButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mController.onCaptureDone();//拍照的监听
}
});
mReviewCancelButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mController.onCaptureCancelled();//取消拍照的监听
}
});
mReviewRetakeButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mController.onCaptureRetake();//拍完之后不满意重新拍的监听
}
});
}
}
photoModule.java
@Override
public boolean isImageCaptureIntent() {
String action = mActivity.getIntent().getAction();
return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
|| CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
}
photoModule.java
private void setupCaptureParams() {
Bundle myExtras = mActivity.getIntent().getExtras();
if (myExtras != null) {
mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
mCropValue = myExtras.getString("crop");
}
}
在onResume()方法中进入相应的模式
CameraActivity.java
@Override
public void onResume() {
..............
..............
..............
mCurrentModule.onResumeBeforeSuper();
super.onResume();
mCurrentModule.onResumeAfterSuper();
setSwipingEnabled(true);
if (mResetToPreviewOnResume) {
// Go to the preview on resume.
mFilmStripView.getController().goToFirstItem();
}
// Default is showing the preview, unless disabled by explicitly
// starting an activity we want to return from to the filmstrip rather
// than the preview.
mResetToPreviewOnResume = true;
..............
..............
}
mFilmStripView胶片视图,可以看成用胶片录电影,最前面的是正在录制,后面的是已经录制完毕的; goToFirstItem()可以理解为到最开始录的胶片,即预览的界面;
然后会进入photoModule.java中,注意在cameraActivity中的onResumeBeforeSuper()与onResumeAfterSuper()方法的实现是在相应的模式中;
onResumeBeforeSuper()作用是做一些UI显示及动态注册广播,及判断SD卡是否存在可写,不可写则保存到内部存储,并将保存路径用sharedPreference保存起来;
onResumeAfterSuper():主要启动onResumeTasks();方法,更新剩余内存的大小
更新剩下可以拍摄的照片的数量
@Override
public void onResumeAfterSuper() {
// Add delay on resume from lock screen only, in order to to speed up
// the onResume --> onPause --> onResume cycle from lock screen.
// Don't do always because letting go of thread can cause delay.
String action = mActivity.getIntent().getAction();
if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
|| MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
Log.v(TAG, "On resume, from lock screen.");
// Note: onPauseAfterSuper() will delete this runnable, so we will
// at most have 1 copy queued up.
mHandler.postDelayed(new Runnable() {
public void run() {
onResumeTasks();
}
}, ON_RESUME_TASKS_DELAY_MSEC);
} else {
Log.v(TAG, "On resume.");
onResumeTasks();
}
mHandler.post(new Runnable(){
@Override
public void run(){
mActivity.updateStorageSpaceAndHint();//更新剩余内存的大小
updateRemainingPhotos();//更新剩下可以拍摄的照片的数量
}
});}
private void onResumeTasks() {
Log.v(TAG, "Executing onResumeTasks.");
System.out.println(333);
if (mOpenCameraFail || mCameraDisabled) return;
if (mOpenCameraThread == null) {
mOpenCameraThread = new OpenCameraThread();
mOpenCameraThread.start();
}
mJpegPictureCallbackTime = 0;
mZoomValue = 0;
// If first time initialization is not finished, put it in the
// message queue.
if (!mFirstTimeInitialized) {
mHandler.sendEmptyMessage(FIRST_TIME_INIT);
} else {
initializeSecondTime();
.............
.............
.............
通过onResumeTasks()方法,打开相机,开启预览
private class OpenCameraThread extends Thread {
@Override
public void run() {
openCamera();// 第一步开启camera
startPreview();// 第二部开始预览
}
}
private void openCamera() {
// We need to check whether the activity is paused before long
// operations to ensure that onPause() can be done ASAP.
if (mPaused) {
return;
}
Log.v(TAG, "Open camera device.");
mCameraDevice = CameraUtil.openCamera(
mActivity, mCameraId, mHandler,
mActivity.getCameraOpenErrorCallback());
if (mCameraDevice == null) {
Log.e(TAG, "Failed to open camera:" + mCameraId);
mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL);
return;
}
.......
.......
.......
}
mCameraDevice = CameraUtil.openCamera(
mActivity, mCameraId, mHandler,
mActivity.getCameraOpenErrorCallback())
其中mCameraDevice是com.android.camera.CameraManager.CameraProxy;的实例。
CameraUtil属于公共的API,用于给不同模块提供对Camera的不同操作。
在它openCamera 方法里,执行:
CameraHolder.instance().open(handler, cameraId, cb);
其中CameraHolder.instance()单例模式。目的就是控制,相机开启的只有能是一个。再次开启前,要确认上次已经销毁。
b、 在CameraManager系统服务,获得camera设备对象为Camera设备提供操作的方法。
@Override
public CameraManager.CameraProxy cameraOpen(
Handler handler, int cameraId, CameraOpenErrorCallback callback) {
mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0,
CameraOpenErrorCallbackForward.getNewInstance(
handler, callback)).sendToTarget();
mCameraHandler.waitDone();
if (mCamera != null) {
return new AndroidCameraProxyImpl();// ----->这个就是丢给前台的mCameraDevice
} else {
return null;
}
}
CameraProxy 里AndroidCameraProxyImpl类这个接口就是将对Camera 接受和发送的操作,送达到Camera设备。
这个接口的实现类是AndroidCameraProxyImpl,这个类属于AndroidCameraManagerImpl的内部类。在AndroidCameraManagerImpl.java 里面还有一个内部类CameraHandler,这个类属于Handler。在CameraHandler的handleMessage方法里,就是根据不同的消息参数来对android.hardware.Camera 进行控制。比如打开,释放,对焦,变焦等等
2.3 服务绑定
Binder服务已经在系统中注册,下面分析服务的客户端和服务端是如何绑定的。首先在app层中,调用了framework Camera.java中的open(int cameraId)方法:
public static Camera open(int cameraId) {
return new Camera(cameraId);
}
调用了构造函数:
Camera(int cameraId) {
int err = cameraInitNormal(cameraId);
... ...
}
在构造函数中调用了cameraInitNormal方法:
private int cameraInitNormal(int cameraId) {
return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
// 代表camera能够正常连接和打开的常量
}
接下来调用的是cameraInitVersion方法:
private int cameraInitVersion(int cameraId, int halVersion) {
mShutterCallback = null;
// 将各种回调设置初始值
... ...
// 新建looper进行消息循环
Looper looper;
if ((looper = Looper.myLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else if ((looper = Looper.getMainLooper()) != null) {
mEventHandler = new EventHandler(this, looper);
} else {
mEventHandler = null;
}
String packageName = ActivityThread.currentOpPackageName();
// 强制使用HAL1的版本,如果存在 HAL2异常的情况
... ...
//调用native方法native_setup
return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
}
可以看出,在构造方法的层级调用中,走到了native方法native_setup。下面分析此native方法:
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
... ...
sp<Camera> camera;
if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
// Default path: hal version is don't care, do normal camera connect.
//clientName是通过将clientPackageName从jstring转换为String16格式得到;
//Camera::USE_CALLING_UID是定义在Camera.h中的枚举类型,其值为//ICameraService::USE_CALLING_UID(同样为枚举类型,值为-1)。
camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID);
}
... ...
// We use a weak reference so the Camera object can be garbage collected.
// The reference is only used as a proxy for callbacks.
//JNICameraContext这个类是一个监听类,用于处理底层Camera回调函数传来的数据和消息
sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
context->incStrong((void*)android_hardware_Camera_native_setup);
camera->setListener(context);
// save context in opaque field
env->SetLongField(thiz, fields.context, (jlong)context.get());
return NO_ERROR;
}
可以看到,在判断HAL的版本之后就调用了native层Camera的connect方法:
frameworks/av/camera/Camera.cpp
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
int clientUid)
{
return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}
在return返回的是CameraBaseT调用connect方法,Camera类继承模板类CameraBase,先找到CameraBaseT的头文件:
/frameworks/av/include/camera/CameraBase.h
static sp<TCam> connect(int cameraId,
const String16& clientPackageName,
int clientUid);
发现是强引用类型TCam调用的方法,接下来在CameraBase.cpp中查看此方法:
frameworks/av/camera/CameraBase.cpp
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
status_t status = NO_ERROR;
// 获取到cameraservice
const sp<ICameraService>& cs = getCameraService();
if (cs != 0) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
//强引用,调用ICameraService的connect方法
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
/*out*/ c->mCamera);
}
if (status == OK && c->mCamera != 0) {
IInterface::asBinder(c->mCamera)->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
ALOGW("An error occurred while connecting to camera: %d", cameraId);
c.clear();
}
return c;
}
const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
Mutex::Autolock _l(gLock);
if (gCameraService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16(kCameraServiceName));
if (binder != 0) {
break;
}
ALOGW("CameraService not published, waiting...");
usleep(kCameraServicePollDelay);
} while(true);
if (gDeathNotifier == NULL) {
gDeathNotifier = new DeathNotifier();
}
binder->linkToDeath(gDeathNotifier);
//通过binder获取CameraService实例
gCameraService = interface_cast<ICameraService>(binder);
}
ALOGE_IF(gCameraService == 0, "no CameraService!?");
return gCameraService;
}
可以看出,在connect方法中获取了cameraservice的实例,然后connect()函数在BpCameraService和BnCameraService的父类ICameraService中声明为纯虚函数,在BpCameraService和CameraService中分别给出了实现,BpCameraService作为代理类,提供接口给客户端。
fnConnectService方法在Camera.cpp作为强引用,指向ICameraService::connect方法。
CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
&ICameraService::connect;
... ...
在ICameraService.cpp的connect方法中,首先将传递过来的Camera对象cameraClient转换成IBinder类型,将调用的参数写到Parcel中,通过BpBinder的transact()函数发送消息,然后由BnCameraService去响应该连接,最后就是等待服务端返回,如果成功则生成一个BpCamera实例。
frameworks/av/camera/ICameraService.cpp
// connect to camera service (android.hardware.Camera)
virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
const String16 &clientPackageName, int clientUid,
/*out*/
sp<ICamera>& device)
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
data.writeStrongBinder(IInterface::asBinder(cameraClient));
data.writeInt32(cameraId);
data.writeString16(clientPackageName);
data.writeInt32(clientUid);
status_t status;
status = remote()->transact(BnCameraService::CONNECT, data, &reply);
//BpBinder的transact()函数向IPCThreadState实例发送消息,通知其有消息要发送给binder driver
if (status != OK) return status;
if (readExceptionCode(reply)) return -EPROTO;
status = reply.readInt32();
if (reply.readInt32() != 0) {
// client端读出server返回的binder
device = interface_cast<ICamera>(reply.readStrongBinder());
}
return status;
}
发送的消息在BnCameraService接收,其中onTransact()函数负责解包收到的Parcel并执行client端的请求的方法。服务端收到CONNECT命令之后,
(1) 使用Camera的Binder对象生成Camera客户代理BpCameraClient实例;
(2) 将生成的BpCameraClient对象作为参数传递到CameraService(/frameworks/av/services/camera/libcameraservice/CameraService.cpp)的connect()函数中,该函数会返回一个BpCamera实例;
(3) 将在(2)中返回的实例对象以IBinder的形式打包到Parcel中返回。
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, /*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::connect()函数,该函数返回一个BpCamera实例。
status_t CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<ICamera>& device) {
ATRACE_CALL();
status_t ret = NO_ERROR;
String8 id = String8::format("%d", cameraId);
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id,
CAMERA_HAL_API_VERSION_UNSPECIFIED,
clientPackageName, clientUid, API_1, 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;
}
可以看到又调用了connectHelper去返回客户端实例。在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();
sp<CLIENT> client = nullptr;
{
// Acquire mServiceLock and prevent other clients from connecting
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;
}
// Enforce client permissions and do basic sanity checks
if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) {
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 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) {
// Handle special case for API1 MediaRecorder where the existing client is returned
device = static_cast<CLIENT*>(clientTmp.get());
return NO_ERROR;
}
// give flashlight a chance to close devices if necessary.
mFlashlight->prepareDeviceOpen(cameraId);
// TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDs
int 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;
if((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__);
if ((ret = client->initialize(mModule)) != OK) {
ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);
return ret;
}
// Update shim paremeters for legacy clients
if (effectiveApiLevel == API_1) {
// Assume we have always received a Client subclass for API1
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) {
// 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
// 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;
}
makeClient方法在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 IDs
int 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) {
// 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<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName, id, facing,
clientPid, clientUid, getpid(), legacyMode);
} else { // Camera2 API route
ALOGW("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 route
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new Camera2Client(cameraService, tmp, packageName, id, facing,
clientPid, clientUid, servicePid, legacyMode);
} else { // Camera2 API route
sp<ICameraDeviceCallbacks> tmp =
static_cast<ICameraDeviceCallbacks*>(cameraCb.get());
*client = new CameraDeviceClient(cameraService, tmp, packageName, id,
facing, clientPid, clientUid, servicePid);
}
break;
default:
// Should not be reachable
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return INVALID_OPERATION;
}
} 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<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName, id, 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 INVALID_OPERATION;
}
}
return NO_ERROR;
}
由此,初始化了服务端的CameraClient实例,之后在客户端的操作都是调用了此实例。这样每一次客户端调用preview/takepicture,就直接调用的是CameraClient中的相关函数。
返回到CameraService::connect()函数中,处理完成之后的client实例赋值给了device,而这个device,就是在客户端CameraBase.cpp中c->mCamera,
status = (cs.get()->fnConnectService)(cl, cameraId, clientPackageName, clientUid,
/out*/ c->mCamera);
这样就真正建立了客户端和服务端的关系。如Camera.cpp中的startPreview
status_t Camera::startPreview()
{
ALOGV("startPreview");
sp <ICamera> c = mCamera;
if (c == 0) return NO_INIT;
return c->startPreview();
}
其实直接就会调用到CameraService中CameraClient.cpp中
status_t CameraClient::startPreview() {
LOG1("startPreview (pid %d)", getCallingPid());
return startCameraMode(CAMERA_PREVIEW_MODE);
}
至此,对于camera的客户端如何连接到server端的已经介绍完毕。
2.4 server端的初始化
camera客户端与服务端的调用关系,就是camera.cpp中的函数,对应到CameraClient中的函数。下面我们再看看CameraClient的初始化过程。
在客户端连接过程中,connectHelper方法里,调用了方法:
if ((ret = client->initialize(mModule)) != OK) {
ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);
return ret;
}
此方法调用了CameraClient的initialize函数:
status_t CameraClient::initialize(CameraModule *module) {
int callingPid = getCallingPid();
status_t res;
// Verify ops permissions
res = startCameraOps();
if (res != OK) {
return res;
}
char camera_device_name[10];
snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
//先实例化camera HAL的CameraHardwareInterface接口
mHardware = new CameraHardwareInterface(camera_device_name);
//调用initialize进入HAL层,打开camera底层驱动
res = mHardware->initialize(module);
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
mHardware.clear();
return res;
}
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)(uintptr_t)mCameraId);
// Enable zoom, error, focus, and metadata messages by default
enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
return OK;
}
在上面的方法中,mHardware->initialize(module)中的module是一个结构体camera_module_t,接下来分析它的初始化过程。
在客户端发起连接的时候,在CameraBase中的connect方法中,调用了getCameraService方法,
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
const String16& clientPackageName,
int clientUid)
{
ALOGV("%s: connect", __FUNCTION__);
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
status_t status = NO_ERROR;
const sp<ICameraService>& cs = getCameraService();
... ...
这个时候初始化了一个CameraService实例,且用Sp包装,这个时候sp将新增计数,相应的CameraService实例里面onFirstRef()函数完成调用。该函数在强引用sp新增引用计数时调用。就是当有sp包装的类初始化的时候调用。
void CameraService::onFirstRef()
{
BnCameraService::onFirstRef();
// Update battery life tracking if service is restarting
BatteryNotifier& notifier(BatteryNotifier::getInstance());
notifier.noteResetCamera();
notifier.noteResetFlashlight();
camera_module_t *rawModule;
int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&rawModule);
mModule = new CameraModule(rawModule);
... ...
CAMERA_HARDWARE_MODULE_ID 获取Camera Hal层的代理stub,并赋值给mModule,后面就可通过操作mModule完成对Camera模块的控制。
至此,服务端的初始化也分析完毕。整个流程的总结如下:
->先是系统注册CameraService的服务
->AP层调用Camera.open()
->Camera.java调用JNI native_setup()
->JNI层调用 android_hardware_Camera_native_setup
-> HAL 客户端(Camera.cpp)调用connect与服务端(CameraService.cpp)连接,并得到CameraService中的CameraClient的一个实例
->服务端CameraClient的初始化,实例化Camera Hal接口 CameraHardwareInterface
->CameraHardwareInterface 打开Camera驱动,初始化完毕
对应的代码层次:
App--->framework-java--->jni--->framework-c++(Camera)--->binder---> framework-c++(CameraService)-->framework-c++(CameraService::Client)---> framework-c++(CameraClient) --->(CameraHardwareInterface) ---> HAL
2.5 HAL层openCamera
首先在CameraService中的onFirstRef()方法里实例化了HAL层的对象,然后调用了相关的方法,下面就从HAL层去分析是如何启动camera的。
mModule = new CameraModule(rawModule);
mNumberOfCameras = mModule->getNumberOfCameras();
可以看出,先是调用了HAL层的getNumberOfCameras()方法,返回支持的摄像头数量。
在HAL层,其调用到了QCamera2Factory.cpp中。在构造函数时调用了get_num_of_cameras()方法,然后getNumberOfCameras()方法返回这个成员变量。
QCamera2Factory::QCamera2Factory()
{
mNumOfCameras = get_num_of_cameras();
}
int QCamera2Factory::getNumberOfCameras()
{
return mNumOfCameras;
}
get_num_of_cameras()方法在mm_camera_interface.c中实现,在while循环中不断访问驱动,然后不满足条件之后跳出循环,返回camera数量。
之后通过HAL开启camera,在HAL层中,具体的实现是在QCamera2HWI.cpp中:
int QCamera2HardwareInterface::openCamera(struct hw_device_t **hw_device)
{
ATRACE_CALL();
int rc = NO_ERROR;
if (!check_cam_access(mCameraId)) {
ALOGE("%s: multiple simultaneous camera instance not supported", __func__);
return -EUSERS;
}
if (mCameraOpened) {
*hw_device = NULL;
return PERMISSION_DENIED;
}
CDBG_HIGH("[KPI Perf] %s: E PROFILE_OPEN_CAMERA camera id %d", __func__,mCameraId);
rc = openCamera();
if (rc == NO_ERROR){
*hw_device = &mCameraDevice.common;
if (m_thermalAdapter.init(this) != 0) {
ALOGE("Init thermal adapter failed");
}
}
else
*hw_device = NULL;
return rc;
}
继续调用openCamera()方法,
int QCamera2HardwareInterface::openCamera()
{
int32_t l_curr_width = 0;
int32_t l_curr_height = 0;
m_max_pic_width = 0;
m_max_pic_height = 0;
char value[PROPERTY_VALUE_MAX];
int enable_4k2k;
size_t i;
if (mCameraHandle) {
ALOGE("Failure: Camera already opened");
return ALREADY_EXISTS;
}
mCameraHandle = camera_open((uint8_t)mCameraId);
... ...
mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle,
camEvtHandle,
(void *) this);
... ...
}
之后调用camera_open方法,此方法在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->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;
}
}
之后继续调用mm_camera_open方法,此方法在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;
int cam_idx = 0;
char t_devname[MM_CAMERA_DEV_NAME_LEN];
const char *temp_dev_name = mm_camera_util_get_dev_name(my_obj->my_hdl);
CDBG("%s: begin\n", __func__);
if (temp_dev_name == NULL) {
CDBG_ERROR("%s: dev name is NULL",__func__);
rc= -1;
goto on_error;
}
strlcpy(t_devname, temp_dev_name, sizeof(t_devname));
snprintf(dev_name, sizeof(dev_name), "/dev/%s",t_devname );
sscanf(dev_name, "/dev/video%d", &cam_idx);
CDBG_ERROR("%s: dev name = %s, cam_idx = %d", __func__, dev_name, cam_idx);
do{
n_try--;
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) || (n_try <= 0 )) {
CDBG_ERROR("%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 * 1000U);
}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;
}
/* open 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 * 1000U);
} 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__);
snprintf(my_obj->evt_thread.threadName, THREAD_NAME_SIZE, "CAM_Dispatch");
mm_camera_cmd_thread_launch(&my_obj->evt_thread,
mm_camera_dispatch_app_event,
(void *)my_obj);
/* launch event poll thread
* we will add evt fd into event poll thread upon user first register for evt */
CDBG("%s : Launch evt Poll Thread in Cam Open", __func__);
snprintf(my_obj->evt_thread.threadName, THREAD_NAME_SIZE, "CAM_Poll");
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);
/* we do not need to unlock cam_lock here before return
* because for open, it's done within intf_lock */
return rc;
on_error:
if (my_obj->ctrl_fd > 0) {
close(my_obj->ctrl_fd);
my_obj->ctrl_fd = 0;
}
if (my_obj->ds_fd > 0) {
mm_camera_socket_close(my_obj->ds_fd);
my_obj->ds_fd = 0;
}
/* we do not need to unlock cam_lock here before return
* because for open, it's done within intf_lock */
return rc;
}
可以看出,在此方法中,打开了视频节点,创建了Socket,Launch相关的线程。
接着,回到QCamera2HWI.cpp中的openCamera()方法中,ops->register_event_notify去调用了mm_camera_interface.c中的方法:
static int32_t mm_camera_intf_register_event_notify(uint32_t camera_handle,
mm_camera_event_notify_t evt_cb,
void * user_data)
{
int32_t rc = -1;
mm_camera_obj_t * my_obj = NULL;
CDBG("%s :E ", __func__);
pthread_mutex_lock(&g_intf_lock);
//获取camera对象
my_obj = mm_camera_util_get_camera_by_handler(camera_handle);
if(my_obj) {
pthread_mutex_lock(&my_obj->cam_lock);
pthread_mutex_unlock(&g_intf_lock);
//真正去注册
rc = mm_camera_register_event_notify(my_obj, evt_cb, user_data);
} else {
pthread_mutex_unlock(&g_intf_lock);
}
CDBG("%s :E rc = %d", __func__, rc);
return rc;
}
可以看出,此方法是注册事件通知的,然后真正实现注册的位置是mm_camera.c中的mm_camera_register_event_notify方法:
int32_t mm_camera_register_event_notify(mm_camera_obj_t *my_obj,
mm_camera_event_notify_t evt_cb,
void * user_data)
{
int rc = -1;
rc = mm_camera_register_event_notify_internal(my_obj,
evt_cb,
user_data);
pthread_mutex_unlock(&my_obj->cam_lock);
return rc;
}
接下来,调用了mm_camera_register_event_notify_internal方法。
int32_t mm_camera_register_event_notify_internal(mm_camera_obj_t *my_obj,
mm_camera_event_notify_t evt_cb,
void * user_data)
{
int i;
int rc = -1;
mm_camera_evt_obj_t *evt_array = NULL;
pthread_mutex_lock(&my_obj->cb_lock);
evt_array = &my_obj->evt;
if(evt_cb) {
/* this is reg case */
for(i = 0; i < MM_CAMERA_EVT_ENTRY_MAX; i++) {
if(evt_array->evt[i].user_data == NULL) {
evt_array->evt[i].evt_cb = evt_cb;
evt_array->evt[i].user_data = user_data;
evt_array->reg_count++;
rc = 0;
break;
}
}
} else {
/* this is unreg case */
for(i = 0; i < MM_CAMERA_EVT_ENTRY_MAX; i++) {
if(evt_array->evt[i].user_data == user_data) {
evt_array->evt[i].evt_cb = NULL;
evt_array->evt[i].user_data = NULL;
evt_array->reg_count--;
rc = 0;
break;
}
}
}
pthread_mutex_unlock(&my_obj->cb_lock);
return rc;
}
此处将事件的回调注册完成。接着回到QCamera2HWI.cpp里,继续初始化、配置相关参数。
至此,打开camera的过程已经分析完成。