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.mzph.cn/web/73864.shtml

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

相关文章

爬虫工程师分享自动批量化获取商品评论数据的方法有哪些?

在电商领域&#xff0c;商品评论数据对于商家了解产品口碑、洞悉用户需求&#xff0c;以及开展竞品分析等工作具有极其重要的价值。作为爬虫工程师&#xff0c;掌握自动批量化获取商品评论数据的方法&#xff0c;能极大提升数据收集效率。下面&#xff0c;我将分享一些实用的操…

Vue3组件事件用户信息卡练习

用户信息卡 题目要求 实现一个用户信息卡系统&#xff0c;包含以下功能&#xff1a; 1.父组件收集用户信息&#xff08;姓名、年龄、班级&#xff09; 2.子组件接收并展示用户信息卡片 3.添加基本的数据验证 <!DOCTYPE html> <html lang"en"> <h…

SpringBean模块(二)bean初始化(2)和容器初始化顺序的比较--引入ApplicationContextInitializer

前面介绍了获取容器可以让spring bean实现ApplicationContextAware&#xff0c;实际也是初始化执行了setApplicationContext接口&#xff0c; 初始化接口还可以借助一些注解或者spring bean的初始化方法&#xff0c;那么他们的执行顺序是什么样的呢&#xff1f; 一、验证&…

中小型企业网络的搭建

1.1 网络逻辑拓扑、布线方案的设计 1.1.1 网络设计依据 网络设计应遵循以下基本原则&#xff1a; 高效性&#xff1a;确保网络架构能够支持企业日常业务的高效运行。 可靠性&#xff1a;采用冗余设计&#xff0c;确保网络的高可用性&#xff0c;避免单点故障。 可扩展性…

angr基础学习

参考&#xff1a;angr AngrCTF_FITM/笔记/03/Angr_CTF从入门到精通&#xff08;三&#xff09;.md at master ZERO-A-ONE/AngrCTF_FITM angr_explore 00_angr_find IDA分析结果&#xff1a; 逻辑简单&#xff0c;输入&#xff0c;complex_function进行加密&#xff0c;加密…

软考-高级-系统架构设计师【考试备考资料下载】

计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试是原中国计算机软件专业技术资格和水平考试的完善与发展。计算机技术与软件专业技术资格&#xff08;水平&#xff09;考试是由国家人力资源和社会保障部、工业和信息化部领导下的国家级考试。 计算机技术与软件专…

3. 第三放平台部署deepseek

有时候我们会发现使用deepseek服务器&#xff0c;异常卡顿&#xff0c;这是由于多方面原因造成的&#xff0c;比如说访问人数过多等。想要解决这个问题&#xff0c;我们可以选择第三方平台进行部署 第三方平台 我们可以选择的第三方平台很多&#xff0c;比如硅基流动、秘塔搜索…

1.4-蜜罐\堡垒机\API接口

1.4-蜜罐\堡垒机\API接口 蜜罐&#xff1a;用来钓鱼或诱惑测试人员的防护系统 bash <(curl -sS -L https://hfish.net/webinstall.sh) # 安装HFISH蜜罐堡垒机&#xff1a; 运维用的&#xff0c;统一管理运维平台;拿下堡垒机就很有可能等于拿下了多个平台 jumpServer一键安…

知识图引导的检索增强生成

摘要 检索增强生成&#xff08;RAG&#xff09;已经成为一种很有前途的技术&#xff0c;用于解决大型语言模型&#xff08;LLM&#xff09;生成的响应中的幻觉问题。现有的RAG研究主要集中在应用基于语义的方法来提取孤立的相关组块&#xff0c;忽略了它们之间的内在关系。在本…

【机器学习】imagenet2012 数据预处理数据预处理

【机器学习】数据预处理 1. 下载/解压数据2. 数据预处理3. 加载以及训练代码3.1 使用PIL等加载代码3.2 使用OpenCV的方式来一张张加载代码3.3 h5的方式来加载大文件 最后总结 这个数据大约 140个G,128w的训练集 1. 下载/解压数据 首先需要下载数据&#xff1a; 数据最后处理…

质量工程:数字化转型时代的质量体系重构

前言&#xff1a;质量理念的范式转移阅读原文 如果把软件开发比作建造摩天大楼&#xff1a; 传统测试 竣工后检查裂缝&#xff08;高成本返工&#xff09; 质量工程 从地基开始的全流程监理体系&#xff08;设计图纸→施工工艺→建材选择→竣工验收&#xff09; IEEE研究…

【全栈开发】—— Paddle OCR 文字识别 + deepseek接入(基于python 最新!!!)

所有源码都在文章中&#xff0c;大家不要私信来要源码&#xff0c;当然&#xff0c;评论区欢迎交流技术 目录 Paddle OCR 配置环境 示例 deepseek接入 环境配置 api 调用代码 sliconflow Paddle OCR 配置环境 清华源下载 paddlepaddle&#xff1a; pip install paddlepaddle …

SAIL-RK3588J 核心板技术方案——高精度装配式建筑机器人控制‌

&#xff08;本方案契合《建筑机器人产业目录》政策要求&#xff09; 一、方案背景与政策支持‌ ‌政策驱动‌ 2025年2月《建筑机器人产业目录》明确将‌“高精度建筑机器人控制设备”‌纳入重点补贴范围&#xff0c;要求定位精度≤0.5mm、支持实时质检与多机协同&#xff0c…

OpenAI API - 快速入门开发

文章目录 开发者快速入门分析图像输入使用工具扩展模型提供闪电般的 AI 体验构建代理进一步探索 模型精选模型推理模型旗舰聊天模型成本优化模型实时模型旧版 GPT 模型DALLE文本转语音转写嵌入调度工具特定模型GPT 基础模型 Libraries创建和导出 API 密钥安装官方 SDKJavaScrip…

蓝桥杯省赛 棋盘 3533 二维差分+二维前缀和

传送门 0棋盘 - 蓝桥云课 const int N 2e3 10;int n,m; int a[N][N];void insert(int x11,int y11,int x22,int y22) {a[x11][y11] ;a[x11][y22 1] --;a[x22 1][y11] --;a[x22 1][y22 1] ; }void solve() {cin >> n >> m;for (int i 1;i < m;i ){int x11…

《C++Linux编程进阶:从0实现muduo 》-第6讲.C++死锁问题如何分析调试-原子操作,互斥量,条件变量的封装

重点内容 视频讲解&#xff1a;《CLinux编程进阶&#xff1a;从0实现muduo C网络框架系列》-第6讲.C死锁问题如何分析调试-原子操作,互斥量,条件变量的封装 代码改动 lesson6代码 实现&#xff1a;base/Atomic.h 实现&#xff1a;base/Mutex.h 实现&#xff1a;base/Condit…

洛谷题单1-P5708 【深基2.习2】三角形面积-python-流程图重构

题目描述 一个三角形的三边长分别是 a a a、 b b b、 c c c&#xff0c;那么它的面积为 p ( p − a ) ( p − b ) ( p − c ) \sqrt{p(p-a)(p-b)(p-c)} p(p−a)(p−b)(p−c) ​&#xff0c;其中 p 1 2 ( a b c ) p\frac{1}{2}(abc) p21​(abc)。输入这三个数字&#xff…

matplotlib标题比x,y轴字体大,明明标题字体更大?

原始代码&#xff1a; plt.xlabel(训练轮次&#xff08;Epochs&#xff09;, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗 plt.ylabel(R值, fontsize14, fontweightbold, fontpropertieschinese_font) # 设置中文字体、加大、加粗…

Baklib内容中台的核心优势是什么?

智能化知识管理引擎 Baklib的智能化知识管理引擎通过多源数据整合与智能分类技术&#xff0c;实现企业知识资产的自动化归集与动态更新。系统内置的语义分析算法可自动识别文档主题&#xff0c;结合自然语言处理技术生成结构化标签体系&#xff0c;大幅降低人工标注成本。针对…

Android学习总结之ContentProvider跨应用数据共享

在 Android 开发中&#xff0c;跨应用数据共享是构建开放生态的关键需求。作为四大组件之一&#xff0c;ContentProvider通过标准化接口和安全机制&#xff0c;成为实现这一需求的核心枢纽。本文将围绕其生命周期方法、核心机制、自定义实现及最佳实践展开&#xff0c;帮助开发…