Android 系统ContentProvider流程

一、ContentProvider初始化注册流程

源码查看路径:http://xrefandroid.com/android-11.0.0_r48/
涉及到源码文件:
/frameworks/base/core/java/android/content/ContentProvider.java
自定义ContentProvider需要继承该类,内部类Transport继承关系如下,实现了aidl 接口 IContentProvider,提供增删改查注册监听操作
ContentProvider.Transport -> ContentProviderNative -> IContentProvider
客户端通过获取aidl binder对象,调用注册的ContentProvider接口
ContentProvider.getIContentProvider 返回创建的aidl 实现Transport对象

/frameworks/base/core/java/android/app/ContentProviderHolder.java
ContentProviderHolder继承Parcelable 通过序列化支持跨进程传输.
ContentProviderHolder.provider 存储 ContentProvider 的 Binder 接口(IContentProvider)
ContentProviderHolder.info   存储当前ContentProvider的组件信息ProviderInfo

/frameworks/base/services/core/java/com/android/server/content/ContentService.java
作为系统级观察者模型的核心组件,允许应用通过注册 ContentObserver 监听指定 URI 的数据变更(如联系人、短信、设置等),并在数据更新时异步通知所有订阅者,实现跨进程数据同步。

/frameworks/base/core/java/android/database/ContentObserver.java
ContentObserver.Transport 继承 IContentObserver.Stub  ContentProvider服务端通过此 binder 对象通知客户端用户数据发生变化

/frameworks/base/services/core/java/com/android/server/am/ContentProviderRecord.java
存储 ContentProvider 的 Binder 对象(如 IContentProvider)、所属进程(ProcessRecord)及权限配置(如 readPermission)
记录 ContentProvider 的启动状态(如已绑定、已发布)
ContentProviderRecord.provider 存储 ContentProvider 的 Binder 接口(IContentProvider)

/frameworks/base/core/java/android/content/pm/ProviderInfo.java
继承自 ComponentInfo,定义 ContentProvider 的组件信息,包括包名、类名、权限(如 readPermission/writePermission)、路径匹配规则(pathPattern)等。
在 AndroidManifest.xml 中通过 <provider> 标签声明,由 PMS(PackageManagerService)解析后生成内存对象。

/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
/frameworks/base/services/core/java/com/android/server/pm/ComponentResolver.java
解析所有Android组件类型activities, services, providers 和 receivers

由Android系统启动流程可知SystemServer进程启动时,会调用SystemServer.startBootstrapServices 启动系统Boot级别服务,该方法会启动ams。
还会调用SystemServer.startOtherServices 该方法会mActivityManagerService.installSystemProviders()来解析所以注册的ContentProvider
ActivityManagerService.installSystemProviders() 中调用如下2步,
1.从pms中获取ContentProvider列表
从AMS的processList中找到进程为"system"且uid="SYSTEM_UID"的ProcessRecord,
然后从系统进程中获取所有ContentProvider ,具体是调用
ActivityManagerService.generateApplicationProvidersLocked(ProcessRecord app)  执行2步
1.1 调用 List<ProviderInfo> providers = ppGlobals.getPackageManager().queryContentProviders(app.processName,...) 获取ProviderInfo列表
ApplicationPackageManager.queryContentProviders(String processName,int uid, int flags,null) 调用 slice = mPM.queryContentProviders(processName, ...) 通过aidl调用pms接口
PackageManagerService.queryContentProviders(String processName,...) 调用matchList =mComponentResolver.queryProviders(processName,...)
ComponentResolver.queryProviders(String processName,...) 遍历 mProviders.mProviders 中的ParsedProvider 如果进程和当前请求进程一致添加到providerList然后返回
ps:mProviders.mProviders 是开机PackageManagerService(PMS)扫描应用安装包(APK)后,将解析出的应用信息添加到mProviders中的。
1.2 将 ProviderInfo列表 封装到 ContentProviderRecord 然后添加到 ProcessRecord.pubProviders 。

2.调用mSystemThread.installSystemProviders(providers) 发布providers
ActivityThread.installSystemProviders(List<ProviderInfo> providers)  调用 installContentProviders(mInitialApplication, providers)
ActivityThread.installContentProviders(Context context, List<ProviderInfo> providers) 主要执行如下两步
2.1 遍历providers列表对象ProviderInfo.
生成 ContentProviderHolder 对象(包含 ContentProvider 的 Binder 接口 IContentProvider) 列表,用于跨进程通信时传递数据提供实例,
具体是调用: 
cph = installProvider(context, null, cpi,false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/)
ActivityThread.installProvider(.., ProviderInfo info,...) 创建当前应用注册的 ContentProvider 实例,并完成其初始化操作
基于ContentProvider名称创建ContentProvider实现类对象, localProvider = packageInfo.getAppFactory().instantiateProvider(cl, info.name)
然后获取ContentProvider中的binder对象赋值给  holder.provider = provider, 调用 provider = localProvider.getIContentProvider() 返回binder 对象 ContentProvider.mTransport.
installProvider方法最后返回ContentProviderHolder对象 holder.
然后将 获取的ContentProviderHolder添加到ContentProviderHolder列表对象results,调用 results.add(cph)
2.2 将ContentProviderHolder列表发布到ams
具体是调用:ActivityManager.getService().publishContentProviders(getApplicationThread(), results)
ActivityManagerService.publishContentProviders(IApplicationThread caller,List<ContentProviderHolder> providers)
遍历ContentProviderHolder列表providers 中 ContentProviderHolder对象src
    基于ContentProviderHolder 从ProcessRecord.pubProviders 获取ContentProviderRecord对象dst,然后添加到ActivityManagerService.mProviderMap,
    调用mProviderMap.putProviderByClass(comp, dst),mProviderMap.putProviderByName(names[j], dst)
    初始化 ContentProviderRecord.provider 调用dst.provider = src.provider.ContentProviderRecord.provider为ContentProvider 的 Binder 接口。

总结:    先从pms获取ContentProvider基本信息创建 ContentProvider实现类对象,然后将ContentProvider 的 Binder 接口对象封装到 ProcessRecord.pubProviders
供应客户端aidl调用


二、ContentResolver调用ContentProvider接口流程

1.查询接口
1.1 获取ContentResolver对象(ContextImpl.ApplicationContentResolver对象)  
调用 ContentResolver cr = getContentResolver() 获取ContentResolver为ApplicationContentResolver对象
ContextWrapper.getContentResolver() 调用 mBase.getContentResolver()
ContextImpl.getContentResolver()  返回mContentResolver
mContentResolver是 ContextImpl.ContextImpl构造方法中调用mContentResolver = new ApplicationContentResolver(this, mainThread)
ContextImpl.ApplicationContentResolver继承ContentResolver 
1.2 查询
cr.query(uri, null, null, null, null) 从上可知cr为ContextImpl.ApplicationContentResolver
ContentResolver.query(Uri uri,...)  调用 如下2几步:
#1.获取对应的IContentProvider
调用IContentProvider unstableProvider = acquireUnstableProvider(uri) ,基于uri获取对应ContentProvider的aidl 接口实现的binder。
ContentResolver.acquireUnstableProvider(Uri uri) 调用acquireUnstableProvider(mContext, uri.getAuthority()
ContextImpl.ApplicationContentResolver.acquireUnstableProvider(Context c, String auth)   调用 mMainThread.acquireProvider(c,ContentProvider.getAuthorityWithoutUserId(auth),resolveUserIdFromAuthority(auth), false)
ActivityThread.acquireProvider(Context c, String auth, int userId, boolean stable) 获取holder.provider,holder获取流程如下:
调用holder = ActivityManager.getService().getContentProvider(getApplicationThread(), c.getOpPackageName(), auth, userId, stable)
ActivityManagerService.getContentProvider(....) 调用getContentProviderImpl(caller, name,...)
ActivityManagerService.getContentProviderImpl(...) 该方法返回ContentProviderHolder对象
根据调用方请求的 ContentProvider 的 authority(如 com.example.provider),遍历系统已注册的 ProviderInfo 列表,匹配到对应的组件信息。
若目标 ContentProvider 尚未启动(未绑定到宿主进程),则触发其宿主进程的启动流程(如通过 startProcessLocked 方法),并等待其初始化完成。
通过 IContentProvider 接口封装 ContentProvider 的 Binder 通信句柄,返回 ContentProviderHolder 对象给调用方(如 ContentResolver),作为后续数据操作(query、insert 等)的通道

#2.调用qCursor = unstableProvider.query(mPackageName, mAttributionTag, uri, projection,queryArgs, remoteCancellationSignal)
因为 unstableProvider是基于uri获取对应ContentProvider的aidl 接口实现的binder。
即通过aidl 调用服务端创建的 ContentProvider.query 方法.

其他增删改流程同上。

2.监听接口
2.1注册监听
cr.registerContentObserver(uri, true, ContentObserver类对象)
ContentResolver.registerContentObserver(Uri uri, boolean notifyForDescendents,ContentObserver observer, int userHandle) 该方法
调用getContentService().registerContentObserver(uri, notifyForDescendents,observer.getContentObserver(), userHandle, mTargetSdkVersion)
getContentService方法返回 ContentService 对象的binder IContentService,即调用
ContentService.registerContentObserver(Uri uri, ...) 调用 mRootNode.addObserverLocked(uri, ...) 
ContentService.addObserverLocked(Uri uri, ...) 
例如uri为content://com.android.mycontentprovider/contact
 最终我们得到ObserverNode的树形结构如下所示:
        mRootNode("")
            -- ObserverNode("com.android.mycontentprovider")
                --ObserverNode("contact") ,
2.2. 监听回调
例如uri为 content://com.android.mycontentprovider/contact/d
getContext().getContentResolver().notifyChange(uri, null)         调用notifyChange(uri, observer, true /* sync to network */);
ContentResolver.notifyChange(Uri uri, ContentObserver observer,boolean syncToNetwork) 调用notifyChange(uri, observer, syncToNetwork ? NOTIFY_SYNC_TO_NETWORK : 0)
ContentResolver.notifyChange(Uri uri, ContentObserver observer,int flags) 调用notifyChange(ContentProvider.getUriWithoutUserId(uri),observer,flags,ContentProvider.getUserIdFromUri(uri, mContext.getUserId()))
ContentResolver.notifyChange(Uri uri, ContentObserver observer, int flags,int userHandle) 调用notifyChange(new Uri[] { uri }, observer, flags, userHandle)
ContentResolver.notifyChange(Uri[] uris, ContentObserver observer, int flags,int userHandle) 调用getContentService().notifyChange(uris, observer == null ? null : observer.getContentObserver(),...)
ContentService.notifyChange(Uri[] uris, IContentObserver observer,...) 
1.调用ContentService的成员变量mRootNode的collectObserverLocked()函数来收集那些注册了监控"content://com.android.mycontentprovider/contact/d"这个URI的ContentObserver,
2.调用了这些ContentObserver的onChange()函数来通知它们监控的数据发生变化了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/43870.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring Initializr搭建spring boot项目

介绍 Spring Initializr 是一个用于快速生成 Spring Boot 项目结构的工具。它为开发者提供了一种便捷的方式&#xff0c;可以从预先定义的模板中创建一个新的 Spring Boot 应用程序&#xff0c;从而节省了从头开始设置项目的大量时间。 使用 Spring Initializr&#xff0c;你…

C++中的new、malloc、realloc、calloc——特点?函数原型?释放方式?区别?校招面试常问内容?

作者&#xff1a;求一个demo 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 内容通俗易懂&#xff0c;没有废话&#xff0c;文章最后是面试常问内容&#xff08;建议通过标题目录学习&#xff09; 废话不多…

【字符设备驱动开发–IMX6ULL】(一)简介

【字符设备驱动开发–IMX6ULL】&#xff08;一&#xff09;简介 一、Linux驱动与裸机开发区别 1.裸机驱动开发回顾 ​ 1、底层&#xff0c;跟寄存器打交道&#xff0c;有些MCU提供了库。 spi.c&#xff1a;主机驱动&#xff08;换成任何一个设备之后只需要调用此文件里面的…

Spring AI MCP 架构详解

Spring AI MCP 架构详解 1.什么是MCP? MCP 是一种开放协议&#xff0c;它对应用程序向大语言模型&#xff08;LLMs&#xff09;提供上下文信息的方式进行了标准化。可以把 MCP 想象成人工智能应用程序的 USB-C 接口。就像 USB-C 为将设备连接到各种外围设备和配件提供了一种…

【Java】IO流

一、IO流的定义 二、 字节流 &#xff08;一&#xff09;FileOutputStream 操作本地文件的字节输出流&#xff0c;可以把程序中的数据写到本地文件中。 1、书写步骤 注&#xff1a; &#xff08;1&#xff09;创建字节输出流对象&#xff1a; 参数是字符串表示的路径或者…

Java 大视界 -- Java 大数据机器学习模型在电商商品推荐冷启动问题中的解决策略(160)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

MySQL———作业实验

一、创建数据库表 1.创建数据库 mysql> create database mydb11_stu; mysql> use mydb11_stu; 2.建表 &#xff08;1&#xff09;创建student表 mysql> create table student ( -> id int(10) not null unique primary key, -> name varch…

深度解析衡石科技HENGSHI SENSE嵌入式分析能力:如何实现3天快速集成

嵌入式分析成为现代SaaS的核心竞争力 在当今SaaS市场竞争中&#xff0c;数据分析能力已成为产品差异化的关键因素。根据Bessemer Venture Partners的最新调研&#xff0c;拥有深度嵌入式分析功能的SaaS产品&#xff0c;其客户留存率比行业平均水平高出23%&#xff0c;ARR增长速…

Day17 -实例:利用不同语言不同框架的特征 进行识别

前置&#xff1a;我们所需的web站点&#xff0c;都可以利用fofa去搜索&#xff0c;例如&#xff1a;app"flask"这样的语句去找对应的站点&#xff0c;找到后&#xff0c;我们模拟不知道是什么框架&#xff0c;再根据特征去判断它的框架。 ***利用工具可以再去结合大…

Linux输入系统应用编程

什么是输入系统 Linux 输入系统是处理用户输入设备(如键盘、鼠标、触摸屏、游戏手柄等)的软件架构。在应用编程层面&#xff0c;它提供了与这些输入设备交互的接口。 主要组成部分 输入设备驱动层&#xff1a;直接与硬件交互的驱动程序 输入核心层&#xff1a;内核中的输入子…

【C++初阶】---类和对象(下)

1.再探构造函数&#xff08;初始化链表&#xff09; •之前我们实现构造函数时&#xff0c;初始化成员变量主要使⽤函数体内赋值&#xff0c;构造函数初始化还有⼀种⽅式&#xff0c;就是初始化列表&#xff0c;初始化列表的使⽤⽅式是以⼀个冒号开始&#xff0c;接着是⼀个以逗…

Ubuntu 22.04.5 LTS 设置时间同步 ntp

提示&#xff1a;文章为操作记录&#xff0c;以备下次使用 文章目录 前言一、设置ntp1.1替换国内源1.2 更新源&安装1.3 验证 前言 设置时间同步&#xff0c;环境版本 # cat /etc/os-release PRETTY_NAME"Ubuntu 22.04.5 LTS" NAME"Ubuntu" VERSION_…

飞书电子表格自建应用

背景 coze官方的插件不支持更多的飞书电子表格操作&#xff0c;因为需要自建应用 飞书创建文件夹 创建应用 开发者后台 - 飞书开放平台 添加机器人 添加权限 创建群 添加刚刚创建的机器人到群里 文件夹邀请群 创建好后&#xff0c;就可以拿到id和key 参考教程&#xff1a; 创…

计算机网络——传输层(TCP)

传输层 在计算机网络中&#xff0c;传输层是将数据向上向下传输的一个重要的层面&#xff0c;其中传输层中有两个协议&#xff0c;TCP&#xff0c;UDP 这两个协议。 TCP 话不多说&#xff0c;我们直接来看协议报头。 源/目的端口号&#xff1a;表示数据从哪个进程来&#xff0…

【ArcGIS】ArcGIS10.6彻底卸载和ArcGIS10.2安装全过程

卸载python3后,解决了ArcGIS与python3冲突问题后,软件可以正常打开使用了 但是还是出现了问题 用ArcGIS 进行空间分析时,中间操作没有任何报错和问题,但是就是没有运行结果 在别人的软件上操作一遍可以出现运行结果 关闭确有这个,但真的不是我给它的运行时间不够,反反复复试…

智慧电力:点亮未来能源世界的钥匙

在科技日新月异的今天&#xff0c;电力行业正经历着前所未有的变革。智慧电力&#xff0c;作为这一变革的核心驱动力&#xff0c;正逐步改变着我们对电力的认知和使用方式。它不仅是电力行业的一次技术革新&#xff0c;更是推动社会可持续发展、实现能源高效利用的重要途径。 智…

oracle中java类的使用

方式一&#xff1a; 编写一个简单的java类 vi OracleJavaDemo.java public class OracleJavaDemo { public static String processData(String input) { return "Processed: " input; } } 编译 javac OracleJavaDemo.java 生成OracleJavaDemo…

pycharm2024.1.1版本_jihuo

目录 前置&#xff1a; 步骤&#xff1a; step one 下载软件 step two 卸载旧版本 1 卸载软件 2 清除残余 step three 下载补丁 step four 安装2024.1.1版本软件 step five 安装补丁 1 找位置放补丁 2 自动设置环境变量 step six 输入jihuo码 前置&#xff1a; 之…

革新汽车安全通信技术,美格智能全系车载通信模组支持NG-eCall

根据QYR&#xff08;恒州博智&#xff09;的统计及预测&#xff0c;2024年全球汽车无线紧急呼叫&#xff08;eCall&#xff09;设备市场销售额达到了25.17亿美元&#xff0c;预计2031年将达到44.97亿美元&#xff0c;年复合增长率&#xff08;CAGR 2025-2031&#xff09;为8.8%…

AWE 2025:当AI科技遇见智能家居

3月20日&#xff0c;以“AI科技、AI生活”为主题的AWE2025&#xff08;中国家电及消费电子博览会&#xff09;在上海新国际博览中心开幕。作为全球家电行业风向标&#xff0c;本届展会最大的亮点莫过于健康理念在家电领域的全面渗透。从食材保鲜到空气净化&#xff0c;从衣物清…