高通平台Camera框架部分浅谈--Camera C/S 的init流程
了解的不够深入,应用功能实现后,再回头细看Camera框架时,还是有些地方没能连通,在网上也找了一些文章结合代码来分析,不过能力有限,甚是痛苦。而且由于平台不同,代码的具体流程还是有区别。
下面所解内容的是基于高通8916平台,也不知道能不能描述清楚,我尽力吧!
(参考的博文,楼主讲的很好,只是平台不同,有些地方的调用位置不同。http://blog.chinaunix.net/uid-2630593-id-3307176.html)
Camera C/S 的init过程
我们在上层应用,需要用到Camera时,打开Camera时调用的是Camera.open(i)函数,这个函数是由Camera.java给我们提供的接口。
下面要介绍的,是Camera的服务是如何注册,和Camera客户端是如何获得系统提供的服务,实现打开Camera的过程。
先贴出Client端调用的大致流程图,图片有点模糊。
调用的相关文件有 CameraActivity.java(上层应用) ---> Camera.java ---> android_android_Camera.java (JNI) ---> Camera.java ---> CameraBase.cpp ---> ServiceManaager.java ---> CameraService.cpp ---> CameraClient.cpp ---> CameraHardwareInterface.cpp(HWI调用接口)
1、Camera 服务端的创建和注册
和Camera服务的注册相关的文件是Main_MediaServer.cpp,我们看到在该文件的main函数中 有个 CameraService::instantiate(); 再看instantiate()函数的真正实现是在BinderService.h 文件中,而真正相关的函数是BinService.h 中的publish()函数,在public()函数中,通过 addService( .....)方法添加相应的服务,而添加的该服务是由CameraService.h 的getServiceName(...)返回。
这样,Camera服务就完成了在ServiceManager中的注册,提供给Client随时调用。
Main_MediaServer.cpp
int main(int argc, char** argv)
{
signal(SIGPIPE, SIG_IGN);
char value[PROPERTY_VALUE_MAX];
bool doLog = (property_get("ro.test_harness", value, "0") > 0) && (atoi(value) == 1);
pid_t childPid;
// FIXME The advantage of making the process containing media.log service the parent process of
// the process that contains all the other real services, is that it allows us to collect more
// detailed information such as signal numbers, stop and continue, resource usage, etc.
// But it is also more complex. Consider replacing this by independent processes, and using
// binder on death notification instead.
if (doLog && (childPid = fork()) != 0) {
// media.log service
//prctl(PR_SET_NAME, (unsigned long) "media.log", 0, 0, 0);
// unfortunately ps ignores PR_SET_NAME for the main thread, so use this ugly hack
strcpy(argv[0], "media.log");
sp<ProcessState> proc(ProcessState::self());
MediaLogService::instantiate();
ProcessState::self()->startThreadPool();
for (;;) {
siginfo_t info;
int ret = waitid(P_PID, childPid, &info, WEXITED | WSTOPPED | WCONTINUED);
if (ret == EINTR) {
continue;
}
if (ret < 0) {
break;
}
char buffer[32];
const char *code;
switch (info.si_code) {
case CLD_EXITED:
code = "CLD_EXITED";
break;
case CLD_KILLED:
code = "CLD_KILLED";
break;
case CLD_DUMPED:
code = "CLD_DUMPED";
break;
case CLD_STOPPED:
code = "CLD_STOPPED";
break;
case CLD_TRAPPED:
code = "CLD_TRAPPED";
break;
case CLD_CONTINUED:
code = "CLD_CONTINUED";
break;
default:
snprintf(buffer, sizeof(buffer), "unknown (%d)", info.si_code);
code = buffer;
break;
}
struct rusage usage;
getrusage(RUSAGE_CHILDREN, &usage);
ALOG(LOG_ERROR, "media.log", "pid %d status %d code %s user %ld.%03lds sys %ld.%03lds",
info.si_pid, info.si_status, code,
usage.ru_utime.tv_sec, usage.ru_utime.tv_usec / 1000,
usage.ru_stime.tv_sec, usage.ru_stime.tv_usec / 1000);
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder = sm->getService(String16("media.log"));
if (binder != 0) {
Vector<String16> args;
binder->dump(-1, args);
}
switch (info.si_code) {
case CLD_EXITED:
case CLD_KILLED:
case CLD_DUMPED: {
ALOG(LOG_INFO, "media.log", "exiting");
_exit(0);
// not reached
}
default:
break;
}
}
} else {
// all other services
if (doLog) {
prctl(PR_SET_PDEATHSIG, SIGKILL); // if parent media.log dies before me, kill me also
setpgid(0, 0); // but if I die first, don't kill my parent
}
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
CameraService::instantiate();
#ifdef AUDIO_LISTEN_ENABLED
ALOGI("ListenService instantiated");
ListenService::instantiate();
#endif
AudioPolicyService::instantiate();
registerExtensions();
ProcessState::self()->startThreadPool();
IPCThreadState::self()->joinThreadPool();
}
}
BinderService.h
static voidinstantiate() { publish(); }
static status_t publish(bool allowIsolated = false) {
sp<IServiceManager> sm(defaultServiceManager());
return sm->addService(
String16(SERVICE::getServiceName()),
new SERVICE(), allowIsolated);
}
CameraService.h
// Implementation of BinderService<T>
static char const* getServiceName() { return "media.camera"; }
2、Camera 客户端获取服务
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
我们在上层应用打开Camera时,是直接调用 Camera.java 函数给我们提供的open(id)函数,在Camera.java的open(...)函数中会new 一个Camera对象,在Camera(...)中 调用了native_setup(...)函数,我们看下native_setup(...)的声明,就知道是个本地的native方法,所以该函数真正的实现是在JNI层的android_hardware_Camera.cpp 文件中。
Camera.java
public static Camera open(int cameraId) {
return new Camera(cameraId);
}
Camera(int cameraId) {
mShutterCallback = null;
mRawImageCallback = null;
mJpegCallback = null;
mPreviewCallback = null;
mPostviewCallback = null;
mUsingPreviewAllocation = false;
mZoomListener = null;
/* ### QC ADD-ONS: START */
mCameraDataCallback = null;
mCameraMetaDataCallback = null;
/* ### QC ADD-ONS: END */
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.currentPackageName();
native_setup(new WeakReference<Camera>(this), cameraId, packageName);
}
private native final void native_setup(Object camera_this, int cameraId,
String packageName);
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Camera的JNI层文件,android_hardware_Camera.cpp 。我们看在这个文件中,native_setup 函数的映射,相对应的函数是android_hardware_Camera_native_setup(...);
在android_hardware_Camera_native_setup函数中是调用了Camera::connect(...)方法,这个直接调用的就是Camera.cpp 文件中的connect(...)方法。
android_hardware_camera.cpp
{ "native_setup",
"(Ljava/lang/Object;ILjava/lang/String;)V",
(void*)android_hardware_Camera_native_setup },
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jstring clientPackageName)
{
// Convert jstring to String16
const char16_t *rawClientName = env->GetStringChars(clientPackageName, NULL);
jsize rawClientNameLen = env->GetStringLength(clientPackageName);
String16 clientName(rawClientName, rawClientNameLen);
env->ReleaseStringChars(clientPackageName, rawClientName);
sp<Camera> 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->SetIntField(thiz, fields.context, (int)context.get());
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
我们看到在Camera.cpp文件的connect方法,真正调用的是CameraBase.cpp中的connect方法。
Camera.cpp
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
int clientUid)
{
return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
在CameraBase.cpp 的connect方法中,通过getCameraService()函数去获取服务,因为Camera Client和Service是通过binder机制来进行通信,所以在该connect方法中的(cs.get()->*fnConnectService)其实是直接执行CameraService中的connect方法。
CameraBase.cpp
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();
if (cs != 0) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
/*out*/ c->mCamera);
}
if (status == OK && c->mCamera != 0) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
ALOGW("An error occurred while connecting to camera: %d", cameraId);
c.clear();
}
return c;
}
const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
Mutex::Autolock _l(gLock);
if (gCameraService.get() == 0) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
// const char* kCameraServiceName = "media.camera";
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);
gCameraService = interface_cast<ICameraService>(binder);
}
ALOGE_IF(gCameraService == 0, "no CameraService!?");
return gCameraService;
}
ServiceManmager.java
public static IBinder getService(String name) {
try {
IBinder service = sCache.get(name);
if (service != null) {
return service;
} else {
return getIServiceManager().getService(name);
}
} catch (RemoteException e) {
Log.e(TAG, "error in getService", e);
}
return null;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (直接粘贴下参考博文的描述,我的能力有限,楼主描述的很好了)
可以看出,该CameraService实例是通过binder获取的,由binder机制可以知道,该服务就是CameraService一个实例。
(cs.get()->*fnConnectService)
然后执行服务端的connect()函数,并返回一个ICamera对象赋值给Camera 的mCamera, 服务端connect()返回的其实是它内部类client的一个实例。
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
由上面的描述,我们知道Client通过binder获得了一个CameraService的实例,而又由于binder机制,Clinet端通过(cs.get()->*fnConnectService)是直接调用到了CameraService.cpp 文件中的connect方法。我们分析 CameraService.cpp 的connect方法,会知道它会有自己内部的client,并最终会将其内部的client对象返回。
在该CammeraService.cpp 的connect方法中会调用 到connectFinishUnsafe(),去实现调用hal层接口,初始化一些参数。
CameraService.cpp
status_t CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<ICamera>& device) {
String8 clientName8(clientPackageName);
int callingPid = getCallingPid();
LOG1("CameraService::connect E (pid %d \"%s\", id %d)", callingPid,
clientName8.string(), cameraId);
status_t status = validateConnect(cameraId, /*inout*/clientUid);
if (status != OK) {
return status;
}
sp<Client> client;
{
sp<BasicClient> clientTmp;
Mutex::Autolock lock(mServiceLock);
if (!canConnectUnsafe(cameraId, clientPackageName,
cameraClient->asBinder(),
/*out*/clientTmp)) {
return -EBUSY;
} else if (client.get() != NULL) {
device = static_cast<Client*>(clientTmp.get());
return OK;
}
int facing = -1;
int deviceVersion = getDeviceVersion(cameraId, &facing);
// If there are other non-exclusive users of the camera,
// this will tear them down before we can reuse the camera
if (isValidCameraId(cameraId)) {
// transition from PRESENT -> NOT_AVAILABLE
updateStatus(ICameraServiceListener::STATUS_NOT_AVAILABLE,
cameraId);
}
switch(deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid());
break;
case CAMERA_DEVICE_API_VERSION_2_0:
case CAMERA_DEVICE_API_VERSION_2_1:
case CAMERA_DEVICE_API_VERSION_3_0:
client = new Camera2Client(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid(),
deviceVersion);
break;
case -1:
ALOGE("Invalid camera id %d", cameraId);
return BAD_VALUE;
default:
ALOGE("Unknown camera device HAL version: %d", deviceVersion);
return INVALID_OPERATION;
}
status_t status = connectFinishUnsafe(client, client->getRemote());
if (status != OK) {
// this is probably not recoverable.. maybe the client can try again
// OK: we can only get here if we were originally in PRESENT state
updateStatus(ICameraServiceListener::STATUS_PRESENT, cameraId);
return status;
}
mClient[cameraId] = client;
LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId,
getpid());
}
// 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 OK;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
在connectFinishUnsafe函数中,会去init 一个module,会直接调用到CameraClient.cpp 文件中的initialize函数。
status_t CameraService::connectFinishUnsafe(const sp<BasicClient>& client,
const sp<IBinder>& remoteCallback) {
status_t status = client->initialize(mModule);
if (status != OK) {
return status;
}
remoteCallback->linkToDeath(this);
return OK;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
在CameraClient.cpp 中是 new了一个CameraHardwareInterface对象,并调用该对象的initialize方法。以及callback的设置。
CameraClient.cpp
status_t CameraClient::initialize(camera_module_t *module) {
int callingPid = getCallingPid();
status_t res;
LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
// 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);
mHardware = new CameraHardwareInterface(camera_device_name);
res = mHardware->initialize(&module->common);
if (res != OK) {
ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
mHardware.clear();
return NO_INIT;
}
mHardware->setCallbacks(notifyCallback,
dataCallback,
dataCallbackTimestamp,
(void *)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);
LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);
return OK;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
为了屏蔽各硬件的差异,系统为我们封装了调用底层Camera接口的函数,就是 CameraHardwareInterface.h
在该文件的initialize方法中,我们看到 会通过 module->methods->open(),去实现Camera驱动设备节点的打开。
CameraHardwareInterface.h
status_t initialize(hw_module_t *module)
{
ALOGD("Opening camera %s", mName.string());
int rc = module->methods->open(module, mName.string(),
(hw_device_t **)&mDevice);
if (rc != OK) {
ALOGE("Could not open camera %s: %d", mName.string(), rc);
return rc;
}
initHalPreviewWindow();
return rc;
}
>>>>>>>>>>>>>>>>>>>>>>>>>>>>> (下面这段是参考博文的原文,粘贴下,其实我还不是很理解,有时间再看下)
void CameraService::onFirstRef()
{
LOG1("CameraService::onFirstRef");
BnCameraService::onFirstRef();
if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&mModule) < 0) {
ALOGE("Could not load camera HAL module");
mNumberOfCameras = 0;
}
else {
ALOGI("Loaded \"%s\" camera module", mModule->common.name);
mNumberOfCameras = mModule->get_number_of_cameras();
if (mNumberOfCameras > MAX_CAMERAS) {
ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
mNumberOfCameras, MAX_CAMERAS);
mNumberOfCameras = MAX_CAMERAS;
}
for (int i = 0; i < mNumberOfCameras; i++) {
setCameraFree(i);
}
if (mModule->common.module_api_version >=
CAMERA_MODULE_API_VERSION_2_1) {
mModule->set_callbacks(this);
}
CameraDeviceFactory::registerService(this);
}
}
了解HAL层的都知道hw_get_module函数就是用来获取模块的Hal stub,这里是通过CAMERA_HARDWARE_MODULE_ID 获取Camera Hal层的代理stub,并赋值给mModule,后面就可通过操作mModule完成对Camera模块的控制。那么onFirstRef()函数又是何时调用的?
onFirstRef()属于其父类RefBase,该函数在强引用sp新增引用计数时调用,什么意思?就是当 有sp包装的类初始化的时候调用,那么camera是何时调用的呢?可以发现在
客户端发起连接时候
sp Camera::connect(int cameraId)
{
LOGV("connect");
sp c = new Camera();
const sp& cs = getCameraService();
}
这个时候初始化了一个CameraService实例,且用Sp包装,这个时候sp将新增计数,相应的CameraService实例里面onFirstRef()函数完成调用。
CameraService::connect()返回client的时候,就表明客户端和服务端连接建立。Camera完成初始化,可以进行拍照和preview等动作。
写在后面
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
哒哒哒,不知不觉,好像整个过程也梳理了一遍,还是蛮有收获的。
结合源码和参考博文来看,真的对自己的帮助很大。
最开始,我也不相信自己会写完,不过最后好像还好。能力有限,有些地方可能表达有误,另外,再次说明,平台不同,相应的代码的调用位置也可能不同,不过大体的流程是一样的。
最后最后的总结
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
刚开始接触一个新的知识时,总会去查找一些资料,然后又很希望很希望能找到那种通过很俗、很易懂的表达方式,又或者说很口语话的方法,来将一些东西将尽可能讲明白的文章。
后来又发现,其实别人讲的再通俗易懂,如果自己没有去跟读代码,没有去用自己的思路、自己的语言去总结,恐怕效果也会不好。
总的来说,整篇文章的思路就是,在系统启动的时候,会去注册和启动 Camera服务,Camera服务注册完成后,我们就可以随时去调用这个服务,让这个服务帮助我们去实现我们想要的功能(比如打开camera、预览......)