网站建设项目报告总结报告,做教育机构网站,广州网络推广有限责任公司,flash网站教程在Android下#xff0c;查询联系人、通话记录等#xff0c;需要用到content provider。但是#xff0c;调用content provider时#xff0c;Android框架内部是如何做的呢#xff1f;这一系列文章就是解决这个问题的#xff0c;所采用的开发环境及源码都是基于Android 1.6版… 在Android下查询联系人、通话记录等需要用到content provider。但是调用content provider时Android框架内部是如何做的呢这一系列文章就是解决这个问题的所采用的开发环境及源码都是基于Android 1.6版本。 概述 总的来说此问题分为两个步骤 初始化content provider。这一阶段主要是参照AndroidManifest.xml初始化content provider。注意这里只有当包含content provider的进程运行的时候才会对该进程内所有的content provider进行初始化。其它provider是按需初始化的后续文章会介绍该问题。 调用content provider进行数据库操作。这个调用通常发生在用户定义的Activity子类的相关接口内。调用时首先会获取对应的content provider对象有可能是代理对象。然后再调用直接调用或者通过IBinder接口。 本文主要探讨第一个问题初始化content provider。应用进程的管理模型 Android框架内应用程序Java代码的入口为ActivityThread.main。用来管理不同的应用的服务名称为activity。它的模型大致为 左边为多个应用进程每个进程中有个主线程ActivityThread.mainLooper.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 public static final IPackageManager main(Context context, boolean factoryTest) { PackageManagerService m new PackageManagerService(context, factoryTest); ServiceManager.addService(package, m); return m; } main方法主要是创建一个PackageManagerService然后注册到ServiceManager中名称为package”。PackageManagerService的构造函数中会去查找系统目录和应用目录下的apk文件以获取应用的包相关的信息比如包名称包含的Acvity、Provider等。 [java] view plaincopy // …… scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode); // …… scanDirLI(mAppInstallDir, 0, scanMode); // …… scanDirLI函数中对于每个package使用函数scanPackageLI解析其中的信息此处应该是读取AndroidManifest.xml。scanPackageLI检查相关信息后又会调用另一个scanPackageLI。这个函数内部会扫描到手机内所有的Provider信息 [java] view plaincopy PackageParser.Provider p pkg.providers.get(i); p.info.processName fixProcessName(pkg.applicationInfo.processName, p.info.processName, pkg.applicationInfo.uid); mProvidersByComponent.put(new ComponentName(p.info.packageName, p.info.name), p); mProvidersByComponent保存了所有的provider信息这部分数据源自于manifest。每个数据包含了PackageParser.Provider、包名称和Provider的类名。 到这里我们可以看到PackageManagerService真的是用来管理手机的应用包的。通过它可以知道所有的系统可用资源。当然这些资源只是一些静态信息。通过这些信息可以创建应用进程、初始化相关的Android组件。 应用进程的初始化 先看一下ActivityThread.main的实现它创建了一个ActivityThread对象初始化之后进入消息循环。 [java] view plaincopy public static final void main(String[] args) { // ...... ActivityThread thread new ActivityThread(); thread.attach(false); Looper.loop(); // ...... } attach函数中回去调用ActivityManagerService.attachApplication方法。 [java] view plaincopy mgr.attachApplication(mAppThread); 此时会进入ActivityManagerService的进程空间进入方法attachApplicationLocked它会去获取和当前客户端应用程序关联的Provider信息。 [java] view plaincopy List providers generateApplicationProvidersLocked(app); 根据上面的信息很容易知道此处是通过PackageManagerService获取Provider信息的。参数app表明只是取运行在该app内的Provider。根据Android的文档content provider必须在对应的AndroidManifest.xml中定义。默认情况下是运行在安装包名称命名的进程里面。你也可以在androidprocess属性中制定所属的进程名称。另一个重要的属性androidmultiprocess则可以指定provider的初始化方式是分散在调用端进程中从而避免进程间通信还是只初始化在某个进程内各个调用端只保留provider的代理。 随后通过下面的方法调用返回到应用程序的进程空间参数中包含了上面获得的providers。此处的thread实际上就是应用端的ApplicationThread对象。 [java] view plaincopy thread.bindApplication(processName, app.instrumentationInfo ! null ? app.instrumentationInfo : app.info, providers, app.instrumentationClass, app.instrumentationProfileFile, app.instrumentationArguments, app.instrumentationWatcher, testMode, 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 ListProviderInfo providers data.providers; if (providers ! null) { installContentProviders(app, providers); } 获取ActivityManagerService传递过来的provider信息并在本进程中初始化。具体的installContentProviders方法中会对每个provider调用installProvider方法 [java] view plaincopy IContentProvider cp installProvider(context, null, cpi, false); installProvider方法中主要是实例化Provider并保存到mProviderMap中 [java] view plaincopy final java.lang.ClassLoader cl c.getClassLoader(); localProvider (ContentProvider)cl. loadClass(info.name).newInstance(); provider localProvider.getIContentProvider(); // ...... // Cache the pointer for the remote provider. String names[] PATTERN_SEMICOLON.split(info.authority); for (int i0; inames.length; i) { ProviderRecord pr new ProviderRecord(names[i], provider, localProvider); try { provider.asBinder().linkToDeath(pr, 0); mProviderMap.put(names[i], pr); } catch (RemoteException e) { return null; } } 上面的installContentProviders方法执行完成之后会调用ActivityManagerService.publishContentProviders方法将provider注册到ActivityManagerService中方便其它应用进程获取。这里面有两个参数一个是ApplicationThread对象另一个是provider实例信息。 [java] view plaincopy try { ActivityManagerNative.getDefault().publishContentProviders( getApplicationThread(), results); } catch (RemoteException ex) { } 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