Android Camera 采用C/S架构,client 与server两个独立的线程之间(CameraService)使用Binder通信。

一 CameraService的注册。

1.手机开机后,会走init.rc流程,init.rc会启动MediaServer Service。

service media /system/bin/mediaserver
class main
user root ####
# google default ####
# user media ####
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm media sdcard_r system net_bt_stack ####
# google default ####
# group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm #### ioprio rt 4

2.MediaServer的main函数位于frameworks/base/media/mediaserver/main_mediaserver.cpp中。

在Main_MediaServer.cpp的main函数中,CameraService完成了注册

 int main(int argc __unused, char** argv)
{
signal(SIGPIPE, SIG_IGN);
char value[PROPERTY_VALUE_MAX];
bool doLog = (property_get("ro.test_harness", value, "") > ) && (atoi(value) == );
pid_t childPid;
..............................
sp<ProcessState> proc(ProcessState::self());
sp<IServiceManager> sm = defaultServiceManager();
ALOGI("ServiceManager: %p", sm.get());
AudioFlinger::instantiate();
MediaPlayerService::instantiate();
#ifdef MTK_AOSP_ENHANCEMENT
MemoryDumper::instantiate();
#endif
CameraService::instantiate();
......................................

3. instantiate的实现在CameraService的父类中,

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 publishAndJoinThreadPool(bool allowIsolated = false) {
publish(allowIsolated);
joinThreadPool();
} static void instantiate() { publish(); } static status_t shutdown() { return NO_ERROR; } private:
static void joinThreadPool() {
sp<ProcessState> ps(ProcessState::self());
ps->startThreadPool();
ps->giveThreadPoolName();
IPCThreadState::self()->joinThreadPool();
}
}; }; // namespace android

可以发现在publish()函数中,CameraService完成服务的注册 。SERVICE是个模板,这里是注册CameraService,所以可用CameraService代替

return sm->addService(String16(CameraService::getServiceName()), new CameraService());

这样,Camera就在ServiceManager完成服务注册,提供给client随时使用。

二  client如何连上server端,并打开camera模块

1.Client如何连接到server端。

我们从Camera.open()开始往framework进行分析,调用frameworks\base\core\java\android\hardware\Camera.java类的open方法 。

public static Camera open() {
............................................
return new Camera(cameraId);
.............................................
}

这里调用了Camera的构造函数,在构造函数中调用了cameraInitVersion

    private int cameraInitVersion(int cameraId, int halVersion) {
..................................................
return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
}

此后进入JNI层android_hardware_camera.cpp

// connect to camera service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
.......................
camera = Camera::connect(cameraId, clientName,
Camera::USE_CALLING_UID);
...................... sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
...........................
camera->setListener(context);
.......................... }

JNI函数里面,我们找到Camera C/S架构的客户端了(即红色加粗的那个Camera),它调用connect函数向服务端发送连接请求。JNICameraContext这个类是一个监听类,用于处理底层Camera回调函数传来的数据和消息

sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
int clientUid)
{
return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}
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;
const sp<ICameraService>& cs = getCameraService(); if (cs != ) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
/*out*/ c->mCamera);
}
if (status == OK && c->mCamera != ) {
c->mCamera->asBinder()->linkToDeath(c);
c->mStatus = NO_ERROR;
} else {
ALOGW("An error occurred while connecting to camera: %d", cameraId);
c.clear();
}
return c;
}
// establish binder interface to camera service
template <typename TCam, typename TCamTraits>
const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
{
Mutex::Autolock _l(gLock);
if (gCameraService.get() == ) {
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> binder;
do {
binder = sm->getService(String16(kCameraServiceName));
if (binder != ) {
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 == , "no CameraService!?");
return gCameraService;
}

此处终于获得CameraService实例了,该CameraService实例是通过binder获取的。

再来看fnConnectService是什么,

在Camera.cpp中,有

CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
&ICameraService::connect;

这样也就是说fnConnectService就是使用CameraService调用connect,从这里开始,终于从进入了服务端的流程

status_t CameraService::connect(
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<ICamera>& device) { .........................
status_t status = validateConnect(cameraId, /*inout*/clientUid);
.................................. if (!canConnectUnsafe(cameraId, clientPackageName,
cameraClient->asBinder(),
/*out*/clientTmp)) {
return -EBUSY;
} status = connectHelperLocked(/*out*/client,
cameraClient,
cameraId,
clientPackageName,
clientUid,
callingPid);

  device = client;

return OK;
}
status_t CameraService::connectHelperLocked(
/*out*/
sp<Client>& client,
/*in*/
const sp<ICameraClient>& cameraClient,
int cameraId,
const String16& clientPackageName,
int clientUid,
int callingPid,
int halVersion,
bool legacyMode) { ....................................
client = new CameraClient(this, cameraClient,
clientPackageName, cameraId,
facing, callingPid, clientUid, getpid(), legacyMode);
....................................
    status_t status = connectFinishUnsafe(client, client->getRemote());
............................................
}

在connectHelpLocked,CameraService返回一个其实是它内部类的client——CameraClient。(注意此client是CameraService内部的CameraClient,不是Camera客户端),此client还赋值给了device,而这个device,就是在客户端CameraBase.cpp中c->mCamera,

        status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
/*out*/ c->mCamera);

而这个c->mCamera就是每一次客户端Camera.cpp中调用一些函数(如preview/takepicture)时的mCamera,这样每一次客户端调用preview/takepicture,就直接调用的是CameraClient中的相关函数。这样就真正建立了客户端和服务端的关系。如Camera.cpp中的startPreview

// start preview mode
status_t Camera::startPreview()
{
ALOGV("startPreview");
sp <ICamera> c = mCamera;
if (c == ) return NO_INIT;
return c->startPreview();
}

其实直接就会调用到CameraService中CameraClient.cpp中

// start preview mode
status_t CameraClient::startPreview() {
LOG1("startPreview (pid %d)", getCallingPid());
return startCameraMode(CAMERA_PREVIEW_MODE);
}

2.service端(其实就是CameraClient)的初始化和运行过程。

刚才我们知道,camera客户端与服务端的调用关系,就是camera.cpp中的函数,对应到CameraClient中的函数。下面我们再看看CameraClient的初始化过程。

在connectFinishUnsafe中,

    status_t status = client->initialize(mModule);

我们再来看CameraClient类的initialize函数

status_t CameraClient::initialize(camera_module_t *module) {
int callingPid = getCallingPid();
status_t res; mHardware = new CameraHardwareInterface(camera_device_name);
res = mHardware->initialize(&module->common); }

CameraClient的初始化就是:先实例化Camera Hal接口 CameraHardwareInterface,CameraHardwareInterface调用initialize()进入HAL层打开Camera底层驱动

    status_t initialize(hw_module_t *module)
{
ALOGI("Opening camera %s", mName.string());
camera_module_t *cameraModule = reinterpret_cast<camera_module_t *>(module);
camera_info info;
status_t res = cameraModule->get_camera_info(atoi(mName.string()), &info);
if (res != OK) return res; int rc = OK;
if (module->module_api_version >= CAMERA_MODULE_API_VERSION_2_3 &&
info.device_version > CAMERA_DEVICE_API_VERSION_1_0) {
// Open higher version camera device as HAL1.0 device.
rc = cameraModule->open_legacy(module, mName.string(),
CAMERA_DEVICE_API_VERSION_1_0,
(hw_device_t **)&mDevice);
} else {
rc = CameraService::filterOpenErrorCode(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;
}

hardware->initialize(&mModule->common)中mModule模块是一个结构体camera_module_t,他是怎么初始化的呢?我们发现CameraService里面有个函数

void CameraService::onFirstRef()
{
BnCameraService::onFirstRef(); if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
(const hw_module_t **)&mModule) < ) {
LOGE("Could not load camera HAL module");
mNumberOfCameras = ;
} }

了解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()即实例化CameraClient并打开驱动,返回CameraClient的时候,就表明客户端和服务端连接建立。Camera完成初始化。

总结: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驱动,初始化完毕

最终的结果就是客户端会得到一个服务端CameraService中的CameraClient的一个实例,客户端的每一个函数操作其实最终都是调用CameraClient的函数

参考文档:

Android 4.0 Camera架构分析之Camera初始化 http://blog.csdn.net/dnfchan/article/details/7594590

Android 5.1 Camera Framework源码

Android 5.1 Camera 架构学习之Camera初始化的更多相关文章

  1. Android 4.0 Camera架构分析之Camera初始化

    Android Camera 采用C/S架构,client 与server两个独立的线程之间使用Binder通信,这已经是众所周知的了.这里将介绍Camera从设备开机,到进入相机应用是如何完成初始化 ...

  2. sc7731 Android 5.1 Camera 学习之一Camera 两个对象

    众所周知,在Android中Camera采用了C/S架构,其中Camera server 与 Camera client之间通过Android Binder IPC机制进行通信.在Camera实现的框 ...

  3. Android 的Camera架构介绍

    http://java-admin.iteye.com/blog/452464   第一部分 Camera概述Android的Camera包含取景器(viewfinder)和拍摄照片的功能.目前And ...

  4. Andriod4.2 Camera 架构与实现

    1.Camera架构包括客户端和服务端,他们之间的通信采用Binder机制实现. Camera的实现主要包括本地代码和Java代码两个层次: Camera本地框架: frameworks/native ...

  5. Android4.0 Camera架构初始化流程【转】

    本文转载自:http://blog.chinaunix.net/uid-2630593-id-3307176.html Android Camera 采用C/S架构,client 与server两个独 ...

  6. 一样的Android,不一样的学习

    这几年,Android开始慢慢流行起来,很多项目也开始涉及这部分内容,所以学习Android也就变的很有意义了. 学什么 学习Android应该学什么,很多人有不同的见解.一般程序员可能只是学习And ...

  7. ZT Android4.2蓝牙基础架构学习

    Android4.2蓝牙基础架构学习 分类: Jellybean Bluetooth Bluetooth 2013-10-13 23:58 863人阅读 评论(3) 收藏 举报 androidblue ...

  8. MVP架构学习

    MVP架构学习 M:数据层(数据库,文件,网络等...) V:UI层(Activity,Fragment,View以及子类,Adapter以及子类) P:中介,关联UI层和数据层,因为V和M是相互看不 ...

  9. Android开发-浅谈架构(二)

    写在前面的话 我记得有一期罗胖的<罗辑思维>中他提到 我们在这个碎片化 充满焦虑的时代该怎么学习--用30%的时间 了解70%该领域的知识然后迅速转移芳草鲜美的地方 像游牧民族那样.原话应 ...

随机推荐

  1. Ubuntu16.04下编译vim with python support失败的原因

    - youcompleteme原话:On Ubuntu 16.04, Python support was not working due to enabling both Python2 and P ...

  2. 模拟DOMContentLoaded事件

    window.onload事件 文档中所有图片,脚本,链接以及子框完成加载后,才会触发window.onload事件. 浏览器兼容性:All DOMContentLoaded事件 当页面中的文档树解析 ...

  3. JS操作性能优化

    1. 适当使用变量 Maybe document.getElementById("myField").style.backgroundColor = "#CCC" ...

  4. BZOJ 1688: Disease Manangement (子集枚举)

    Disease Manangement Q - 枚举子集 Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d &a ...

  5. 读取pdf文件 .选择了itextsharp 库

    此库还是比较成熟.看博客园很多文章都介绍了此库 用法 如果项目用到读取pdf.  我这只是提供个思路.或者提供个方法.用itextsharp 能方便实现 StringBuilder text = ne ...

  6. 关于如何在C语言中嵌入汇编命令

    转载自:http://www.keil.com/support/docs/2308.htm C51: GETTING INLINE ASSEMBLY TO WORK Information in th ...

  7. 启动Activity但不显示其界面

    最近在工作中做了一个很简单的任务,制作一个apk,点击该app链接到某一个网站.     代码很简单,只有如寥寥几行: (browser.java) package com.test.browser; ...

  8. Android 有趣味的GridView

    工作这么久以来,都是以解决需求为目标.渐渐发现这种学习方式不好,学到的知识能马上解决问题,但没有经过梳理归纳.故想系统总结下一些有趣味的知识点.在这篇博客中想以一个例子系统讲解下GridView控件涉 ...

  9. linux crontab 计划任务 atd和windows下的计划任务

    crontab 命令 如果发现您的系统里没有这个命令,请安装下面两个软件包. vixie-cron crontabs crontab 是用来让使用者在固定时间或固定间隔执行程序之用,换句话说,也就是类 ...

  10. COJN 0585 800604鸡蛋的硬度

    800604鸡蛋的硬度 难度级别:B: 运行时间限制:1000ms: 运行空间限制:51200KB: 代码长度限制:2000000B 试题描述 最近XX公司举办了一个奇怪的比赛:鸡蛋硬度之王争霸赛.参 ...