前往小程序,Get更优阅读体验!
立即前往
发布
社区首页 >专栏 >你真的懂ContentProvider么

你真的懂ContentProvider么

作者头像
老马的编程之旅
发布2022-06-22 14:57:17
发布2022-06-22 14:57:17
64100
代码可运行
举报
文章被收录于专栏:深入理解Android深入理解Android
运行总次数:0
代码可运行

启动性能 ContentProvider 的生命周期默认在 Application onCreate() 之前,而且都是在主线程创建的。我们自定义的 ContentProvider 类的构造函数、静态代码块、onCreate 函数都尽量不要做耗时的操作,会拖慢启动速度。

稳定性 ContentProvider 在进行跨进程数据传递时,利用了 Android 的 Binder 和匿名共享内存机制。

Binder 传递 CursorWindow 对象内部的匿名共享内存的文件描述符。 这样在跨进程传输中,**结果数据并不需要跨进程传输,而是在不同进程中通过传输的匿名共享内存文件描述符来操作同一块匿名内存,**这样来实现不同进程访问相同数据的目的

基于 mmap 的匿名共享内存机制也是有代价的。当传输的数据量非常小的时候,可能不一定划算。所以 ContentProvider 提供了一种 call 函数,它会直接通过 Binder 来传输数据。

ContentProvider 的接口调用参数和 call 函数调用并没有使用匿名共享机制,Binder有1024的限制,传输数据如果过大,就会抛出异常

安全性 虽然 ContentProvider 为应用程序之间的数据共享提供了很好的安全机制,但是如果 ContentProvider 是 exported,当支持执行 SQL 语句时就需要注意 SQL 注入的问题。另外如果我们传入的参数是一个文件路径,然后返回文件内容,这个时候也要校验合法性,不然整个应用的私有数据都有可能被别人拿到,在 Intent 传递参数的时候可能会经常会犯这个错误。

源码分析:

attachApplication 方法工作的第一部分就算是分析完了,该部分内容的主要工作是:通过 PMS 收集在 AndroidManifest 中注册的 ContentProvider 信息,将其封装成 ProviderInfo 集合。

将的 ProviderInfo 信息集合,作为参数远程调用 ApplicationThread 的 bindApplication 方法。此时将重新回到应用进程启动类 ActivityThread 中:

ApplicationThread 是 ActivityThread 与系统 PMS 进程通信的桥梁,它本质也是一个 Binder 对象。

代码语言:javascript
代码运行次数:0
复制
    public final void bindApplication(String processName, ApplicationInfo appInfo,
                                      List<ProviderInfo> providers, ...省略) {

        ... 省略

        //将返回数据都封装在AppBindData中
        AppBindData data = new AppBindData();
        data.processName = processName;
        data.appInfo = appInfo;
        //这是我们要跟踪的ContentProvider集合
        data.providers = providers;
        data.instrumentationName = instrumentationName;
        data.instrumentationArgs = instrumentationArgs;
        data.instrumentationWatcher = instrumentationWatcher;
        data.instrumentationUiAutomationConnection = instrumentationUiConnection;
        data.debugMode = debugMode;
        data.enableBinderTracking = enableBinderTracking;
        data.trackAllocation = trackAllocation;
        data.restrictedBackupMode = isRestrictedBackupMode;
        data.persistent = persistent;
        data.config = config;
        data.compatInfo = compatInfo;
        data.initProfilerInfo = profilerInfo;
        data.buildSerial = buildSerial;
        data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
        //发送BIND_APPLICATION消息到主线程Handler
        sendMessage(H.BIND_APPLICATION, data);
    }

在 bindApplication 方法发送 BIND_APPLICATION 消息到当前进程的主线程 Handler 中。

在分析 ContentProvider 的收集过程中,验证了自定义 ContentProvider 必须在 AndroidManifest.xml 注册,这里是在AMS里验证的

回到 ActivityThread 在 ApplicationThread 的 bindApplication 方法发送消息到主线程,此时来到 ActivityThread Handler 的 handleMessage 方法,先看下在 ActivityThread 中的声明:

代码语言:javascript
代码运行次数:0
复制
class H extends Handler {
    public static final int BIND_APPLICATION        = 110;
    public static final int EXIT_APPLICATION        = 111;
    public static final int RECEIVER                = 113;
    public static final int CREATE_SERVICE          = 114;
    public static final int SERVICE_ARGS            = 115;
    public static final int STOP_SERVICE            = 116;

    // 省略

    public void handleMessage(Message msg) {
        switch (msg.what) {
            //通过 ApplicationThread 发送的 BIND_APPLICATION
            case BIND_APPLICATION:
                AppBindData data = (AppBindData) msg.obj;
                //调用 handleBindApplication 开始真正创建 Application
                handleBindApplication(data);
                break;
                
                ...省略
        }
    }
}

handleBindApplication主要做了以下2个逻辑: 1.遍历 PMS 收集到的所有 ContentProvider 集合信息(ProviderInfo),并创建所有 ContentProvider 实例。回调其 onCreate 方法。 2.创建当前进程的 Application 对象,首先回调其 attach 方法,这步发生在遍历 ContentProvider 集合之前,创建每个 ContentProvider 并回调其 onCreate 方法之后,回调 Application 的 onCreate。

**ContentProvider 加载和创建都是在主线程完成,并且还都是在应用启动过程完成,**ContentProvider 的生命周期默认在 Application onCreate 之前。这也验证了文章开头为大家介绍的启动性能,在使用 ContentProvider 需要注意的“暗坑”,自定义 ContentProvider 类的构造函数、静态代码块、onCreate 函数都尽量不要做耗时的操作,会拖慢启动速度。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021-02-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档