[Android O] Camera 服务启动流程简析

news/2023/12/1 11:58:08

前言

去年正式进入框架组的时候,啥也不会,瞎jb分析了一通 Android N 上面的 Camera 相关流程。其实基本上都是跟着别人的分析日志看代码,然后按照自己的理解记了些笔记而已。

不过当时感觉受益匪浅,并且后来在项目开发、维护的时候,很多相关的内容都派上了用场。

从正式进入项目到现在大概有 10 个月了吧,其中大概有一半时间在 Android N 上填坑,另一半就是填 Android O 上的坑了(虽然这些坑基本上都是自己人挖的)。现在终于感觉自己对 Android Camera 这块的架构也有一定的认识了。

然而,公司业务要往 HAL3 上迁移了,又要重新开始学习 Camera 流程了……
不过现在的我已经有一定的能力,可以自己跟踪流程去分析了。趁此机会,我就从比较简单的 Camera 服务启动流程开始,锻炼锻炼分析代码、抽象出主干思想的功力吧。


Camera 服务启动流程概览

在 Android O 中,系统启动时,就会启动 CameraProvider 服务。它将 Camera HAL 从 cameraserver 进程中分离出来,作为一个独立进程 android.hardware.camera.provider@2.4-service 来控制 HAL。
这两个进程之间通过 HIDL 机制进行通信。

这样的改动源自于 Android O 版本加入的 Treble 机制,它的主要功能(如下图所示)是将 service 与 HAL 隔离,以方便 HAL 部分进行独立升级。这其实和 APP 与 Framework 之间的 Binder 机制类似,通过引入一个进程间通信机制而针对不同层级进行解耦(从 Local call 变成了 Remote call)。
Alt text
(这个图是部门里的大佬给的…)

如此一来 Camera 服务的启动流程就变得有些复杂了,但是最核心的部分其实没变,最终都要从动态库中获取连接 HAL 的结构,并保存下来以备未来对 Camera 设备进行操作。
这几天跟了一下代码流程,大概总结了一下 cameraserver 与 provider 这两个进程启动、初始化的调用逻辑,如下图。
@图. 主要调用步骤总览

总体逻辑顺序:

  1. provider 进程启动,注册;
  2. cameraserver 进程启动,注册,初始化;
  3. cameraserver 获取远端 provider(此时实例化 CameraProvider 并初始化)。

上图中,实线箭头是调用关系。左边是 cameraserver 进程中的动作,右边则是 provider 进程中的动作,它们之间通过 ICameraProvider 联系在了一起,而这个东西与 HIDL 相关,我们可以不用关心它的实现方式。

由图可见:

  • cameraserver 一侧,Cameraservice 类依旧是主体。它通过 CameraProviderManager 来管理对 CameraProvider 的操作。此处初始化的最终目的是连接上 CameraProvider。
  • provider 一侧,最终主体是 CameraProvider。初始化最终目的是得到一个 mModule,通过它可以直接与 HAL 接口定义层进行交互。

至此,我们就能对 Android O 上的 Camera 服务启动流程有一个大致的了解。但由于我个人功力尚浅,目前只能理解到这个地步,还无法轻易抽象出更容易理解的框架,所以图片中的流程还是比较凌乱的,可能需要对照相应代码才能理解。

下面是我分析代码时的一些笔记,有需要可以对照上图中的流程看看。


CameraProvider 的启动与注册

这个服务进程的启动很简单,主要动作是注册该 CameraProvider,以便 CameraServer 启动时能找到它。需要注意的是,此时 CameraProvider 还未实例化与初始化。

Service.cpp

文件位置:hardware\interfaces\camera\provider\2.4\default

看代码:

  • 第 6 行:与 /dev/vndbinder 进行某种关联,注释表明 Camera HAL 可能会通过它与其它 vendor 组件进行通信。
  • 第 7 行:创建默认为直通模式(passthrough)的 CameraProvider 服务实现。
int main()
{ALOGI("Camera provider Service is starting.");// The camera HAL may communicate to other vendor components via// /dev/vndbinderandroid::ProcessState::initWithDriver("/dev/vndbinder");return defaultPassthroughServiceImplementation<ICameraProvider>("legacy/0", /*maxThreads*/ 6);
}

LegacySupport.h

文件路径:system\libhidl\transport\include\hidl

该函数做了这些事:

  • 第 5 行:配置 RPC 线程池(当前设置最大线程为 6)。
  • 第 6 行:将 Interface(即 CameraProvider)以入参 legacy/0 为名注册到相应的管理服务中。
  • 第 12 行:连接到线程池。
template<class Interface>
__attribute__((warn_unused_result))
status_t defaultPassthroughServiceImplementation(std::string name,size_t maxThreads = 1) {configureRpcThreadpool(maxThreads, true);status_t result = registerPassthroughServiceImplementation<Interface>(name);if (result != OK) {return result;}joinRpcThreadpool();return 0;
}

CameraService 的启动与初始化

一般来说应该是 Provider 服务先启动,然后 Cameraserver 再启动,并 ”连接“ 到 Provider。
前面已经分析了 Provider 的启动,现在就来看看 Cameraserver 的启动流程。

main_cameraserver.cpp

文件位置:frameworks\av\camera\cameraserver

  • 关于线程池配置的部分就忽略吧,主要关注第 11 行,在该进程中实例化了 CameraService。
  • 实例化只有简单的一行代码,但实例化的过程并不那么简单。这个 instantiate() 接口并不是定义在 CameraService 类中的,而是定义在 BinderService 类里(而 CameraService 继承了它)。在此处,它的作用是创建一个 CameraService(通过 new 的方式),并将其加入到 ServiceManager 中(注意,在这一过程中,CameraService 被强指针引用了)。
int main(int argc __unused, char** argv __unused)
{signal(SIGPIPE, SIG_IGN);// Set 3 threads for HIDL callshardware::configureRpcThreadpool(3, /*willjoin*/ false);sp<ProcessState> proc(ProcessState::self());sp<IServiceManager> sm = defaultServiceManager();ALOGI("ServiceManager: %p", sm.get());CameraService::instantiate();ProcessState::self()->startThreadPool();IPCThreadState::self()->joinThreadPool();
}

CameraService.cpp

文件位置:frameworks\av\services\camera\libcameraservice

由于首次被强指针引用时,就会调用 onFirstRef() 函数执行初始化之类的业务逻辑,所以现在就看看 CameraService 在此处实现了什么逻辑。

onFirstRef

  • 根据 12~ 17 行可以知道,初始化的主要逻辑实现应该在 enumerateProviders() 函数中。
  • 而最后在 19 行调用一个 ping 函数,可能是在尝试连接到服务代理吧,不管它。
void CameraService::onFirstRef()
{ALOGI("CameraService process starting");BnCameraService::onFirstRef();// Update battery life tracking if service is restartingBatteryNotifier& notifier(BatteryNotifier::getInstance());notifier.noteResetCamera();notifier.noteResetFlashlight();status_t res = INVALID_OPERATION;res = enumerateProviders();if (res == OK) {mInitialized = true;}CameraService::pingCameraServiceProxy();
}

enumerateProviders

  • 函数内容略多,所以只截取需要重点关注的部分。
  • 首先将 CameraProviderManager 实例化(第 2 行),然后调用 initialize() 接口将其初始化(第 3 行),传入的参数是 this 指针,指向当前 CameraService 实例的地址。
if (nullptr == mCameraProviderManager.get()) {mCameraProviderManager = new CameraProviderManager();res = mCameraProviderManager->initialize(this);if (res != OK) {ALOGE("%s: Unable to initialize camera provider manager: %s (%d)",__FUNCTION__, strerror(-res), res);return res;}
}

CameraProviderManager.cpp

文件位置:frameworks\av\services\camera\libcameraservice\common

initialize

在分析具体实现之前,可以先看看它在头文件中的声明:

  • 用于初始化管理器,并给它设置一个状态监听(即 CameraService 实例)。选择性地接受一个与服务交互的代理。
  • 默认的代理通过 Hardware 服务管理器进行通信。备用的代理可以用来进行测试。代理的生命周期必须要超过管理器的生命周期。
  • 注意到在 enumerateProviders 中调用该接口时,只有一个入参,说明当前用的是默认代理。
    /*** Initialize the manager and give it a status listener; optionally accepts a service* interaction proxy.** The default proxy communicates via the hardware service manager; alternate proxies can be* used for testing. The lifetime of the proxy must exceed the lifetime of the manager.*/status_t initialize(wp<StatusListener> listener,ServiceInteractionProxy *proxy = &sHardwareServiceInteractionProxy);

接下来看看具体实现的逻辑:

  • 第 11~19 行:通过服务代理作出一个注册动作。根据注释,注册会触发一个给所有已知 Provider 进行通知的动作。
  • 第 22 行:这是我们主要关注的函数。注释翻译过来是这样,看看这是否为一个直通的 HAL,如果不是也没关系。注意传入的参数 kLegacyProviderName,在文件开头有它的定义,即为字符串 legacy/0
status_t CameraProviderManager::initialize(wp<CameraProviderManager::StatusListener> listener,ServiceInteractionProxy* proxy) {std::lock_guard<std::mutex> lock(mInterfaceMutex);if (proxy == nullptr) {ALOGE("%s: No valid service interaction proxy provided", __FUNCTION__);return BAD_VALUE;}mListener = listener;mServiceProxy = proxy;// Registering will trigger notifications for all already-known providersbool success = mServiceProxy->registerForNotifications(/* instance name, empty means no filter */ "",this);if (!success) {ALOGE("%s: Unable to register with hardware service manager for notifications ""about camera providers", __FUNCTION__);return INVALID_OPERATION;}// See if there's a passthrough HAL, but let's not complain if there's notaddProviderLocked(kLegacyProviderName, /*expected*/ false);return OK;
}

addProviderLocked

这个函数主要作用是将找到的这个 Provider 通过 ProviderInfo 记录下来并初始化。

  • 第 2~8 行:检查已知的 Provider 中是否已有名为 legacy/0 的。
  • 第 10~21 行:根据 legacy/0 从服务代理处获取 CameraProvider 接口,这里需要特别注意,因为此处真正地初始化了对应的 CameraProvider(怎么就在这初始化了?下一节继续分析)。
  • 第 23~28 行:通过 ProviderInfo 来保存当前 Provider 相关信息。
  • 第 30 行:记录当前 Provider。
status_t CameraProviderManager::addProviderLocked(const std::string& newProvider, bool expected) {for (const auto& providerInfo : mProviders) {if (providerInfo->mProviderName == newProvider) {ALOGW("%s: Camera provider HAL with name '%s' already registered", __FUNCTION__,newProvider.c_str());return ALREADY_EXISTS;}}sp<provider::V2_4::ICameraProvider> interface;interface = mServiceProxy->getService(newProvider);if (interface == nullptr) {if (expected) {ALOGE("%s: Camera provider HAL '%s' is not actually available", __FUNCTION__,newProvider.c_str());return BAD_VALUE;} else {return OK;}}sp<ProviderInfo> providerInfo =new ProviderInfo(newProvider, interface, this);status_t res = providerInfo->initialize();if (res != OK) {return res;}mProviders.push_back(providerInfo);return OK;
}

CameraProvider 的初始化

在 CameraService 的初始化过程中,CameraProvider 才开始进行初始化,只不过这个初始化是通过服务代理进行远端调用而进行的。

CameraProviderManager::addProviderLocked 函数的实现逻辑中,调用了 ICameraProvider::getService 接口,该接口最终会调用到一个名为 HIDL_FETCH_ICameraProvider 的函数。

CameraProvider.cpp

文件位置:hardware\interfaces\camera\provider\2.4\default

HIDL_FETCH_ICameraProvider

若传入的参数是 legacy/0,则创建一个 CameraProvider 实例(构造函数中调用了它自身的初始化函数)并返回相应指针给函数调用者。

ICameraProvider* HIDL_FETCH_ICameraProvider(const char* name) {if (strcmp(name, kLegacyProviderName) != 0) {return nullptr;}CameraProvider* provider = new CameraProvider();if (provider == nullptr) {ALOGE("%s: cannot allocate camera provider!", __FUNCTION__);return nullptr;}if (provider->isInitFailed()) {ALOGE("%s: camera provider init failed!", __FUNCTION__);delete provider;return nullptr;}return provider;
}

initialize

整个函数实现比较冗长,只贴出我们需要关注的部分分析。

  • 第 1~7 行:需要注意 rawModule 这个指针指向的结构,通过 hw_get_module 函数获取到它的实例(从相应的 Camera HAL 动态库中加载得到)。实际上这个结构就是连接到 HAL 层的关键点,通过它就可以调用到 HAL 中的一些函数。
  • (关于 hw_get_module,我以前分析过 Android N 上相关的逻辑,在 O 上其实没有很大改动,如果要详细了解可以去看看那篇文章)
  • 第 9~15 行:基于 rawModule 创建 CameraModule 实例并初始化。之后都是通过 mModule 来对 HAL 进行操作的。(其实 CameraModule 是对于 camera_module_t 的一层封装,诸如 init、open 这样的操作,实际上都是通过调用 camera_module_t 结构中函数指针指向的 HAL 层的具体实现函数来完成的)
  • 执行完这个函数,CameraProvider 也就随之初始化完成了。
camera_module_t *rawModule;
int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,(const hw_module_t **)&rawModule);
if (err < 0) {ALOGE("Could not load camera HAL module: %d (%s)", err, strerror(-err));return true;
}mModule = new CameraModule(rawModule);
err = mModule->init();
if (err != OK) {ALOGE("Could not initialize camera HAL module: %d (%s)", err, strerror(-err));mModule.clear();return true;
}
ALOGI("Loaded \"%s\" camera module", mModule->getModuleName());

小结

在 Android O 之前,Service 与 HAL 的耦合比较严重,而现在 Google 通过 HIDL 这个进程通信机制将他们分隔成两个进程,这使得 Service 与 HAL 之间的通路建立过程变得复杂了一些。
本文对 Android O 上,这两个进程的启动与初始化流程进行了简单的分析。总体来说是如下逻辑顺序:

  1. android.hardware.camera.provider@2.4-service 进程启动,仅注册 Provider;
  2. cameraserver 进程启动,实例化 CameraService,并注册到 ServiceManager 中;
  3. 由于强指针首次引用,CameraService::onFirstRef() 被调用,相当于进行初始化;
  4. 在 CameraService 初始化过程中,通过 CameraProviderManager 来获取已注册的 Provider,并实例化、初始化 CameraProvider
  5. CameraProvider 初始化过程中,从动态库中加载了 HAL 层的关键结构,并将其封装到 CameraModule 中;
  6. 将获取到的 CameraProvider 保存在 ProviderInfo 中,以便后续的使用。

这其实就相当于 Android N 之前,整个 cameraserver 的启动流程。殊途同归,最后都是通过 CameraModule 及其内部的 camera_module_t 连接到 Camera HAL。


http://www.ppmy.cn/news/429423.html

相关文章

Android之 Camera相机使用

一 简介 1.1 随着信息时代的发展&#xff0c;相机在我们生活中使用越来越频繁&#xff0c;也成为手机的基本配置之一。相机可以用来拍照&#xff0c;拍视频&#xff0c;人脸识别&#xff0c;视频聊天&#xff0c;扫码支付&#xff0c;监控等常见领域 不管什么场景&#xff0c…

Camera7 MTK camera打开流程介绍

一、整体介绍&#xff1a; 首先看下MTKcam的整体框架图如下包含了很多的内容&#xff0c;其中camera的打开流程也贯穿在 其中&#xff0c;从Camera APK 一层层的系统调用到driver再到Hardware层&#xff0c;这篇文章主要从Pipeline开始 介绍打开camera的流程&#xff0c;JAVA…

W10 无法启动你的相机

要写一个调用摄像头的程序&#xff0c;结果一直没反应&#xff0c;打开相机检测下&#xff0c;果然系统提示&#xff1a;无法启动你的相机&#xff01;&#xff08;如下图&#xff1a;&#xff09; 百度了众多答案&#xff0c;最后也没解决&#xff1b;功夫不负有心人&#xff…

Android Camera 运行流程

1.总体架构 Android Camera 框架从整体上看是一个 client/service 的架构, 有两个进程: client 进程,可以看成是 AP 端,主要包括 JAVA 代码与一些 native c/c代码; service 进 程,属于服务端,是 native c/c代码,主要负责和 linux kernel 中的 camera driver 交互,搜集 linuxker…

Android-打开系统相机并拍照两种显示方式。

目标效果&#xff1a; 第二张为点击第一个按钮拍照后显示的&#xff0c;比较模糊&#xff0c;第三章为点击第二个按钮拍照后显示的&#xff0c;比较清楚。 1.activity_main.xml页面设置布局。 activity_main.xml页面&#xff1a; <RelativeLayout xmlns:android"http…

MTK camera启动流程

目录 一、Camera 框架介绍&#xff1a; 二、Camera 启动流程 三、kernel 启动流程 1、set clock 设置时钟 2、set driver 3、上电相关 四、总结 1、ID读取不到&#xff0c;I2C不通 2、Camera 启动时间过长 3、preview 阶段耗时 4、低电流、功耗相关问题 一、Camera …

Android Camera2相机使用流程讲解

引言 以前自己在APP端做自定义相机的时候&#xff0c;一般使用Camera1&#xff0c;通过camear.opensurfaceView的方式就可以很方便的实现效果。相机的拍照调用也比较方便。最近因为工作原因接触到android TV端的开发&#xff0c;第一代主板基于Android 4.4 通过原来Camera的使…

Android Camera2教程之打开相机、开启预览、实现PreviewCallback、拍照

转载请注明出处&#xff1a; http://blog.csdn.net/lb377463323/article/details/52740411 Android API 21新增了Camera2&#xff0c;这与之前的camera架构完全不同&#xff0c;使用起来也比较复杂&#xff0c;但是功能变得很强大。 在讲解开启预览之前&#xff0c;首先需要了…

Android 自定义相机第二次打开卡死

原因&#xff1a;相机没有被正确释放导致第二次打卡死。 //正确的释放资源代码public void release(){if (mCamera ! null) {mCamera.setPreviewCallback(null) ;mCamera.stopPreview();mCamera.release();mCamera null;}}

APP使用相机CameraX

APP使用相机 Android 开发者>文档>指南 - 选择相机库 CameraXCamera2Camera&#xff08;已废弃&#xff09; CameraX 示例应用 SampleDescriptionCameraXBasicDemonstrates how to use CameraX APIs.CameraXAdvancedDemonstrates how to use CameraX APIs with TFLite…

基于Java汽车养护管理系统设计实现(源码+lw+部署文档+讲解等)

博主介绍&#xff1a; ✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战 ✌ &#x1f345; 文末获取源码联系 &#x1f345; &#x1f447;&#x1f3fb; 精…

手机中android版本9是什么,这是Android手机Android 9.0还是Android 6.0?

我想将一些评论变成一个答案&#xff0c;该答案可用于其他验证&#xff0c;以防其他人遇到类似的问题(供应商也重新设置了通知窗口)。 Android 9.0于2018年3月发布。安全补丁程序级别为2017年5月。这根本没有意义。如果15个月大的小孩的疫苗接种卡上显示最近的疫苗接种是在他出…

贷款,借钱如何判断是否高利贷?多少利息算高利贷?

先给出认定标准&#xff0c;不超过年化利率24%&#xff0c;也就是不超过月息2分&#xff0c;都不算高利贷&#xff0c;受法律保护。 市面上的借钱途径很多&#xff0c;排除那些擦边球不正规的渠道&#xff0c;需要正规审核的贷款利息之间差别其实挺大的&#xff0c;找了一下自…

城镇、农村医保卡怎么用?弄丢了如何补办?可以给父母用吗?

“学姐学姐&#xff0c;我在旅游时生病了&#xff0c;医保还能不能报销呀” “学姐学姐&#xff0c;我在老家交了医保&#xff0c;但我长期在异地工作&#xff0c;医保还能不能用呀” “学姐学姐&#xff0c;我社保卡弄丢了怎么办呀” “学姐学姐&#xff0c;有没有什么办法可以…

真实案例详述:丢手机太危险了

点击上方“逆锋起笔”&#xff0c;公众号回复 pdf 领取大佬们推荐的学习资料 来源&#xff1a;公众号“信息安全老骆驼” 今天看到一篇文章&#xff0c;看完后真的感觉丢手机太危险了&#xff0c;大家一定要注意&#xff0c;丢手机后第一时间挂失手机卡&#xff0c;银行卡。 9月…

一部手机失窃引发的惊心动魄的战争

来源&#xff1a;公众号“信息安全老骆驼” 9月4日 —— 7:30&#xff1a;正带着大娃在理发店理发&#xff0c;老婆过来告诉我&#xff0c;她在小区门口推着二娃蹲下买水果时婴儿车袋子里的手机被偷了。这时看到P40 pro上市&#xff0c;一年一度的换机季又到来了。说是丢失后就…

巨头盯着你的小钱包

燃财经&#xff08;ID:chaintruth&#xff09;原创 作者 | 朱晓宇 编辑 | 饶霞飞 双十二前夕&#xff0c;#近六成90后有实质性负债#登上微博热搜&#xff0c;阅读量达到4.9亿人次&#xff0c;网友跟帖超过5.3万条。 一位普通人&#xff0c;凭着一个手机号和一张身份证&#xff…

年轻人,攒点钱吧

之所以想谈这个话题&#xff0c;是因为我最近&#xff08;真的&#xff09;缺钱了。看到这&#xff0c;有些同学就纳闷了&#xff0c;“二哥&#xff0c;你也会缺钱啊&#xff01;”我只能说&#xff0c;二哥也是个普通的社畜啊&#xff01; 简单陈述一下这个月的状况&#xff…

毕业参加工作了,记住一句话,攒钱绝对靠谱

之所以想谈这个话题&#xff0c;是因为我最近&#xff08;真的&#xff09;缺钱了。看到这&#xff0c;有些同学就纳闷了&#xff0c;“二哥&#xff0c;你也会缺钱啊&#xff01;”我只能说&#xff0c;二哥也是个普通的社畜啊&#xff01; 简单陈述一下这个月的状况&#xf…

从手机丢失看数据安全

手机在现代生活中扮演重要角色&#xff0c;里面有大量的隐私和数据&#xff0c;手机银行&#xff0c;支付宝等都能操作个人的财产&#xff0c;所以手机的安全也越来越重要&#xff0c;一旦手机丢失&#xff0c;造成的不仅仅是一部手机的损失&#xff0c;还可能造成隐私的泄露&a…
最新文章