Android ContentProvider启动流程源码解析(8.0)

来源:互联网 发布:日本原单淘宝店 编辑:程序博客网 时间:2024/06/10 23:05

一,写在前面

       在文章 Android 如何自定义一个ContentProvider中,介绍了如何使用以及自定义一个ContentProvider,本篇不再介绍如何使用ContentProvider访问其他应用的数据。在阅读本篇文章前,建议先了解Activity的启动流程,可参考文章 Android Activity的启动流程源码解析(8.0) ,将不再对重复的代码细节进行分析。


二,启动ContentProvider的入口

       如何启动一个ContentProvider呢?在一个Activity类中,可以调用getContentResolver().query(...)查询指定uri对应的数据,在这个过程中若ContentProvider没有启动,则会启动ContentProvider。当然,相应的insert,delete,update方法也可以启动ContentProvider,本篇文章以query方法为例进行分析。
       获取ContentResolver的对象,实际上调用的是ContextWrapper$getContentResolver方法,ContextWrapper是抽象类Context的一个子类。 
       查看ContextWrapper$getContentResolver方法源码:
    @Override    public ContentResolver getContentResolver() {        return mBase.getContentResolver();    }
       第3行,变量mBase对应的是ContextImpl对象,分析见Android Activity的启动流程源码解析(8.0) ,这里不再重复阐述。
       
      查看ContextImpl$getContentResolver方法源码:
    @Override    public ContentResolver getContentResolver() {        return mContentResolver;    }
       第3行,变量mContentResolver的初始化在ContextImpl的构造函数中完成,mContentResolver = new ApplicationContentResolver(this, mainThread, user),也就是返回的是ApplicationContentResolver的实例。值得一提的是,ContextImpl对象的创建是在启动Activity的流程中完成,具体分析见 Android Activity的启动流程源码解析(8.0) ,这里不再重复阐述。

       ApplicationContentResolver是ContextImpl的一个内部类,且继承类ContentResolver。调用getContentResolver().query(...)方法,是从父类ContentResolver继承的query方法。
       查看ContentResolver$query方法源码:
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,            @Nullable String[] projection, @Nullable String selection,            @Nullable String[] selectionArgs, @Nullable String sortOrder,            @Nullable CancellationSignal cancellationSignal) {        //...    IContentProvider unstableProvider = acquireUnstableProvider(uri);    if (unstableProvider == null) {                 return null;            }        //...    qCursor = unstableProvider.query(mPackageName, uri, projection,                        selection, selectionArgs, sortOrder, remoteCancellationSignal);        //...}
       第8行,获取一个IContentProvider类型的对象unstableProvider。启动ContentProvider从这里开始分析,后面会详细分析。
       第9行,对变量unstableProvider进行判空检查;
       第15行,根据指定uri,执行查询数据操作,文章的最后会详细分析

       查看ContentResolver$acquireUnstableProvider方法(一个参数)源码:
public final IContentProvider acquireUnstableProvider(Uri uri) {        if (!SCHEME_CONTENT.equals(uri.getScheme())) {            return null;        }        String auth = uri.getAuthority();        if (auth != null) {            return acquireUnstableProvider(mContext, uri.getAuthority());        }        return null;}
       第2行,对uri的scheme进行检查;
       第7行,逻辑跳到ApplicationContentResolver$acquireUnstableProvider方法(两个参数);

       查看ApplicationContentResolver$acquireUnstableProvider方法源码:
@Overrideprotected IContentProvider acquireUnstableProvider(Context c, String auth) {    return mMainThread.acquireProvider(c,    ContentProvider.getAuthorityWithoutUserId(auth),    resolveUserIdFromAuthority(auth), false);}
       第3行,变量mMainThread是一个ActivityThread类型的对象,该变量的初始化也是在ContextImpl的构造函数中完成。

       查看ActivityThread$acquireProvider方法源码:
    public final IContentProvider acquireProvider(            Context c, String auth, int userId, boolean stable) {        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);        if (provider != null) {            return provider;        }        ContentProviderHolder holder = null;        //...        holder = ActivityManager.getService().getContentProvider(                    getApplicationThread(), auth, userId, stable);        //...        holder = installProvider(c, holder, holder.info,                true /*noisy*/, holder.noReleaseNeeded, stable);        return holder.provider;    }
       第3行,调用ActivityThread$acquireExistingProvider方法,查询Map集合中是否包含该IContextProvider对象,下面会具体分析。
       第4行,若provider不为null,表示该IContextProvider对象已经存在,无需再创建。
       第11行,若provider为null,那么需要创建一个IContextProvider对象。这里就是启动ContentProvider流程的入口,后面会重点具体分析。
       第16行,将11行创建的IContextProvider对象存储在一个Map集合中,起到一个缓存的作用,不用每次创建IContextProvider对象。

       分析ActivityThread$acquireProvider方法的第3行,查看ActivityThread$acquireExistingProvider方法源码:
public final IContentProvider acquireExistingProvider(            Context c, String auth, int userId, boolean stable) {    synchronized (mProviderMap) {        final ProviderKey key = new ProviderKey(auth, userId);        final ProviderClientRecord pr = mProviderMap.get(key);        if (pr == null) {    return null;        }            IContentProvider provider = pr.mProvider;//...return provider;    }      }
       第4行,将参数auth封装在ProviderKey对象中,并作为Map集合的key;
       第5行,变量mProviderMap的初始化:final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap = new ArrayMap<ProviderKey, ProviderClientRecord>();当Map集合中不存在该key时,就会返回null。


三,启动ContentProvider,交给AMS处理

       前面已经提到,ActivityThread$acquireProvider方法的第11行是启动ContentProvider的入口。
       第11行代码:holder = ActivityManager.getService().getContentProvider(getApplicationThread(), auth, userId, stable)。ActivityManager.getService()这个已经再熟悉不过了,基于Binder机制,最终会调用系统服务ActivityManagerService$getContentProvider方法。具体分析见文章 Android Activity的启动流程源码解析(8.0) ,这里不再重复阐述。
        查看ActivityManagerService$getContentProvider方法源码:
    @Override    public final ContentProviderHolder getContentProvider(            IApplicationThread caller, String name, int userId, boolean stable) {        //...        return getContentProviderImpl(caller, name, null, stable, userId);    }    //继续查看...    private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,            String name, IBinder token, boolean stable, int userId) {        //...ProcessRecord proc = getProcessRecordLocked(cpi.processName, cpr.appInfo.uid, false);if (proc != null && proc.thread != null && !proc.killed) {    if (!proc.pubProviders.containsKey(cpi.name)) {//...proc.thread.scheduleInstallProvider(cpi);//...    }} else {             //...    proc = startProcessLocked(cpi.processName,    cpr.appInfo, false, 0, "content provider",    new ComponentName(cpi.applicationInfo.packageName,    cpi.name), false, false, false);        //...}           //...code            }
       第17行,ProcessRecord封装了ContentProvider所在应用程序进程的相关信息;
       第25行,若应用程序进程已经启动,则调用scheduleInstallProvider方法,启动ContentProvider;
       第33行,若应用程序进程没有启动,则调用AMS$startProcessLocked方法启动进程。本篇文章假设应用程序进程没有启动,来研究ContentProvider的启动流程,下面会重点分析这里。


四,入口ActivityThread$main的分析

       为什么要分析应用程序进程的启动呢?因为应用程序进程启动后,接着启动ContentProvider。进程启动是交给ActivityManagerService$startProcessLocked方法来处理,最终会调用ActivityThread$main方法(ActivityThread是代表主线程的实例)。这里推荐一篇博客 Android应用程序进程启动过程 ,文章详细讲解了进程的启动流程。
       
       下面继续分析ActivityThread$main方法,这个方法很重要。想要完全理解Handler机制,了解main方法也是必须的,下面会讲述一些篇外话。
       ActivityThread$main方法查看源码:
public static void main(String[] args) {        //...        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }//...        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");}
       第5行,创建Looper对象,并将该对象放入ThreadLocal中。
       简单介绍下ThreadLocal:可以使某一个变量在不同线程代表不同的值。在这里用于存放主线程ActivityThread中创建的Looper,当然子线程也可以创建自己的Looper,但不同线程的Looper并不是一个对象。
       值得一提的:调用Looper.prepareMainLooper()方法专门用于创建主线程的Looper对象,在子线程中创建Looper对象也比较熟悉了,一般调用Looper.prepare()方法。当然这两种方式创建Looper是有区别,区别在于主线程的Looper不被允许停掉,具体代码细节分析留给感兴趣哥们验证~

       第7行,创建ActivityThread的实例;
       第8行,调用ActivityThread$attach方法,内部完成ContentProvider的启动过程,后面会重点分析
       第16行,进行消息循环的操作,内部有一个无限for循环,不断的获取Message对象且处理消息。
       第18行,该行代码被执行的前提是:Looper$loop方法跳出无限for循环。因此需要调用Looper$quit方法停掉Looper,前面已经讲到主线程的Looper不会被停掉。由于不是本篇重点,具体的代码细节不做阐述,这里直接给出结论。也就是说,抛出RuntimeException这个异常还是比较少见的,Android系统也不支持这样做。

       回到ActivityThread$attach方法的调用,它会启动ContentProvider,下面继续分析。
       查看ActivityThread$attach方法源码:
private void attach(boolean system) {//...final IActivityManager mgr = ActivityManager.getService();//...mgr.attachApplication(mAppThread);//...}
       第5行,返回一个IActivityManager接口的代理对象,这个应该比较熟悉了,具体分析可以参考文章 Android Activity的启动流程源码解析(8.0) ;
       第9行,向系统服务AMS发起请求,基于Binder机制,回调用ActivityManagerService$attachApplication方法;变量mAppThread是一个ApplicationThread类型的变量,这个也比较熟悉了,具体分析可以参考文章 Android Activity的启动流程源码解析(8.0) ;

       查看ActivityManagerService相关方法的源码:
public final void attachApplication(IApplicationThread thread) {        synchronized (this) {            //...            attachApplicationLocked(thread, callingPid);                //...        }}//继续查看...private final boolean attachApplicationLocked(IApplicationThread thread,            int pid) {//...thread.bindApplication(processName, appInfo, providers,                        app.instr.mClass,                        profilerInfo, app.instr.mArguments,                        app.instr.mWatcher,                        app.instr.mUiAutomationConnection, testMode,                        mBinderTransactionTrackingEnabled, enableTrackAllocation,                        isRestrictedBackupMode || !normalMode, app.persistent,                        new Configuration(getGlobalConfiguration()), app.compat,                        getCommonServicesLocked(app.isolated),                        mCoreSettingsObserver.getCoreSettingsLocked(),                        buildSerial);//...}
       第17行,变量thread是一个ApplicationThread的对象,调用bindApplication方法完成一次IPC的调用,代码逻辑切换到ApplicationThread中去执行。这个应该比较熟悉了,具体分析可以参考文章 Android Activity的启动流程源码解析(8.0) ,这里不再重复阐述。

       查看ActivityThread$ApplicationThread$bindApplication方法源码:
public final void bindApplication(String processName, ApplicationInfo appInfo,                List<ProviderInfo> providers, ComponentName instrumentationName,                ProfilerInfo profilerInfo, Bundle instrumentationArgs,                IInstrumentationWatcher instrumentationWatcher,                IUiAutomationConnection instrumentationUiConnection, int debugMode,                boolean enableBinderTracking, boolean trackAllocation,                boolean isRestrictedBackupMode, boolean persistent, Configuration config,                CompatibilityInfo compatInfo, Map services, Bundle coreSettings,                String buildSerial) {    //...    AppBindData data = new AppBindData();            data.processName = processName;            data.appInfo = appInfo;            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;            sendMessage(H.BIND_APPLICATION, data);}
       第13行,创建AppBindData对象,用于封装一些数据。
       第30行,ActivityThread$sendMessage方法的内部代码不再展示。具体来说,使用Handler发送了一个消息,基于Handler的消息机制,将任务切换到Handler所在的线程中执行,于是任务切换到ActivityThread中执行。
       我们会发现,Android四大组件的启动,代码逻辑由系统服务AMS切换到ApplicationThread,然后基于Handler的消息机制,最终切换到主线程ActivityThread中执行。
    
       继续分析消息的处理过程,查看ActivityThread$H$handleMessage方法源码:
public void handleMessage(Message msg) {    switch (msg.what) {//...case BIND_APPLICATION:    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");    AppBindData data = (AppBindData)msg.obj;    handleBindApplication(data);    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);    break;   //...    }}
       第9行,调用ActivityThread$handleBindApplication方法;

       查看ActivityThread$handleBindApplication方法源码:
private void handleBindApplication(AppBindData data) {//...final ContextImpl instrContext = ContextImpl.createAppContext(this, pi);//..final ClassLoader cl = instrContext.getClassLoader();        mInstrumentation = instantiate(cl, data.instrumentationName.getClassName(),                instrContext, Application::instantiateInstrumentation);//..Application app = data.info.makeApplication(data.restrictedBackupMode, null);//...installContentProviders(app, data.providers);//...mInstrumentation.callApplicationOnCreate(app);//...}
       handleBindApplication做的事情,有些跟启动Activity的流程比较类似,类似的代码细节就不再重复分析了。
       第5行,创建上下文环境,具体来说是创建ContextImpl对象;
       第10行,获取Instrumentation类型的对象;
       第15行,创建Application对象,由于第2个参数为null,不会调用Application$onCreate方法;
       第19行,调用ctivityThread$installContentProviders方法,启动ContentProvider,后面会重点分析
       第23行,Instrumentation$callApplicationOnCreate方法内部,会调用Application$onCreate方法,意味着应用程序进程启动完毕。
       
       查看ActivityThread$installContentProviders方法源码:
    private void installContentProviders(            Context context, List<ProviderInfo> providers) {        final ArrayList<ContentProviderHolder> results = new ArrayList<>();        for (ProviderInfo cpi : providers) {            if (DEBUG_PROVIDER) {                StringBuilder buf = new StringBuilder(128);                buf.append("Pub ");                buf.append(cpi.authority);                buf.append(": ");                buf.append(cpi.name);                Log.i(TAG, buf.toString());            }            ContentProviderHolder cph = installProvider(context, null, cpi,                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);                //...        }//...    }
       第2行,集合providers中存储了应用程序进程中所有的ProviderInfo对象,ProviderInfo封装了ContentProvider相关的信息。
       第5行,遍历集合providers;
       第14行,调用ActivityThread$installProvider方法,ProviderInfo对象作为方法的参数,启动ContentProvider;

       查看ActivityThread$installProvider方法源码:
private ContentProviderHolder installProvider(Context context,            ContentProviderHolder holder, ProviderInfo info,            boolean noisy, boolean noReleaseNeeded, boolean stable) {ContentProvider localProvider = null;        IContentProvider provider;//..final java.lang.ClassLoader cl = c.getClassLoader();localProvider = instantiate(cl, info.name, context,Application::instantiateProvider);//...localProvider.attachInfo(c, info);//...    }
       第10行,通过ClassLoader创建ContentProvider的实例;
       第15行,调用ContentProvider$attachInfo方法启动ContentProvider;
       
       查看ContentProvider$attachInfo方法源码:
public void attachInfo(Context context, ProviderInfo info) {        attachInfo(context, info, false);}//继续查看...private void attachInfo(Context context, ProviderInfo info, boolean testing) {        //...        if (mContext == null) {                // ...            ContentProvider.this.onCreate();        }}
       第15行,哇,调用了ContentProvider$onCreate方法,意味着ContentProvider已经启动了。

五,ContentProvider启动后,分析query的流程

       前面分析了ContentProvider的启动流程,下面继续分析query的流程。回到ContentResolver$query方法,该方法内部调用了IContentProvider$query方法。
       查看IContentProvider源码:
public interface IContentProvider extends IInterface {    //...    public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,             @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)             throws RemoteException;    public String getType(Uri url) throws RemoteException;    public Uri insert(String callingPkg, Uri url, ContentValues initialValues)            throws RemoteException;    public int bulkInsert(String callingPkg, Uri url, ContentValues[] initialValues)            throws RemoteException;    public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)            throws RemoteException;    public int update(String callingPkg, Uri url, ContentValues values, String selection,            String[] selectionArgs) throws RemoteException;    //...}
       原来,IContentProvider是一个接口,还继承了IInterface接口。有意思的是,在AIDL文件自动生成的java文件中,可以找到一样的结构。但这里并没有类似于Stub的类,在源码中search "extends Binder implements IContentProvider",这个相当于Stub的类就是ContentProviderNative。

       查看ContentProviderNative源码:
abstract public class ContentProviderNative extends Binder implements IContentProvider {    public ContentProviderNative()    {        attachInterface(this, descriptor);    }    static public IContentProvider asInterface(IBinder obj)    {        if (obj == null) {            return null;        }        IContentProvider in =            (IContentProvider)obj.queryLocalInterface(descriptor);        if (in != null) {            return in;        }        return new ContentProviderProxy(obj);    }    @Override    public boolean onTransact(int code, Parcel data, Parcel reply, int flags)            throws RemoteException {        try {            switch (code) {                case QUERY_TRANSACTION:                {                    //...                    Cursor cursor = query(callingPkg, url, projection, queryArgs, cancellationSignal);                        //...code                }return super.onTransact(code, data, reply, flags);    }    //...code    @Override    public IBinder asBinder()    {        return this;    }    final class ContentProviderProxy implements IContentProvider    {    public ContentProviderProxy(IBinder remote)            {                 mRemote = remote;            }    @Override    public IBinder asBinder()    {        return mRemote;    }    @Override    public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,    @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)    throws RemoteException {BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();//...code    mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);    //...code    }//...code        }    //...code    }
       哇~这个结构是不是似曾相识,类ContentProviderNative相当于Stub类。接下来,需要找到接口的实现类,源码中search "extends ContentProviderNative ",这个实现类就是ContentProvider的内部类Transport。

       查看ContentProvider$Transport$query源码:
class Transport extends ContentProviderNative {//...        @Override        public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,                @Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {//...return ContentProvider.this.query(                        uri, projection, queryArgs,                        CancellationSignal.fromTransport(cancellationSignal));//...}        //...}
       第11行,哇,最终调用了ContentProvider的query方法,这个不就是我们想要的嘛。这也验证访问ContentProvider的数据,是基于Binder机制完成了一次进程间的通信。
       值得一提的是理解这个流程,需要对AIDL文件生成的java文件有比较好的认识,由于不是本篇重点,这里不进行阐述。

六,最后

       本篇文章分两部分进行,前面一部分,用大量篇幅分析ContentProvider的启动过程,这也是本篇文章的重点;后面一部分,以查询数据为例,分析其他应用是如何访问ContentProvider暴露的数据。相信通过上面的分析,应该对ContentProvider的工作流程有比较好的认识了。同时,本篇文章到这里就结束啦~        ^_^