ContentProvider启动过程and多进程调用全过程源码详解

本文详细分析了ContentProvider的启动过程,包括通过getContentResolver操作ContentProvider,从ContextWrapper到ContextImpl,再到ApplicationContentResolver的创建。通过源码跟踪,解释了ContentResolver如何获取IContentProvider对象,涉及AMS、ActivityThread、进程创建等多个环节,揭示了ContentProvider跨进程调用的原理。
摘要由CSDN通过智能技术生成

之前有两篇文章分别说了应用的启动过程(Activity)插件化知识详细分解及原理 之应用的启动过程和Service的启动过程Service启动过程and新进程创建全过程源码分析这里涉及了多进程调用的关系,建议先看这两篇。今天来说一下ContentProvider的启动过程及都进程调用过程,至于ContentProvider如何使用就不说了。下面进入正题

首先我们知道如果我们要操作ContentProvider的话是通过getContentResolver来操作的,通常我们使用一般是这样的

//指定uri
Uri uri = Uri.parse("content://xxxxx");
//准备数据
ContentValues values = new ContentValues();
values.put("xx","xx");
//对该uri匹配的Provider进行处理
    //插入
 getContentResolver().insert(uri,values);
    //查询
 getContentResolver().query(uri,new String[]{
  "xx"},null,null,null);
    //删除
 getContentResolver().delete(uri,"id=?",new String[]{
  "1"});
    //修改
 getContentResolver().update(uri,values,"id=?",new String[]{
  "1"});

1、那么我们就从这里开始,那么我们先要去看一下getContentResolver()的代码了

public class ContextWrapper extends Context {
   

    Context mBase;

    public ContextWrapper(Context base) {
        mBase = base;
    }

    @Override
    public ContentResolver getContentResolver() {
        //调用了Context的getContentResolver方法
        return mBase.getContentResolver();
    }
}

2、我们发现点进去后进入到了ContextWrapper 中,然后又调用了Context的getContentResolver()方法,而我们之前的文章都分析过了Context的实现类是ContextImpl,那么我们直接去看ContextImpl中的getContentResolver方法,而Context是在哪里初始化被创建的都在Service启动过程and新进程创建全过程源码分析文章中有分析。
源码路径:
/frameworks/base/core/java/android/app/ContextImpl.java

class ContextImpl extends Context {
   
    ....
    //mContentResolver成员变量
    private final ApplicationContentResolver mContentResolver;

    ....

    //构造方法
    private ContextImpl(ContextImpl container, ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
            Display display, Configuration overrideConfiguration) {

        ....
        构造方法中创建了ApplicationContentResolver,注意第二个参数,这是ActivityThread类型,这里是调用者的ActivityThread哦!!
        mContentResolver = new ApplicationContentResolver(this, mainThread, user);

        ....

    }
    @Override
    public ContentResolver getContentResolver() {
    //返回了ApplicationContentResolver
        return mContentResolver;
    }
}

3、在ContextImpl的getContentResolver方法中返回了一个ApplicationContentResolver类型的对象,这个对象在ContextImpl的构造方法中初始化,这个类是ContextImpl的内部类,它继承于ContentProvider

 private static final class ApplicationContentResolver extends ContentResolver {
   
    .....
 }

4、到这里我们知道了getContentResolver()方法返回的是ContextImpl中的内部类ApplicationContentResolver 对象,这个对象在ContextImpl的构造方法中被初始化,创建的时候需要依赖调用者进程的ActivityThread,这里我们只跟踪一个query方法,因为系统给我们本来就提供了很多的Provider使用,但是我们并不知道它是怎么被运行的,所有我们通过这个方法来进行分析。因为返回的是ApplicationContentResolver 的对象,本来我们查看它的query方法就可以了,但是ApplicationContentResolver 并没有重写ContentResolver中的query、insert、delete、update方法,那么我们还是要去看ContentResolver中的方法
源码路径:
/frameworks/base/core/java/android/content/ContentResolver.java

    public final Cursor query(Uri uri, String[] projection,
            String selection, String[] selectionArgs, String sortOrder) {
            //直接又调用了6个参数的query方法
        return query(uri, projection, selection, selectionArgs, sortOrder, null);
    }

5、上面直接又调用了6个参数的query方法,我们来看一下

    public final Cursor query(final Uri uri, String[] projection,
            String selection, String[] selectionArgs, String sortOrder,
            CancellationSignal cancellationSignal) {

        //1、获取IContentProvider接口对象
        IContentProvider unstableProvider = acquireUnstableProvider(uri);
        if (unstableProvider == null) {
            return null;
        }

        IContentProvider stableProvider = null;
        Cursor qCursor = null;
        try {
            ....
            try {
                //2、通过获取的IContentProvider查询数据,并返回Cursor对象,在这里会线程阻塞,至于为什么接着往下看
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            } catch (DeadObjectException e) {
                //在第2步调用过程中,远程进程已经死亡,试图恢复连接
                unstableProviderDied(unstableProvider);
                //连接后重新获取provider
                stableProvider = acquireProvider(uri);
                if (stableProvider == null) {
                    return null;
                }
                //然后再次查询
                qCursor = stableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            }
            if (qCursor == null) {
                return null;
            }

            // Force query execution.  Might fail and throw a runtime exception here.
            qCursor.getCount();
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);

            // 将返回的Cursor对象包装成CursorWrapperInner
            CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
                    stableProvider != null ? stableProvider : acquireProvider(uri));
            stableProvider = null;
            qCursor = null;
            return wrapper;
        } catch (RemoteException e) {
            return null;
        } finally {
            if (qCursor != null) {
                qCursor.close();
            }
            if (cancellationSignal != null) {
                cancellationSignal.setRemote(null);
            }
            if (unstableProvider != null) {
                releaseUnstableProvider(unstableProvider);
            }
            if (stableProvider != null) {
                releaseProvider(stableProvider);
            }
        }
    }

6、从查询到返回结果一共有3步,我们总结一下,然后一会再一一的分析

1。首先通过acquireUnstableProvider方法获取了IContentProvider对象,这里会线程阻塞,等待返回IContentProvider,为什么请接着看
2。通过调用返回的IContentProvider对象调用该对象的query方法,这里有两种情况,一种是正常调用成功并返回Cursor对象,另一种是调用过程中远程对象死亡然后捕获异常后再次重新尝试连接后再调用query方法。
3。将返回的Cursor对象进行包装,包装成CursorWrapperInner类型后返回给调用者。

上面三步走完就获取到了provider中的数据,这里最重要要看一下acquireUnstableProvider是如果取到了IContentProvider接口对象

6.1.1、首先通过acquireUnstableProvider方法获取了IContentProvider对象,注意,现在还是在ContentResolver中,看代码

    //常量
    public
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值