Android Camera调用流程
发布日期:2021-06-30 18:53:43 浏览次数:3 分类:技术文章

本文共 16993 字,大约阅读时间需要 56 分钟。

一个流程图画的非常好的文章

1、Packages/apps/到framework 打开Camera

  1. ./packages/apps/Camera/src/com/android/camera/Camera.java

进来第一个肯定是onCreate(Bundle icicle) {

这里是开始了一个Camera的线程

//start camera opening processmCameraStartUpThread = new CameraStartUpThread();CameraStarUpThread是一个类
/// M: open camera process functions @{
private class CameraStartUpThread extends Thread {
//上面的注释就写着open camera process functions 打开相机进程的函数 Util.openCamera(Camera.this, isPIPMode(getCurrentMode())); //这一句就是用Util这个类来打开相机进程了
./packages/apps/Camera/src/com/android/camera/Util.java//这里面还有打开摄像头的函数openCamerapublic static void openCamera(Activity activity, boolean isPIP)            throws CameraHardwareException, CameraDisabledException {        Log.i(TAG,"openCamera begin isPIP = " + isPIP);        // Check if device policy has disabled the camera.        DevicePolicyManager dpm = (DevicePolicyManager) activity.getSystemService(                Context.DEVICE_POLICY_SERVICE);        if (dpm.getCameraDisabled(null)) {            throw new CameraDisabledException();        }        if (isPIP) {            retryOpen(activity, OPEN_RETRY_COUNT, CameraHolder.instance().getBackCameraId());            retryOpen(activity, OPEN_RETRY_COUNT, CameraHolder.instance().getFrontCameraId());        } else {            int currentCameraId = ((com.android.camera.Camera)activity).getCameraId();            retryOpen(activity, OPEN_RETRY_COUNT, currentCameraId);        }        Log.i(TAG,"openCamera end");    }    //这里面又会调用一个retryOpen函数    private static CameraManager.CameraProxy retryOpen(Activity activity, int count, int cameraId)     //这个函数最终会调用open函数来打开摄像头    try {                if (activity instanceof ActivityBase) {                    CameraProxy cameraProxy = CameraHolder.instance().open(cameraId);                    return cameraProxy;                } else {                    return CameraHolder.instance().open(cameraId);                }     ........     }

2. 这里面的CameraHolder.instance().open调用了下面的open函数

./packages/apps/Camera/src/com/android/camera/CameraHolder.java

public CameraProxy open(int cameraId)            throws CameraHardwareException {        Log.i(TAG, "CameraHolder open cameraId = " + cameraId);        assertError(cameraId != UNKONW_ID);        if (mMockCameraInfo == null) {           //这里又有一个open函数           return getCameraProxyWrapper(cameraId).open();        } else {            if (mMockCamera == null) {                throw new RuntimeException();            }            getCameraProxyWrapper(cameraId).insertMockCameraProxy(mMockCamera[cameraId]);            return mMockCamera[cameraId];        }    }    public synchronized CameraProxy open()                throws CameraHardwareException {            Log.i(TAG, "CameraProxyWrapper open mCameraOpened = " + mCameraOpened + " mCameraId = " + mCameraId);            assertError(!mCameraOpened);            if (mCameraProxy == null) {                try {                    Log.i(TAG, "open camera " + mCameraId);                    mCameraProxy = mCameraManager.cameraOpen(mCameraId);                    //现在又跑到一个mCameraManager.cameraOpen里面来了//看一下下面这个函数,这个函数就是app里面最终调用到framework里面的接口// Open camera synchronously. This method is invoked in the context of a    // background thread.    CameraProxy cameraOpen(int cameraId) {        // Cannot open camera in mCameraHandler, otherwise all camera events        // will be routed to mCameraHandler looper, which in turn will call        // event handler like Camera.onFaceDetection, which in turn will modify        // UI and cause exception like this:        // CalledFromWrongThreadException: Only the original thread that created        // a view hierarchy can touch its views.        MMProfileManager.startProfileCameraOpen();        mCamera = FrameworksClassFactory.openCamera(cameraId);        MMProfileManager.stopProfileCameraOpen();        if (mCamera != null) {            mParametersIsDirty = true;            if (mParamsToSet == null) {                mParamsToSet = mCamera.getParameters();            }            mCameraProxy = new CameraProxy();            return mCameraProxy;        } else {            return null;        }        //./packages/apps/Camera/src/com/mediatek/camera/FrameworksClassFactory.java        //代码的路径 camera.open这里就是跑到framework里面去了        public static ICamera openCamera(int cameraId) {        if (MOCK_CAMERA) {            return MockCamera.open(cameraId);        } else {            Camera camera = Camera.open(cameraId);            if (null == camera) {                Log.e(TAG, "openCamera:got null hardware camera!");                return null;            }            // wrap it with ICamera            return new AndroidCamera(camera);        }    }

2、Framework open到jni调用流程

  1. 还是open这个接口

代码路径:./frameworks/base/core/java/android/hardware/Camera.java

public static Camera open(int cameraId) {        if (!isPermissionGranted()) {            return null;        }        return new Camera(cameraId);    }//这里的return new Camera就是在下面进行了初始化//填充一些参数    Camera(int cameraId) {        mShutterCallback = null;        mRawImageCallback = null;        mJpegCallback = null;        mPreviewCallback = null;        mPreviewRawDumpCallback = null;        mPostviewCallback = null;        mUsingPreviewAllocation = false;        mZoomListener = null;        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
(this), cameraId, packageName); } //这个native_setup就是打开摄像头的关键了
  1. jni的调用接口
    看到这个native 函数说明这个函数是在jni接口,用的是c++代码实现的,so,我们继续找
    private native final void native_setup(Object camera_this, int cameraId,
    终于我们在./frameworks/base/core/jni/android_hardware_Camera.cpp
    这里面找到了这个函数,然后我们看一下这个函数
static JNINativeMethod camMethods[] = {  { "getNumberOfCameras",    "()I",    (void *)android_hardware_Camera_getNumberOfCameras },  { "_getCameraInfo",    "(ILandroid/hardware/Camera$CameraInfo;)V",    (void*)android_hardware_Camera_getCameraInfo },  { "native_setup",    "(Ljava/lang/Object;ILjava/lang/String;)V",    (void*)android_hardware_Camera_native_setup },  //从这里可以看出来,实现这个函数的真正函数是android_hardware_Camera_native_setup  //所以我们继续找一下这个函数在哪里  { "native_release",    "()V",

3. 下面就是打开摄像头的jni代码,app调用open的时候就会调用到这个位置

// connect to camera servicestatic 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::connect(cameraId, clientName, Camera::USE_CALLING_UID);//不相关的代码就不加进来了//sp
camera = Camera::connect(cameraId, clientName,//这句代码应该是从camera jni连接到camera client的关键 上面有个clientName也说明了这点 .......}

3、Android camera Client和camera service调用流程

我只知道spCamera>是一个强指针引用,具体是多厉害百度一下更好

从client的代码里面 
frameworks/av/camera/Camera.cpp

sp
Camera::connect(int cameraId, const String16& clientPackageName, int clientUid){ return CameraBaseT::connect(cameraId, clientPackageName, clientUid); //CameraBaseT::connect这个又是从哪里来的,而且都是c++这可是难倒了我 //不太好办}//在./frameworks/av/include/camera/CameraBase.h:113: //typedef CameraBase
CameraBaseT;//里面有一个typedef 好了,那我们下一句就应该去找CameraBase
这个东西//找到在这个位置//./frameworks/av/camera/CameraBase.cpp:94:sp
CameraBase
::connect(int cameraId,sp
CameraBase
::connect(int cameraId, const String16& clientPackageName, int clientUid){ ALOGV("%s: connect", __FUNCTION__); sp
c = new TCam(cameraId); sp
cl = c; status_t status = NO_ERROR; //下一步就应该到getCameraService这里来了 //这时候我们就要到cameraservice.java里面去看代码了 const sp
& 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;}

为了查看它的调用流程,我加了一点日志在connect函数里面,加的日志代码如下

template 
sp
CameraBase
::connect(int cameraId, const String16& clientPackageName, int clientUid){ ALOGD("%s: weiqifa connect 23", __FUNCTION__); sp
c = new TCam(cameraId); sp
cl = c; status_t status = NO_ERROR; const sp
& cs = getCameraService(); if (cs != 0) { TCamConnectService fnConnectService = TCamTraits::fnConnectService; status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, /*out*/ c->mCamera); ALOGD("%s: weiqifa connect 234", __FUNCTION__); //ALOGD("cs.get()->*fnConnectService %s: weiqifawe", *(cs.get()->*fnConnectService)); } 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;}

这里写图片描述

我们可以看到CameraBase: connect: weiqifa connect 234这句话已经打印出来了
然后我们也可以看到CameraService::connect X 打印出来了
然后我们也可以看到CameraClient: CameraClient::initialize X这个也打印出来了
上面的三个日志还是非常重要的

看一下cameraservice.cpp的connect函数,service是服务端,client是客户端,那么客户端的实现在服务端应该有一个对应的函数

status_t CameraService::connect(        const sp
& cameraClient, int cameraId, const String16& clientPackageName, int clientUid, ..... switch(deviceVersion) { case CAMERA_DEVICE_API_VERSION_1_0: client = new CameraClient(this, cameraClient, //new CameraClient 这个new了一个这个东西,那么CameraClient里面的东西就会被调用了 clientPackageName, cameraId, facing, callingPid, clientUid, getpid());
./frameworks/av/services/camera/libcameraservice/api1/CameraClient.cpp:73:status_t CameraClient::initialize(camera_module_t *module) {    int callingPid = getCallingPid();    status_t res;   //    //看到这里的时候我突然看到了open的函数    //但是有个问题很奇怪这个函数是谁调用了呢?谁让他运行的??????    LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);    res = mHardware->initialize(&module->common);    //这句还是比较关键的mHardware->initialize就是要获取硬件设备的一些东东啊    //......        LOG1("CameraClient::initialize X (pid %d, id %d)", callingPid, mCameraId);    return OK;

./frameworks/av/services/camera/libcameraservice/device1/CameraHardwareInterface.h

status_t initialize(hw_module_t *module)    {        ALOGI("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;    }    //日志里面也有这样的打印    01-01 22:23:00.999868   191   748 I CameraClient: Opening camera 0

我们下一步就是要去找到hw_module_t这个结构体,找到了这个结构体就可以往下走

libcameraservice.so里面调用

void CameraService::onFirstRef(){    LOG1("CameraService::onFirstRef weiqifa");    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++) {
for (int i = 0; i < MAX_CAMERAS; i++) { // workaround for MATV LOG1("setCameraFree(%d)", i); setCameraFree(i); } if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_1) { mModule->set_callbacks(this); } CameraDeviceFactory::registerService(this); }}

hw_get_module(CAMERA_HARDWARE_MODULE_ID这个是加载硬件hardware层对应的东东,具体可以查看链接

看一下CAMERA_HARDWARE_MODULE_ID

hardware/libhardware/include/hardware/camera_common.h:35:#define CAMERA_HARDWARE_MODULE_ID "camera"

看一下我们打印出来的日志

weiqifa@weiqifa-Inspiron-3847:~/weiqifa/log$ grep -wrn "CameraService::onFirstRef" ././mobilelog/APLog_2010_0105_214945/main_log.boot:922:01-05 22:49:08.208839   194   194 D CameraService: CameraService::onFirstRef weiqifaweiqifa@weiqifa-Inspiron-3847:~/weiqifa/log$

4、Android camera Hardware调用

hardware肯定是属于平台的特性,所以我们这里就要找到平台特性的东西了。

从libcameraservice下来

if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,                (const hw_module_t **)&mModule) < 0) {        ALOGE("Could not load camera HAL module");        mNumberOfCameras = 0;    }

hw_get_module这个东西就是获取hardware下面的内容的东西。具体的可以看一下链接

然后我们就找到了这个地方
./mediatek/hardware/mtkcam/module/module.h

staticcamera_moduleget_camera_module(){    camera_module module = {        common: {             tag:                   HARDWARE_MODULE_TAG,              module_api_version:    CAMERA_MODULE_API_VERSION_2_1,              hal_api_version:       HARDWARE_HAL_API_VERSION,              id:                    CAMERA_HARDWARE_MODULE_ID,              name:                  "MediaTek Camera Module",              author:                "MediaTek",              methods:               get_module_methods(),              dso:                   NULL,              reserved:              {
0}, }, get_number_of_cameras: get_number_of_cameras, get_camera_info: get_camera_info, set_callbacks: set_callbacks, }; return module;}

里面的methods: get_module_methods()这个就是我们hardware的open函数

open_device(hw_module_t const* module, const char* name, hw_device_t** device){    return  NSCam::getCamDeviceManager()->open(module, name, device);}statichw_module_methods_t*get_module_methods(){    static    hw_module_methods_t    _methods =    {        open: open_device    };    return  &_methods;}

open_device就会找到NScam::getCamDeviceManager()->open

NSCam这个是一个命名空间,我看了网上的解释,更像是类引用,后面我再跟进去找到open的地方

./mediatek/hardware/mtkcam/devicemgr/CamDeviceManagerBase.cpp

status_tCamDeviceManagerBase::open(    hw_module_t const* module,     char const* name,     hw_device_t** device){    RWLock::AutoWLock _l(mRWLock);    //    return  openDeviceLocked(module, name, device);}

这里调用到了openDeviceLocked 我们找到这个地方

./mediatek/hardware/mtkcam/devicemgr/CamDeviceManagerBase.openDevice.cpp

/****************************************************************************** * ******************************************************************************/status_tCamDeviceManagerBase::openDeviceLocked(    hw_module_t const* module,     char const* name,     hw_device_t** device){    status_t status = OK;    sp
pDevice = NULL; int32_t const i4OpenId = (name != NULL) ? ::atoi(name) : -1; // String8 const s8ClientAppMode = queryClientAppMode(); uint32_t const version = determineOpenDeviceVersionLocked(s8ClientAppMode, i4OpenId); // MY_LOGD("+ mOpenMap.size:%d mEnumMap.size:%d", mOpenMap.size(), mEnumMap.size()); // // [1] check to see whether it's ready to open. if ( OK != (status = validateOpenLocked(i4OpenId)) ) { return status; } // // [2] get platform IPlatform*const pPlatform = getPlatform(); if ( ! pPlatform ) { MY_LOGE("No Platform"); return NAME_NOT_FOUND; } // // [3] create device based on device version. if ( version == CAMERA_DEVICE_API_VERSION_1_0 ) { pDevice = pPlatform->createCam1Device(s8ClientAppMode.string(), i4OpenId); } else if ( version >= CAMERA_DEVICE_API_VERSION_3_0 ) { MY_LOGE("Unsupported version:0x%x >= CAMERA_DEVICE_API_VERSION_3_0", version); return UNKNOWN_ERROR; } else { MY_LOGE("Unsupported version:0x%x", version); return UNKNOWN_ERROR; } // if ( pDevice == 0 ) { MY_LOGE("device creation failure"); return NO_MEMORY; } // // [4] open device successfully. { *device = const_cast
(pDevice->get_hw_device()); // pDevice->set_hw_module(module); pDevice->set_module_callbacks(mpModuleCallbacks); pDevice->setDeviceManager(this); // attachDeviceLocked(pDevice); } // return OK;}

转载地址:https://linus.blog.csdn.net/article/details/49943289 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:给ubuntuGedit安装gedit-source-code-browser
下一篇:Linux设备驱动之mmap设备操作

发表评论

最新留言

不错!
[***.144.177.141]2024年04月17日 07时51分20秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

【java】List、Set和Map的区别 2019-04-30
【java】实现java多态【图文教程】 2019-04-30
ThreadPoolExecutor线程池详解 2019-04-30
【java】synchronized对象锁和类锁简介【图文教程】 2019-04-30
【并发控制】并发控制与分布式锁(redis/zookeeper)实现【图文教程】_ 第1章 2019-04-30
【并发控制】并发控制与分布式锁(redis/zookeeper)实现【图文教程】_ 第2章 2019-04-30
【并发控制】并发控制与分布式锁(redis/zookeeper)实现【图文教程】_ 第3章 2019-04-30
【并发控制】并发控制与分布式锁(redis/zookeeper)实现【图文教程】_ 第4章 2019-04-30
【并发控制】并发控制与分布式锁(redis/zookeeper)实现【图文教程】_ 第5章 2019-04-30
synchronized和CAS锁的区别【图文教程】 2019-04-30
【java】属性别名:@JsonProperty和@JSONField的区别?【图文教程】 2019-04-30
配置nginx只允许域名访问,禁止ip访问【图文教程】 2019-04-30
Java代理【图文教程】_第1章_静态代理 2019-04-30
Java代理【图文教程】_第2章_jdk动态代理 2019-04-30
AOP面向切面编程【图文教程】_第1章 2019-04-30
AOP面向切面编程【图文教程】_第2章 2019-04-30
二叉树之前序、中序、后序和层次遍历【图文教程】 2019-04-30
【java】class内部模块(静态方法,静态块,静态变量,方法块等)执行顺序【图文教程】 2019-04-30
HashMap、HashTable和ConcurrentHashMap计算hash表索引的公式 2019-04-30
equals()方法和==的区别【图文教程】 2019-04-30