ContentProvider启动过程与多进程调用

getContentResolver()

我们在Application或者Activity里调用bindService()的时候,其实调用的是Context中的抽象方法:

public abstract ContentResolver getContentResolver();
复制代码

真正的是现在ContextImpl中:

private final ApplicationContentResolver mContentResolver;
...
private ContextImpl(ContextImpl container, ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, UserHandle user, int flags,
            Display display, Configuration overrideConfiguration, int createDisplayWithId) {
    ...
    mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
...
@Override
public ContentResolver getContentResolver() {
    return mContentResolver;
}
复制代码

在构造方法中通过ActivityThread构造了ApplicationContentResolver类型的对象。这个对象是ActivityThread和UserHandle的包装类。

private static final class ApplicationContentResolver extends ContentResolver {
    private final ActivityThread mMainThread;
    private final UserHandle mUser;
    ...
}
复制代码

获取到ContentResolver之后就可以进行query、insert、delete、update操作。

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);
            }
        }
    }
复制代码

通过acquireUnstableProvider方法获取了IContentProvider对象:

//常量
    public static final String SCHEME_CONTENT = "content";

    //获取IContentProvider    
    public final IContentProvider acquireUnstableProvider(Uri uri) {
    //这里判断uri的scheme是否是content,就是我们写的uri是否是以
    //content://开头的
        if (!SCHEME_CONTENT.equals(uri.getScheme())) {
            return null;
        }
        //判断authorities是否为空
        String auth = uri.getAuthority();
        if (auth != null) {
            //如果不为空直接return了acquireUnstableProvider方法
            return acquireUnstableProvider(mContext, uri.getAuthority());
        }
        return null;
    }
复制代码

看看acquireUnstableProvider()方法实现:

protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
复制代码

是抽象方法,具体实现在刚刚创建的ApplicationContentResolver:

@Override
        protected IContentProvider acquireUnstableProvider(Context c, String auth) {
            return mMainThread.acquireProvider(c,
                    ContentProvider.getAuthorityWithoutUserId(auth),
                    resolveUserIdFromAuthority(auth), false);
        }
复制代码

看看ActivityThread中的具体实现:

public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {

        //1.查看是否有缓存的IContentProvider,命中直接返回
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            return provider;
        }

        //通过AMS获取了被调用provider的信息

        IActivityManager.ContentProviderHolder holder = null;
        try {
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), auth, userId, stable);
        } catch (RemoteException ex) {
        }
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + auth);
            return null;
        }

        // 加载provider并保存
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);

        //返回holder.provider     
        return holder.provider;
    }
复制代码

ActivityManagerNative.getDefault()返回的是AMS的代理类,最终会通过BInder机制调用到AMS:

@Override
    public final ContentProviderHolder getContentProvider(
            IApplicationThread caller, String name, int userId, boolean stable) {
            //如果IApplicationThread 为空直接抛异常了
        enforceNotIsolatedCaller("getContentProvider");
        if (caller == null) {
            String msg = "null IApplicationThread when getting content provider "
                    + name;
            Slog.w(TAG, msg);
            throw new SecurityException(msg);
        }
        //返回getContentProviderImpl方法
        return getContentProviderImpl(caller, name, null, stable, userId);
    }
复制代码

在AMS中,看getContentProviderImpl方法:

private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, boolean stable, int userId) {
        //用来保存provider的信息   
        ContentProviderRecord cpr;
        ContentProviderConnection conn = null;      
        ProviderInfo cpi = null;

        synchronized(this) {
            long startTime = SystemClock.elapsedRealtime();

            //获取调用者的进程信息
            ProcessRecord r = null;
            if (caller != null) {
                r = getRecordForAppLocked(caller);
                if (r == null) {
                    throw new SecurityException(
                            "Unable to find app for caller " + caller
                          + " (pid=" + Binder.getCallingPid()
                          + ") when getting content provider " + name);
                }
            }

            boolean checkCrossUser = true;

            checkTime(startTime, "getContentProviderImpl: getProviderByName");

            // 查看provider信息是否被加载过,是否存在缓存
            cpr = mProviderMap.getProviderByName(name, userId);
            // If that didn't work, check if it exists for user  and then
            // verify that it's a singleton provider before using it.
            if (cpr == null && userId != UserHandle.USER_OWNER) {
                cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
                if (cpr != null) {
                    cpi = cpr.info;
                    if (isSingleton(cpi.processName, cpi.applicationInfo,
                            cpi.name, cpi.flags)
                            && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
                        userId = UserHandle.USER_OWNER;
                        checkCrossUser = false;
                    } else {
                        cpr = null;
                        cpi = null;
                    }
                }
            }
            //这里如果是第一次调用肯定是不会命中缓存
            boolean providerRunning = cpr != null;

            if (providerRunning) {
                //如果命中缓存
                cpi = cpr.info;
                String msg;
                checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
                if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
                        != null) {
                    throw new SecurityException(msg);
                }
                checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");

                //判断provider的multiprocess是否为true,如果是true,provider则会在调用者的进程中初始化,
                //multiprocess默认为false,默认系统只有一个该provider
                if (r != null && cpr.canRunHere(r)) {

                    ContentProviderHolder holder = cpr.newHolder(null);                 
                    holder.provider = null;
                    return holder;
                }

               ....
            }

            boolean singleton;
            //没有命中缓存
            if (!providerRunning) {
                try {
                    checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");

                    //通过PackageManagerService得到provider所在应用程序的信息

                    cpi = AppGlobals.getPackageManager().
                        resolveContentProvider(name,
                            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
                    checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
                } catch (RemoteException ex) {
                }
                if (cpi == null) {
                    return null;
                }
                .....

                //检查权限
                if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
                        != null) {
                    throw new SecurityException(msg);
                }

                ....

                ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                checkTime(startTime, "getContentProviderImpl: before getProviderByClass");

                //判断provider这个类是否是第一次加载
                cpr = mProviderMap.getProviderByClass(comp, userId);
                checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
                final boolean firstClass = cpr == null;
                if (firstClass) {
                    final long ident = Binder.clearCallingIdentity();
                    try {
                        checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");

                        //获取provider的Application信息
                        ApplicationInfo ai =
                            AppGlobals.getPackageManager().
                                getApplicationInfo(
                                        cpi.applicationInfo.packageName,
                                        STOCK_PM_FLAGS, userId);
                        checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
                        if (ai == null) {
                            Slog.w(TAG, "No package info for content provider "
                                    + cpi.name);
                            return null;
                        }
                        ai = getAppInfoForUser(ai, userId);
                        //创建provider的信息
                        cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                    } catch (RemoteException ex) {
                        // pm is in same process, this will never happen.
                    } finally {
                        Binder.restoreCallingIdentity(ident);
                    }
                }

                checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");

                //判断provider的multiprocess是否为true,如果是true,provider则会在调用者的进程中初始化,
                //multiprocess默认为false,默认系统只有一个该provider
                if (r != null && cpr.canRunHere(r)) {
                    // If this is a multiprocess provider, then just return its
                    // info and allow the caller to instantiate it.  Only do
                    // this if the provider is the same user as the caller's
                    // process, or can run as root (so can be in any process).
                    return cpr.newHolder(null);
                }

                if (DEBUG_PROVIDER) {
                    RuntimeException e = new RuntimeException("here");
                    Slog.w(TAG, "LAUNCHING REMOTE PROVIDER (myuid " + (r != null ? r.uid : null)
                          + " pruid " + cpr.appInfo.uid + "): " + cpr.info.name, e);
                }
                //因为multiprocess所以会继续走到这里,系统中所有的provider都会存储在mLaunchingProviders
                //的ArrayList中,以为默认系统只能有一个该provider的实例,这里是看一下是否有其他的应用已经
                //实例了该provider,如果是肯定会存在mLaunchingProviders,那么i也就肯定小于N
                final int N = mLaunchingProviders.size();
                int i;
                for (i=; i= N) {
                    final long origId = Binder.clearCallingIdentity();

                    try {
                        ....
                        //查看provider所属进程是否已经存在
                        ProcessRecord proc = getProcessRecordLocked(
                                cpi.processName, cpr.appInfo.uid, false);

                        //判断该进程是否已经启动了      
                        if (proc != null && proc.thread != null) {
                            if (DEBUG_PROVIDER) {
                                Slog.d(TAG, "Installing in existing process " + proc);
                            }
                            checkTime(startTime, "getContentProviderImpl: scheduling install");
                            proc.pubProviders.put(cpi.name, cpr);
                            try {
                                //使用ApplicationThread发送一条消息,加载provider,一会再分析
                                proc.thread.scheduleInstallProvider(cpi);
                            } catch (RemoteException e) {
                            }
                        } else {
                            //如果进程没有创建则创建一个新的进程

                            proc = startProcessLocked(cpi.processName,
                                    cpr.appInfo, false, , "content provider",
                                    new ComponentName(cpi.applicationInfo.packageName,
                                            cpi.name), false, false, false);

                            if (proc == null) {
                                Slog.w(TAG, "Unable to launch app "
                                        + cpi.applicationInfo.packageName + "/"
                                        + cpi.applicationInfo.uid + " for provider "
                                        + name + ": process is bad");
                                return null;
                            }
                        }
                        //将该provider的信息保存到mLaunchingProviders中
                        cpr.launchingApp = proc;
                        mLaunchingProviders.add(cpr);
                    } finally {
                        Binder.restoreCallingIdentity(origId);
                    }
                }

                checkTime(startTime, "getContentProviderImpl: updating data structures");


                //存入provider的信息
                if (firstClass) {
                    mProviderMap.putProviderByClass(comp, cpr);
                }

                mProviderMap.putProviderByName(name, cpr);
                conn = incProviderCountLocked(r, cpr, token, stable);
                if (conn != null) {
                    conn.waiting = true;
                }
            }
        }

       .....
        //返回provider的信息封装成ContentProviderHolder返回
        return cpr != null ? cpr.newHolder(conn) : null;
    }
复制代码
  • 首先判断了被调用的provider是否之前已经存在,然后判断了multiprocess属性是否为true,如果为true将允许在调用者的进程中实例该provider,还判断了该provider所属进程是否已经被创建,如果创建直接使用ApplicationThread发送消息加载provider,如果没有创建则先创建一个进程
  • 创建新进程调用了AMS中的方法startProcessLocked
  • 真正创建进程的是通过Process的start的方法
  • 创建被创建后会调用该进程的ActivityThread的main方法
  • 然后接着调用ActivityThread.attach方法
  • 在attach中会调用ActivityManagerService.attachApplication
  • 在AMS的attachApplication方法中会获取需要在本进程中加载的provider,
  • AMS会调用ActivityThread.bindApplication方法
  • bindApplication方法中会发送一个消息到ActivityThread中的Handler里
  • ActivityThread中的Handler中调用了 handleBindApplication,我们从这里开始
private void handleBindApplication(AppBindData data) {

        ....

    //创建上下文对象
    final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);

        ....

        //准备初始化的数据
        if (data.instrumentationName != null) {
            InstrumentationInfo ii = null;
            try {
                ii = appContext.getPackageManager().
                    getInstrumentationInfo(data.instrumentationName, );
            } catch (PackageManager.NameNotFoundException e) {
            }
            if (ii == null) {
                throw new RuntimeException(
                    "Unable to find instrumentation info for: "
                    + data.instrumentationName);
            }

            mInstrumentationPackageName = ii.packageName;
            mInstrumentationAppDir = ii.sourceDir;
            mInstrumentationSplitAppDirs = ii.splitSourceDirs;
            mInstrumentationLibDir = ii.nativeLibraryDir;
            mInstrumentedAppDir = data.info.getAppDir();
            mInstrumentedSplitAppDirs = data.info.getSplitAppDirs();
            mInstrumentedLibDir = data.info.getLibDir();

            //准备创建Application的数据
            ApplicationInfo instrApp = new ApplicationInfo();
            instrApp.packageName = ii.packageName;
            instrApp.sourceDir = ii.sourceDir;
            instrApp.publicSourceDir = ii.publicSourceDir;
            instrApp.splitSourceDirs = ii.splitSourceDirs;
            instrApp.splitPublicSourceDirs = ii.splitPublicSourceDirs;
            instrApp.dataDir = ii.dataDir;
            instrApp.nativeLibraryDir = ii.nativeLibraryDir;
            //LoadedApk对象是APK文件在内存中的表示。 //Apk文件的相关信息,诸如Apk文件的代码和资源,甚至代码里面的Activity,Service等四大组件的信息我们都可以通过此对象获取

            LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
                    appContext.getClassLoader(), false, true, false);

            //创建新进程的Context
            ContextImpl instrContext = ContextImpl.createAppContext(this, pi);

            try {

            //创建Instrumentation对象
                java.lang.ClassLoader cl = instrContext.getClassLoader();
                mInstrumentation = (Instrumentation)
                    cl.loadClass(data.instrumentationName.getClassName()).newInstance();
            } catch (Exception e) {
                throw new RuntimeException(
                    "Unable to instantiate instrumentation "
                    + data.instrumentationName + ": " + e.toString(), e);
            }
            //初始化Instrumentation
            mInstrumentation.init(this, instrContext, appContext,
                   new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
                   data.instrumentationUiAutomationConnection);

        ....

        } else {
            mInstrumentation = new Instrumentation();
        }

       ....

        try {

          //通过创建Application并回调Application的attach方法
          Application app = data.info.makeApplication(data.restrictedBackupMode, null);
          mInitialApplication = app;

           if (!data.restrictedBackupMode) {
                List providers = data.providers;
                if (providers != null) {
                    //加载provider
                    installContentProviders(app, providers);
                    // For process that contains content providers, we want to
                    // ensure that the JIT is enabled "at some point".
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, *);
                }
            }

            try {
                //回调Application的OnCreate方法
                mInstrumentation.callApplicationOnCreate(app);
            } catch (Exception e) {
                if (!mInstrumentation.onException(app, e)) {
                    throw new RuntimeException(
                        "Unable to create application " + app.getClass().getName()
                        + ": " + e.toString(), e);
                }
            }
        } finally {
            StrictMode.setThreadPolicy(savedPolicy);
        }
    }
复制代码

加载ContentProvider的方法installContentProviders():

private void installContentProviders(
            Context context, List providers) {
        final ArrayList 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());
            }
            //看名字应该是这个方法真正加载,进去看看
            IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
            if (cph != null) {
                cph.noReleaseNeeded = true;
                results.add(cph);
            }
        }

        try {
         //通知AMS,ContentProvider已经加载完成           
         ActivityManagerNative.getDefault().publishContentProviders(
                getApplicationThread(), results);
        } catch (RemoteException ex) {
        }
    }
复制代码

真正加载provider的方法installProvider:

private IActivityManager.ContentProviderHolder installProvider(Context context,
            IActivityManager.ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {

        ContentProvider localProvider = null;
        IContentProvider provider;
        if (holder == null || holder.provider == null) {
          //创建context
            Context c = null;
            ApplicationInfo ai = info.applicationInfo;
            if (context.getPackageName().equals(ai.packageName)) {
                c = context;
            } else if (mInitialApplication != null &&
                    mInitialApplication.getPackageName().equals(ai.packageName)) {
                c = mInitialApplication;
            } else {
                try {
                    c = context.createPackageContext(ai.packageName,
                            Context.CONTEXT_INCLUDE_CODE);
                } catch (PackageManager.NameNotFoundException e) {
                    // Ignore
                }
            }

           ...

            try {
                //加载provider
                final java.lang.ClassLoader cl = c.getClassLoader();
                localProvider = (ContentProvider)cl.
                    loadClass(info.name).newInstance();

                //调用了getIContentProvider    
                provider = localProvider.getIContentProvider();
                if (provider == null) {

                    return null;
                }
                //调用了provider的onCreate方法
                localProvider.attachInfo(c, info);
            } catch (java.lang.Exception e) {
                if (!mInstrumentation.onException(null, e)) {
                    throw new RuntimeException(
                            "Unable to get provider " + info.name
                            + ": " + e.toString(), e);
                }
                return null;
            }
        } else {
            provider = holder.provider;

        }

        IActivityManager.ContentProviderHolder retHolder;

        synchronized (mProviderMap) {
            //调用了asBinder方法
            IBinder jBinder = provider.asBinder();

            //下面就是将provider的信息保存
            if (localProvider != null) {
                ComponentName cname = new ComponentName(info.packageName, info.name);
                ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                if (pr != null) {                
                    provider = pr.mProvider;
                } else {
                    holder = new IActivityManager.ContentProviderHolder(info);
                    holder.provider = provider;
                    holder.noReleaseNeeded = true;
                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                    mLocalProviders.put(jBinder, pr);
                    mLocalProvidersByName.put(cname, pr);
                }
                retHolder = pr.mHolder;
            } else {
                ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
                if (prc != null) {

                    if (!noReleaseNeeded) {
                        incProviderRefLocked(prc, stable);
                        try {
                            ActivityManagerNative.getDefault().removeContentProvider(
                                    holder.connection, stable);
                        } catch (RemoteException e) {
                            //do nothing content provider object is dead any way
                        }
                    }
                } else {
                    ProviderClientRecord client = installProviderAuthoritiesLocked(
                            provider, localProvider, holder);
                    if (noReleaseNeeded) {
                        prc = new ProviderRefCount(holder, client, , );
                    } else {
                        prc = stable
                                ? new ProviderRefCount(holder, client, , )
                                : new ProviderRefCount(holder, client, , );
                    }
                    mProviderRefCountMap.put(jBinder, prc);
                }
                retHolder = prc.holder;
            }
        }

        return retHolder;
    }
复制代码

方法主要是加载ContentProvider,然后通过加载的ContentProvider调用了getIContentProvider方法赋值给了一个IContentProvider类型的变量,这里有玄机哦!我们看一下ContentProvider中的getIContentProvider方法

//成员变量  mTransport          
private Transport mTransport = new Transport();             

//getIContentProvider方法
public IContentProvider getIContentProvider() {
        return mTransport;
    }
复制代码
class Transport extends ContentProviderNative {
     ....
 }
复制代码
abstract public class ContentProviderNative extends Binder implements IContentProvider {
    ....
}
复制代码

继承于Binder实现了IContentProvider,那么也就是说在ActivityThread中初始化Application的时候,加载的ContentProvider返回的是一个Binder对象,那么也就可以理解为什么ContentProvider可以远程调用了吧。

installContentProviders方法中通过调用 ActivityManagerNative.getDefault().publishContentProviders,ContentProvider已经加载完成,然后到这里再回到第5步当中,所以说会阻塞线程。

你可能感兴趣的:(ContentProvider启动过程与多进程调用)