高通平台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、预览......)

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小驰行动派

谢谢老板,今晚吃鸡~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值