Android Camera调用流程

原创 2016年02月22日 18:19:23

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

http://blog.csdn.net/lushengchu_luis/article/details/11033095

1、Packages/apps/到framework 打开Camera

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

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

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

//start camera opening process
mCameraStartUpThread = 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
//这里面还有打开摄像头的函数openCamera
public 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<Camera>(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 service
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);
//不相关的代码就不加进来了
//sp<Camera> 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> 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<TCam>         CameraBaseT;
//里面有一个typedef 好了,那我们下一句就应该去找CameraBase<TCam>这个东西
//找到在这个位置
//./frameworks/av/camera/CameraBase.cpp:94:sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
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;
    //下一步就应该到getCameraService这里来了
    //这时候我们就要到cameraservice.java里面去看代码了
    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;
}

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

template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                               const String16& clientPackageName,
                                               int clientUid)
{
    ALOGD("%s: weiqifa connect 23", __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);
    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<ICameraClient>& 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层对应的东东,具体可以查看链接hw_get_module获取硬件模块

看一下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 weiqifa
weiqifa@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下面的内容的东西。具体的可以看一下链接
hw_get_module
然后我们就找到了这个地方
./mediatek/hardware/mtkcam/module/module.h

static
camera_module
get_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);
}


static
hw_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_t
CamDeviceManagerBase::
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_t
CamDeviceManagerBase::
openDeviceLocked(
    hw_module_t const* module, 
    char const* name, 
    hw_device_t** device
)
{
    status_t status = OK;
    sp<ICamDevice> 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<hw_device_t*>(pDevice->get_hw_device());
        //
        pDevice->set_hw_module(module);
        pDevice->set_module_callbacks(mpModuleCallbacks);
        pDevice->setDeviceManager(this);
        //
        attachDeviceLocked(pDevice);
    }
    //
    return  OK;
}
版权声明:喜欢linux

相关文章推荐

Android Camera 调用流程

一:Camera的执行流程: 1.总体介绍   Android Camera框架从整体上看是一个client/service架构。有两个进程,一个是client进程,可以看成AP端 ,主要包括Jav...

Android系统Camera录像过程分析

最近调试系统Camera,遇到如下问题:在录像过程中,拔掉Camera;会出现应用程序卡死现象。   先说说之前的设计架构:   当用户拔掉Camera时,会给应用程序发送广播;当应用程序收到广播...

Android Camera调用流程

Android中Camera的调用流程可分为以下几个层次: Package->Framework->JNI->Camera(cpp)--(binder)-->CameraService->Camer...

Android Camera 调用流程

Android中Camera的调用流程可分为以下几个层次: Package->Framework->JNI->Camera(cpp)--(binder)-->CameraService->Camer...

Android Camera使用指南

要自己写一个相机应用直接使用相机硬件,首先应用需要一个权限设置,在AndroidManifest.xml中加上使用设备相机的权限: 为你的应用创建自定义的相机,一般步骤如下:   ...

Android Camera开发之基础知识篇

概述Android框架支持设备的相机拍照和录像功能,你的应用可以直接调用系统的Camera应用来拍照或者录像(比如微信拍照),当然也可以利用Android系统提供的API开发一个Camera应用来实现...

Android Camera开发系列(上)——Camera的基本调用与实现拍照功能以及获取拍照图片加载大图片

Android Camera开发系列(一)——Camera的基本调用与API实现拍照功能 最近也是在搞个破相机,兼容性那叫一个不忍直视啊,于是自己翻阅了一些基本的资料,自己实现了一个相机,虽然相机...

初识Camera,调用系统拍照录像程序

Camera 官方指南,英语不太好,翻译有可能不准确,见谅 o(^▽^)o 关于拍照录像,有两种处理方式,一种是构建Intent调用系统或其他的APP,另一种是自定义自己的拍照或录像界面,下面就讲解一...
  • krubo1
  • krubo1
  • 2016年01月07日 16:07
  • 1092

android 7.0 camera 打开流程

本文以Android 7.0 代码为主,camera代码使用的是MTK平台的,抛开其它方面的信息,单纯以初始化打开相机为主线分析,主要在上层到底层的调用过程上,有些细节研究的不深还需要后续接着分析...

android-Camera 崩溃分析

本文是对android摄像头进行一些分析。在编译的时候发现了错误,报出了w/CameraBase:An error occurred while connecting to camera:0 以及 W...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android Camera调用流程
举报原因:
原因补充:

(最多只允许输入30个字)