浅析调用android的content provider(一)

        在Android下,查询联系人、通话记录等,需要用到content provider。但是,调用content provider时,Android框架内部是如何做的呢?这一系列文章就是解决这个问题的,所采用的开发环境及源码都是基于Android 1.6版本。
  • 概述
       总的来说此问题分为两个步骤: 
  1. 初始化content provider。这一阶段主要是参照AndroidManifest.xml,初始化content provider。注意这里只有当包含content provider的进程运行的时候,才会对该进程内所有的content provider进行初始化。其它provider是按需初始化的(后续文章会介绍该问题)。  
  2. 调用content provider,进行数据库操作。这个调用通常发生在用户定义的Activity子类的相关接口内。调用时,首先会获取对应的content provider对象(有可能是代理对象)。然后,再调用(直接调用或者通过IBinder接口)。
       本文主要探讨第一个问题:初始化content provider。
  • 应用进程的管理模型

       Android框架内,应用程序Java代码的入口为ActivityThread.main。用来管理不同的应用的服务名称为activity。它的模型大致为:


       左边为多个应用进程,每个进程中有个主线程ActivityThread.main,Looper.loop()是主线程的消息循环。所有的应用进程都是通过IBinder机制和ActivityManagerService进程进行交互的。应用进程为了能调用activity服务进程的ActivityManagerService中的方法,必须通过ActivityManagerProxy类。activity服务进程则通过ApplicationThreadProxy类与服务进程的ApplicationThread通信。ApplicationThread的作用主要是将activity服务进程的调用转换为ActivityThread主线程中的消息,从而保证ActivityManagerService的调用是异步的。

       右边的activity服务进程是所有应用的服务进程,用于管理应用进程。启动新的应用进程时,会向zygote服务进程发送socket消息。zygote接收到消息后,则会启动新的delvik虚拟机,然后运行ActivityThread.main,启动新的应用。

  • PackageManagerService

       PackageManagerService也是一个服务,是用来管理手机内所有的apk包的。调用它的方式和调用ActivityManagerService是一样的,通过IBinder。它的初始化入口为PackageManagerService.main:

[java] view plaincopy
  1. public static final IPackageManager main(Context context, boolean factoryTest) {  
  2.     PackageManagerService m = new PackageManagerService(context, factoryTest);  
  3.     ServiceManager.addService("package", m);  
  4.     return m;  
  5. }  

       main方法主要是创建一个PackageManagerService,然后注册到ServiceManager中,名称为"package”。PackageManagerService的构造函数中,会去查找系统目录和应用目录下的apk文件,以获取应用的包相关的信息;比如:包名称,包含的Acvity、Provider等。

[java] view plaincopy
  1. // ……  
  2. scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);  
  3. // ……  
  4. scanDirLI(mAppInstallDir, 0, scanMode);  
  5. // ……  

       scanDirLI函数中,对于每个package,使用函数scanPackageLI解析其中的信息(此处应该是读取AndroidManifest.xml)。scanPackageLI检查相关信息后,又会调用另一个scanPackageLI。这个函数内部会扫描到手机内所有的Provider信息:

[java] view plaincopy
  1. PackageParser.Provider p = pkg.providers.get(i);  
  2. p.info.processName = fixProcessName(pkg.applicationInfo.processName,  
  3.         p.info.processName, pkg.applicationInfo.uid);  
  4. mProvidersByComponent.put(new ComponentName(p.info.packageName,  
  5.         p.info.name), p);  

       mProvidersByComponent保存了所有的provider信息,这部分数据源自于manifest。每个数据包含了PackageParser.Provider、包名称和Provider的类名。

       到这里,我们可以看到,PackageManagerService真的是用来管理手机的应用包的。通过它可以知道所有的系统可用资源。当然这些资源只是一些静态信息。通过这些信息,可以创建应用进程、初始化相关的Android组件。

  • 应用进程的初始化
       先看一下ActivityThread.main的实现,它创建了一个ActivityThread对象,初始化之后,进入消息循环。

[java] view plaincopy
  1. public static final void main(String[] args) {  
  2.     // ......  
  3.     ActivityThread thread = new ActivityThread();  
  4.     thread.attach(false);  
  5.   
  6.     Looper.loop();  
  7.   
  8.     // ......  
  9. }  

       attach函数中,回去调用ActivityManagerService.attachApplication方法。

[java] view plaincopy
  1. mgr.attachApplication(mAppThread);  

       此时,会进入ActivityManagerService的进程空间,进入方法attachApplicationLocked,它会去获取和当前客户端应用程序关联的Provider信息。

[java] view plaincopy
  1. List providers = generateApplicationProvidersLocked(app);  

       根据上面的信息,很容易知道此处是通过PackageManagerService获取Provider信息的。参数app表明,只是取运行在该app内的Provider。根据Android的文档,content provider必须在对应的AndroidManifest.xml中定义。默认情况下,是运行在安装包名称命名的进程里面。你也可以在android:process属性中制定所属的进程名称。另一个重要的属性android:multiprocess则可以指定provider的初始化方式,是分散在调用端进程中,从而避免进程间通信;还是只初始化在某个进程内,各个调用端只保留provider的代理。

       随后,通过下面的方法调用,返回到应用程序的进程空间,参数中包含了上面获得的providers。此处的thread实际上就是应用端的ApplicationThread对象。

[java] view plaincopy
  1. thread.bindApplication(processName, app.instrumentationInfo != null  
  2.         ? app.instrumentationInfo : app.info, providers,  
  3.         app.instrumentationClass, app.instrumentationProfileFile,  
  4.         app.instrumentationArguments, app.instrumentationWatcher, testMode,   
  5.         isRestrictedBackupMode, mConfiguration, getCommonServicesLocked());  

       ApplicationThread.bindApplication会发送BIND_APPLICATION消息给主线程。主线程会调用ActivityThread.handleBindApplication方法。这个函数里面主要分两步:一是根据需要创建Application、ApplicationContext和ApplicationContentResolver对象。因为,有可能多个apk运行在一个进程中,那么它们内部的组件(Component)执行的上下文(context)是不一样的。这几个对象实际上就是provider执行的上下文。二是根据传递过来的provider信息,创建provider实例,并保存在ActivityThread.mProviderMap中。具体的实例化provider过程如下(下面的代码位于ActivityThread.handleBindApplication中):

[java] view plaincopy
  1. List<ProviderInfo> providers = data.providers;  
  2. if (providers != null) {  
  3.     installContentProviders(app, providers);  
  4. }  

       获取ActivityManagerService传递过来的provider信息,并在本进程中初始化。具体的,installContentProviders方法中,会对每个provider调用installProvider方法:

[java] view plaincopy
  1. IContentProvider cp = installProvider(context, null, cpi, false);  

       installProvider方法中,主要是实例化Provider,并保存到mProviderMap中:

[java] view plaincopy
  1. final java.lang.ClassLoader cl = c.getClassLoader();  
  2. localProvider = (ContentProvider)cl.  
  3.     loadClass(info.name).newInstance();  
  4. provider = localProvider.getIContentProvider();  
  5. // ......  
  6. // Cache the pointer for the remote provider.  
  7. String names[] = PATTERN_SEMICOLON.split(info.authority);  
  8. for (int i=0; i<names.length; i++) {  
  9.     ProviderRecord pr = new ProviderRecord(names[i], provider,  
  10.             localProvider);  
  11.     try {  
  12.         provider.asBinder().linkToDeath(pr, 0);  
  13.         mProviderMap.put(names[i], pr);  
  14.     } catch (RemoteException e) {  
  15.         return null;  
  16.     }  
  17. }  
       上面的installContentProviders方法执行完成之后,会调用ActivityManagerService.publishContentProviders方法,将provider注册到ActivityManagerService中,方便其它应用进程获取。这里面有两个参数,一个是ApplicationThread对象,另一个是provider实例信息。

[java] view plaincopy
  1. try {  
  2.     ActivityManagerNative.getDefault().publishContentProviders(  
  3.         getApplicationThread(), results);  
  4. catch (RemoteException ex) {  
  5. }  

       ActivityManagerService.publishContentProviders的实现也很简单,主要是将provider信息保存到ActivityManagerService.mProvidersByName中。具体参见源码。
  • 总结
       本文主要介绍了Android系统内provider的初始化,Android系统默认是会初始化一些provider的,比如:ContactsProvider。它们的初始化和本文介绍的流程应该差不多,主要是在应用进程初始化时获取provider的信息,然后实例化provider,最后将实例化的provider保存到ActivityManagerService中,供其它应用进程使用。需要说明的一点是,应用进程内可以运行多个apk中的组件。

       下一篇文章会介绍调用provider的流程。


转载于:https://www.cnblogs.com/zsw-1993/p/4879932.html

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

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

相关文章

linux中的集线器、交换机、路由器及组网

集线器&#xff1a;&#xff08;缺点&#xff1a;群发信息 hub&#xff08;集线器&#xff09;能够完成多个电脑的链接每个数据包的发送都是以广播的形式进行的&#xff0c;容易堵塞网络 通过交换机组网 网络交换机&#xff08;又称“网络交换器”&#xff09;&#xff0c;是…

R语言第七讲 线性回归分析案例续

题目 MASS 库中包含 Boston (波士顿房价)数据集&#xff0c;它记录了波士顿周围 506 个街区的 medv (房价中位数)。我们将设法用 13 个预测变量如 rm (每栋住宅的平均房间数)&#xff0c; age (平均房 龄)&#xff0c; lstat (社会经济地位低的家庭所占比例)等来预测…

LeetCode 1129. 颜色交替的最短路径(BFS)

文章目录1. 题目2. 解题1. 题目 在一个有向图中&#xff0c;节点分别标记为 0, 1, ..., n-1。 这个图中的每条边不是红色就是蓝色&#xff0c;且存在自环或平行边。 red_edges 中的每一个 [i, j] 对表示从节点 i 到节点 j 的红色有向边。 类似地&#xff0c;blue_edges 中的每…

web.config文件之自定义错误节

web.config文件之自定义错误节 大家都知道&#xff0c;在开发asp.net应用程序时&#xff0c;通过web.config文件可以配置在执行 Web 请求期间发生未处理的错误时&#xff0c;ASP.NET 显示信息的方式。下面是一个典型的基本配置&#xff1a; ?<system.web><customErro…

R语言第八讲 评估模型之交叉验证法分析案例

题目 评估Auto数据集上拟合多个线性模型所产生的测试错误率。Auto数据集是存在与ISLR程序包中的一个摩托车相关数据的数据集&#xff0c;读者可自行下载ISLR程序包&#xff0c;并将Auto数据集加载。 相关资料 交叉验证是在机器学习建立模型和验证模型参数时常用的办法。交叉验…

linux中UDP程序流程、客户端、服务端

UDP--- 用户数据报协议&#xff08;User Datagram Protocol&#xff09;&#xff0c;是一个无连接的简单的面向数据报的运输层协议。 优点&#xff1a;传输速度快 缺点&#xff1a;不可靠 socket的中文意思是接插件&#xff1a; 创建socket 在 Python 中 使用socket 模块的类 …

LeetCode 1041. 困于环中的机器人

文章目录1. 题目2. 解题1. 题目 在无限的平面上&#xff0c;机器人最初位于 (0, 0) 处&#xff0c;面朝北方。机器人可以接受下列三条指令之一&#xff1a; “G”&#xff1a;直走 1 个单位“L”&#xff1a;左转 90 度“R”&#xff1a;右转 90 度 机器人按顺序执行指令 ins…

Javascript实现合并单元格

Web上的报表或表格应用&#xff0c;较为复杂的表格操作一般都比较难实现&#xff0c;这里介绍一下用ComponentOne Studio for ASP.NET Wijmo中的SpreadJS&#xff0c;可以实现一些较为复杂的表格操作&#xff0c;个人认为他模仿桌面应用的操作体验非常不错&#xff0c;虽然我并…

R语言第八讲续 评估模型之自助法分析案例

题目 今天来用自助法评估一下ISLR 程序包中的 Portfolio (金融资产)数据集的预测函数 相关资料 自助法&#xff08;Bootstraping&#xff09;是另一种模型验证&#xff08;评估&#xff09;的方法&#xff08;之前已经介绍过单次验证和交叉验证&#xff09;。其以自助采样&…

python中常见的15中面试题

下面这些问题涉及了与Python相关的许多技能&#xff0c;问题的关注点主要是语言本身&#xff0c;不是某个特定的包或模块。每一个问题都可以扩充为一个教程&#xff0c;如果可能的话。某些问题甚至会涉及多个领域。 我之前还没有出过和这些题目一样难的面试题&#xff0c;如果你…

LeetCode 1039. 多边形三角剖分的最低得分(区间DP)

文章目录1. 题目2. 解题1. 题目 给定 N&#xff0c;想象一个凸 N 边多边形&#xff0c;其顶点按顺时针顺序依次标记为 A[0], A[i], ..., A[N-1]。 假设您将多边形剖分为 N-2 个三角形。 对于每个三角形&#xff0c;该三角形的值是顶点标记的乘积&#xff0c;三角剖分的分数是…

CentOS6.4安装包初识

LiveCD 一般用来修复系统使用&#xff0c;有容量很小&#xff0c;不用安装&#xff0c;可以自启动等特性。bin DVD也具有同 样的功能&#xff0c;但是体积较大&#xff0c;所以会有live DVD。   LiveDVD 与LiveCD 相同是不需要安装就直接使用的&#xff0c;要安装的话还是要安…

R语言第九讲 验证集法

目的 为了更好的熟悉分析定性变量的逻辑斯谛回归分析的应用和验证集法(评估拟合拟合模型的一种方法&#xff09;&#xff0c;用一个简单的示例来介绍一下它们在分析数据中的应用。 题目 在 Default 数据集上用income 和 balance 做逻辑斯谛回归来预测 default的概率。现…

总结python中基本的面试题

1.Python是如何进行内存管理的&#xff1f; 答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一、对象的引用计数机制 Python内部使用引用计数&#xff0c;来保持追踪内存中的对象&#xff0c;所有对象都有引用计数。 引用计数增加的情况&#xff1a; 1&a…

02.改善深层神经网络:超参数调试、正则化以及优化 W1.深度学习的实践层面

文章目录1. 训练&#xff0c;验证&#xff0c;测试集2. 偏差&#xff0c;方差3. 机器学习基础4. 正则化5. 为什么正则化预防过拟合6. dropout&#xff08;随机失活&#xff09;正则化7. 理解 dropout8. 其他正则化9. 归一化输入10. 梯度消失 / 梯度爆炸11. 神经网络权重初始化1…

动态规划 POJ 1088 滑雪

Description Michael 喜欢滑雪百这并不奇怪&#xff0c; 因为滑雪的确很刺激。可是为了获得速度&#xff0c;滑的区域必须向下倾斜&#xff0c;而且当你滑到坡底&#xff0c;你不得不再次走上坡或者等待升降机来载你。Michael想知道载一个 区域中最长底滑坡。区域由一个二维数组…

R语言第十讲 逻辑斯蒂回归

模型函数介绍 Logistic Regression 虽然被称为回归&#xff0c;但其实际上是分类模型&#xff0c;并常用于二分类。Logistic Regression 因其简单、可并行化、可解释强深受工业界喜爱。 Logistic 回归的本质是&#xff1a;假设数据服从这个Logistic 分布&#xff0c;然后使用极…

网络上总结python中的面试题

【题目:001】| 说说你对zen of python的理解&#xff0c;你有什么办法看到它? Python之禅,Python秉承一种独特的简洁和可读行高的语法&#xff0c;以及高度一致的编程模式&#xff0c;符合“大脑思维习惯”&#xff0c;使Python易于学习、理解和记忆。Python同时采用了一条极简…

阿里云 超级码力在线编程大赛初赛 第3场 题目4. 完美字符串

文章目录1. 题目2. 解题1. 题目 描述 定义若一个字符串的每个字符均为’1’&#xff0c;则该字符串称为完美字符串。 给定一个只由’0’和’1’组成的字符串s和一个整数k。 你可以对字符串进行任意次以下操作 选择字符串的一个区间长度不超过k的区间[l, r]&#xff0c;将区间…

(译)Windows Azure的7月更新:SQL数据库,流量管理,自动缩放,虚拟机

Windows Azure的7月更新:SQL数据库&#xff0c;流量管理&#xff0c;自动缩放&#xff0c;虚拟机 今早我们释出一些很棒的Windows Azure更新。这些新的提升包括&#xff1a;SQL数据库&#xff1a;支持SQL自动导出和一个新的高级层SQL数据库选项流量管理&#xff1a;在HTML门户的…