ContentProvider原理分析

来源:互联网 发布:西门子plc伺服编程 编辑:程序博客网 时间:2024/04/30 01:08

转载请注明出处: http://blog.csdn.net/a992036795/article/details/51612425

一、ContentProvider的介绍
关于ContentProvider的介绍,以及使用可以参考我的上一篇博客http://blog.csdn.net/a992036795/article/details/51610936

二、原理
1、我们知道要访问一个ContentProvider要使用到ContentResolver。我们就先来看ContentReselover。我们通常使用ContentResolver,一般在Activity中使用getContentReselover()方法,然后调用query、insert等方法。那么我们先看看getContentReselover()方法

  @Override    public ContentResolver getContentResolver() {        return mBase.getContentResolver();    }

这个是ContextWrapper中的方法,因为Activity继承自ContextWrapper,所以我们实际调用的ContextWrapper的 getContentResolver方法。那么mBase是什么了,查看源码可以知道他的实现其实是ContextImpl这个类。
这就相当于调用了ContextImpl 的getContextResolver()方法。
那么我们来看ContextImpl类中的这个方法:
ContextImpl:

  public ContentResolver getContentResolver() {        return mContentResolver;    }

可以看到它返回了一个成员变量mContentResolver,那么mContentResolve是在哪里被创建的呢?答案是在ContextImpl的构造方法中

 private ContextImpl(ContextImpl container, ActivityThread mainThread,            LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,            Display display, Configuration overrideConfiguration, int createDisplayWithId) {        mOuterContext = this;        //中间代码省略      mContentResolver = new ApplicationContentResolver(this, mainThread, user);    }

看以看到它实际是一个ApplicationContentResolver
它实际上继承自ContentResolver,我们来看看它的定义:

 private static final class ApplicationContentResolver extends ContentResolver {        private final ActivityThread mMainThread;        private final UserHandle mUser;        public ApplicationContentResolver(                Context context, ActivityThread mainThread, UserHandle user) {            super(context);            mMainThread = Preconditions.checkNotNull(mainThread);            mUser = Preconditions.checkNotNull(user);        }        @Override        protected IContentProvider acquireProvider(Context context, String auth) {            return mMainThread.acquireProvider(context,                    ContentProvider.getAuthorityWithoutUserId(auth),                    resolveUserIdFromAuthority(auth), true);        }        @Override        protected IContentProvider acquireExistingProvider(Context context, String auth) {            return mMainThread.acquireExistingProvider(context,                    ContentProvider.getAuthorityWithoutUserId(auth),                    resolveUserIdFromAuthority(auth), true);        }        @Override        public boolean releaseProvider(IContentProvider provider) {            return mMainThread.releaseProvider(provider, true);        }        @Override        protected IContentProvider acquireUnstableProvider(Context c, String auth) {            return mMainThread.acquireProvider(c,                    ContentProvider.getAuthorityWithoutUserId(auth),                    resolveUserIdFromAuthority(auth), false);        }        @Override        public boolean releaseUnstableProvider(IContentProvider icp) {            return mMainThread.releaseProvider(icp, false);        }        @Override        public void unstableProviderDied(IContentProvider icp) {            mMainThread.handleUnstableProviderDied(icp.asBinder(), true);        }        @Override        public void appNotRespondingViaProvider(IContentProvider icp) {            mMainThread.appNotRespondingViaProvider(icp.asBinder());        }        /** @hide */        protected int resolveUserIdFromAuthority(String auth) {            return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier());        }    }}

好了,就这么简单。我来贴一下时序图,然后接着分析。
这里写图片描述

2、那么我们拿到这个ContentResolver之后,我们一般会调用他的query、insert等方法。我们就这里根据insert方法进行追踪查看它的实现。
调用方法:

getContentResolver().insert(SimpleContentProvider.USERINFO_CONTENT_URI,newRecord) ;

上面的代码是一个调用的实例,然后我们来看方法的定义:

ContentProvider.java

public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) {        Preconditions.checkNotNull(url, "url");        IContentProvider provider = acquireProvider(url);        if (provider == null) {            throw new IllegalArgumentException("Unknown URL " + url);        }        try {            long startTime = SystemClock.uptimeMillis();            Uri createdRow = provider.insert(mPackageName, url, values);            long durationMillis = SystemClock.uptimeMillis() - startTime;            maybeLogUpdateToEventLog(durationMillis, url, "insert", null /* where */);            return createdRow;        } catch (RemoteException e) {            // Arbitrary and not worth documenting, as Activity            // Manager will kill this process shortly anyway.            return null;        } finally {            releaseProvider(provider);        }    }

可以看到这个方法主要调用acquireProvider(url)方法,然后调用provider.insert(mPackageName, url, values);进行插入数据。
我们就直接看acquireProvider(url)这个方法:

    public final IContentProvider acquireProvider(Uri uri) {        if (!SCHEME_CONTENT.equals(uri.getScheme())) {            return null;        }        final String auth = uri.getAuthority();        if (auth != null) {            return acquireProvider(mContext, auth);        }        return null;    }

可以看到它调用了重载方法acquireProvider(mContext, auth); 我们继续进入这个方法可以看到:

 /** @hide */    protected abstract IContentProvider acquireProvider(Context c, String name);

我们知道它实际是ApplicationContentResolver所以这个方法的实现在 ApplicationContentResolver中,那么就是调用ApplicationContentResolver中的这个方法:

        @Override        protected IContentProvider acquireProvider(Context context, String auth) {            return mMainThread.acquireProvider(context,                    ContentProvider.getAuthorityWithoutUserId(auth),                    resolveUserIdFromAuthority(auth), true);        }

接着又看到它调用了mMainThread.acquireProvider这个方法。而mMainThread是ActivityThread类,我们接着来看这个方法

 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;        }        // There is a possible race here.  Another thread may try to acquire        // the same provider at the same time.  When this happens, we want to ensure        // that the first one wins.        // Note that we cannot hold the lock while acquiring and installing the        // provider since it might take a long time to run and it could also potentially        // be re-entrant in the case where the provider is in the same process.        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;        }        // Install provider will increment the reference count for us, and break        // any ties in the race.        holder = installProvider(c, holder, holder.info,                true /*noisy*/, holder.noReleaseNeeded, stable);        return holder.provider;    }

我们着重看这句:

  holder = ActivityManagerNative.getDefault().getContentProvider(                    getApplicationThread(), auth, userId, stable);

这个ActivityManagerNative.getDefault(),它其实是夸进程的调用ActivityManagerService.就是binder机制。这里给出部分源码,就不做分析。
可以参考:http://blog.csdn.net/a992036795/article/details/51579711
ActivityManagerNative

* Retrieve the system's default/global activity manager.     */    static public IActivityManager getDefault() {        return gDefault.get();    }
    private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {        protected IActivityManager create() {            IBinder b = ServiceManager.getService("activity");            if (false) {                Log.v("ActivityManager", "default service binder = " + b);            }            IActivityManager am = asInterface(b);            if (false) {                Log.v("ActivityManager", "default service = " + am);            }            return am;        }    };}
class ActivityManagerProxy implements IActivityManager{    public ActivityManagerProxy(IBinder remote)    {        mRemote = remote;    }    public IBinder asBinder()    {        return mRemote;    }    public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,            String resolvedType, IBinder resultTo, String resultWho, int requestCode,            int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {        Parcel data = Parcel.obtain();        Parcel reply = Parcel.obtain();        data.writeInterfaceToken(IActivityManager.descriptor);

好了回归主题,那么也就是说,它调用了ActivityManagerService的getContentProvider方法。
那么就接着给出这个方法在ActivityManagerService的定义:

 @Override    public final ContentProviderHolder getContentProvider(            IApplicationThread caller, String name, int userId, boolean stable) {        enforceNotIsolatedCaller("getContentProvider");        if (caller == null) {            String msg = "null IApplicationThread when getting content provider "                    + name;            Slog.w(TAG, msg);            throw new SecurityException(msg);        }        // The incoming user check is now handled in checkContentProviderPermissionLocked() to deal        // with cross-user grant.        return getContentProviderImpl(caller, name, null, stable, userId);    }

可以看到他又调用了getContentProviderImp方法:

  private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,            String name, IBinder token, boolean stable, int userId) {        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");            // First check if this content provider has been published...            cpr = mProviderMap.getProviderByName(name, userId);            // If that didn't work, check if it exists for user 0 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");                if (r != null && cpr.canRunHere(r)) {                    // This provider has been published or is in the process                    // of being published...  but it is also allowed to run                    // in the caller's process, so don't make a connection                    // and just let the caller instantiate its own instance.                    ContentProviderHolder holder = cpr.newHolder(null);                    // don't give caller the provider object, it needs                    // to make its own.                    holder.provider = null;                    return holder;                }                final long origId = Binder.clearCallingIdentity();                checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");                // In this case the provider instance already exists, so we can                // return it right away.                conn = incProviderCountLocked(r, cpr, token, stable);                if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {                    if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {                        // If this is a perceptible app accessing the provider,                        // make sure to count it as being accessed and thus                        // back up on the LRU list.  This is good because                        // content providers are often expensive to start.                        checkTime(startTime, "getContentProviderImpl: before updateLruProcess");                        updateLruProcessLocked(cpr.proc, false, null);                        checkTime(startTime, "getContentProviderImpl: after updateLruProcess");                    }                }                if (cpr.proc != null) {                    if (false) {                        if (cpr.name.flattenToShortString().equals(                                "com.android.providers.calendar/.CalendarProvider2")) {                            Slog.v(TAG, "****************** KILLING "                                + cpr.name.flattenToShortString());                            Process.killProcess(cpr.proc.pid);                        }                    }                    checkTime(startTime, "getContentProviderImpl: before updateOomAdj");                    boolean success = updateOomAdjLocked(cpr.proc);                    maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);                    checkTime(startTime, "getContentProviderImpl: after updateOomAdj");                    if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);                    // NOTE: there is still a race here where a signal could be                    // pending on the process even though we managed to update its                    // adj level.  Not sure what to do about this, but at least                    // the race is now smaller.                    if (!success) {                        // Uh oh...  it looks like the provider's process                        // has been killed on us.  We need to wait for a new                        // process to be started, and make sure its death                        // doesn't kill our process.                        Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()                                + " is crashing; detaching " + r);                        boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);                        checkTime(startTime, "getContentProviderImpl: before appDied");                        appDiedLocked(cpr.proc);                        checkTime(startTime, "getContentProviderImpl: after appDied");                        if (!lastRef) {                            // This wasn't the last ref our process had on                            // the provider...  we have now been killed, bail.                            return null;                        }                        providerRunning = false;                        conn = null;                    }                }                Binder.restoreCallingIdentity(origId);            }            boolean singleton;            if (!providerRunning) {                try {                    checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");                    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 the provider is a singleton AND                // (it's a call within the same user || the provider is a                // privileged app)                // Then allow connecting to the singleton provider                singleton = isSingleton(cpi.processName, cpi.applicationInfo,                        cpi.name, cpi.flags)                        && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);                if (singleton) {                    userId = UserHandle.USER_OWNER;                }                cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);                checkTime(startTime, "getContentProviderImpl: got app info for user");                String msg;                checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");                if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))                        != null) {                    throw new SecurityException(msg);                }                checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");                if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate                        && !cpi.processName.equals("system")) {                    // If this content provider does not run in the system                    // process, and the system is not yet ready to run other                    // processes, then fail fast instead of hanging.                    throw new IllegalArgumentException(                            "Attempt to launch content provider before system ready");                }                // Make sure that the user who owns this provider is running.  If not,                // we don't want to allow it to run.                if (!isUserRunningLocked(userId, false)) {                    Slog.w(TAG, "Unable to launch app "                            + cpi.applicationInfo.packageName + "/"                            + cpi.applicationInfo.uid + " for provider "                            + name + ": user " + userId + " is stopped");                    return null;                }                ComponentName comp = new ComponentName(cpi.packageName, cpi.name);                checkTime(startTime, "getContentProviderImpl: before getProviderByClass");                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");                        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);                        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");                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) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "                            + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "                            + cpr.info.name + " callers=" + Debug.getCallers(6));                // This is single process, and our app is now connecting to it.                // See if we are already in the process of launching this                // provider.                final int N = mLaunchingProviders.size();                int i;                for (i = 0; i < N; i++) {                    if (mLaunchingProviders.get(i) == cpr) {                        break;                    }                }                // If the provider is not already being launched, then get it                // started.                if (i >= N) {                    final long origId = Binder.clearCallingIdentity();                    try {                        // Content provider is now in use, its package can't be stopped.                        try {                            checkTime(startTime, "getContentProviderImpl: before set stopped state");                            AppGlobals.getPackageManager().setPackageStoppedState(                                    cpr.appInfo.packageName, false, userId);                            checkTime(startTime, "getContentProviderImpl: after set stopped state");                        } catch (RemoteException e) {                        } catch (IllegalArgumentException e) {                            Slog.w(TAG, "Failed trying to unstop package "                                    + cpr.appInfo.packageName + ": " + e);                        }                        // Use existing process if already started                        checkTime(startTime, "getContentProviderImpl: looking for process record");                        ProcessRecord proc = getProcessRecordLocked(                                cpi.processName, cpr.appInfo.uid, false);                        if (proc != null && proc.thread != null) {                            if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,                                    "Installing in existing process " + proc);                            if (!proc.pubProviders.containsKey(cpi.name)) {                                checkTime(startTime, "getContentProviderImpl: scheduling install");                                proc.pubProviders.put(cpi.name, cpr);                                try {                                    proc.thread.scheduleInstallProvider(cpi);                                } catch (RemoteException e) {                                }                            }                        } else {                            checkTime(startTime, "getContentProviderImpl: before start process");                            proc = startProcessLocked(cpi.processName,                                    cpr.appInfo, false, 0, "content provider",                                    new ComponentName(cpi.applicationInfo.packageName,                                            cpi.name), false, false, false);                            checkTime(startTime, "getContentProviderImpl: after start process");                            if (proc == null) {                                Slog.w(TAG, "Unable to launch app "                                        + cpi.applicationInfo.packageName + "/"                                        + cpi.applicationInfo.uid + " for provider "                                        + name + ": process is bad");                                return null;                            }                        }                        cpr.launchingApp = proc;                        mLaunchingProviders.add(cpr);                    } finally {                        Binder.restoreCallingIdentity(origId);                    }                }                checkTime(startTime, "getContentProviderImpl: updating data structures");                // Make sure the provider is published (the same provider class                // may be published under multiple names).                if (firstClass) {                    mProviderMap.putProviderByClass(comp, cpr);                }                mProviderMap.putProviderByName(name, cpr);                conn = incProviderCountLocked(r, cpr, token, stable);                if (conn != null) {                    conn.waiting = true;                }            }            checkTime(startTime, "getContentProviderImpl: done!");        }        // Wait for the provider to be published...        synchronized (cpr) {            while (cpr.provider == null) {                if (cpr.launchingApp == null) {                    Slog.w(TAG, "Unable to launch app "                            + cpi.applicationInfo.packageName + "/"                            + cpi.applicationInfo.uid + " for provider "                            + name + ": launching app became null");                    EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,                            UserHandle.getUserId(cpi.applicationInfo.uid),                            cpi.applicationInfo.packageName,                            cpi.applicationInfo.uid, name);                    return null;                }                try {                    if (DEBUG_MU) Slog.v(TAG_MU,                            "Waiting to start provider " + cpr                            + " launchingApp=" + cpr.launchingApp);                    if (conn != null) {                        conn.waiting = true;                    }                    cpr.wait();                } catch (InterruptedException ex) {                } finally {                    if (conn != null) {                        conn.waiting = false;                    }                }            }        }        return cpr != null ? cpr.newHolder(conn) : null;    }

代码太长~ 我也不敢看~着重看这几句:

            // First check if this content provider has been published...            cpr = mProviderMap.getProviderByName(name, userId);
 proc = startProcessLocked(cpi.processName,                                    cpr.appInfo, false, 0, "content provider",                                    new ComponentName(cpi.applicationInfo.packageName,                                            cpi.name), false, false, false);
  return cpr != null ? cpr.newHolder(conn) : null;

大致意思是,在发布了的ContentProvide中先查找有没有该ContentProvider,又就返回一个 holder,这个holder中存放在这contentProvider,没有的话就使用starProcessLocked启动ContentProvider所在的那个进程。
源码不是很懂,猜的~ 大神勿喷。
这里写图片描述

3、那么我们就来看startProcessLocked
ActivityManagerService.java

 private final void startProcessLocked(ProcessRecord app,            String hostingType, String hostingNameStr) {        startProcessLocked(app, hostingType, hostingNameStr, null /* abiOverride */,                null /* entryPoint */, null /* entryPointArgs */);    }

他继续调用它的重载方法:

private final void startProcessLocked(ProcessRecord app, String hostingType,            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {        ....//看这里!!!!            Process.ProcessStartResult startResult = Process.start(entryPoint,                    app.processName, uid, uid, gids, debugFlags, mountExternal,                    app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,                    app.info.dataDir, entryPointArgs);....        }    }

可以看到他调用了Process.start()方法,
那么我们来看这个方法的定义:

    /**     * Start a new process.     *      * <p>If processes are enabled, a new process is created and the     * static main() function of a <var>processClass</var> is executed there.     * The process will continue running after this function returns.     *      * <p>If processes are not enabled, a new thread in the caller's     * process is created and main() of <var>processClass</var> called there.     *      * <p>The niceName parameter, if not an empty string, is a custom name to     * give to the process instead of using processClass.  This allows you to     * make easily identifyable processes even if you are using the same base     * <var>processClass</var> to start them.     *      * @param processClass The class to use as the process's main entry     *                     point.     * @param niceName A more readable name to use for the process.     * @param uid The user-id under which the process will run.     * @param gid The group-id under which the process will run.     * @param gids Additional group-ids associated with the process.     * @param debugFlags Additional flags.     * @param targetSdkVersion The target SDK version for the app.     * @param seInfo null-ok SELinux information for the new process.     * @param abi non-null the ABI this app should be started with.     * @param instructionSet null-ok the instruction set to use.     * @param appDataDir null-ok the data directory of the app.     * @param zygoteArgs Additional arguments to supply to the zygote process.     *      * @return An object that describes the result of the attempt to start the process.     * @throws RuntimeException on fatal start failure     *      * {@hide}     */    public static final ProcessStartResult start(final String processClass,                                  final String niceName,                                  int uid, int gid, int[] gids,                                  int debugFlags, int mountExternal,                                  int targetSdkVersion,                                  String seInfo,                                  String abi,                                  String instructionSet,                                  String appDataDir,                                  String[] zygoteArgs) {

看注释第一行,使用zygote启动一个新的进程。到这里就不分析。
这里写图片描述

4、上文讲到如果ContentProvider没有发布的话,则ContentProvider所在的那个进程。那么我们就从应用启动的入口在来分析一边。
应用从ActivityThread的main方法中开始。
ActivityThread#main:

public static void main(String[] args) {        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");        SamplingProfilerIntegration.start();        // CloseGuard defaults to true and can be quite spammy.  We        // disable it here, but selectively enable it later (via        // StrictMode) on debug builds, but using DropBox, not logs.        CloseGuard.setEnabled(false);        Environment.initForCurrentUser();        // Set the reporter for event logging in libcore        EventLogger.setReporter(new EventLoggingReporter());        // Make sure TrustedCertificateStore looks in the right place for CA certificates        final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());        TrustedCertificateStore.setDefaultUserDirectory(configDir);        Process.setArgV0("<pre-initialized>");        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        // End of event ActivityThreadMain.        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }}

可以看到它new 出来ActivityThread之后调用了attach(false)方法
追踪这个方法:

 private void attach(boolean system) {       ...            final IActivityManager mgr = ActivityManagerNative.getDefault();            try {                mgr.attachApplication(mAppThread);            } catch (RemoteException ex) {                // Ignore            }                    ......                    }

可以看到它调用了mgr.attachApplication(mAppThread); 这个实际调用的ActivityManagerService的attachApplication(mAppThread)方法。
这个上文讲过,底层就是binder。跨进程操作,实际就是拿到的代理类ActivityManagerProxy,实现是服务端的ActivityManagerService。
来看看他的参数 mAppThread
他是ActivityThread的成员变量:

    final ApplicationThread mAppThread = new ApplicationThread();

看他的定义:

private class ApplicationThread extends ApplicationThreadNative {        private static final String DB_INFO_FORMAT = "  %8s %8s %14s %14s  %s";        private int mLastProcessState = -1;        private void updatePendingConfiguration(Configuration 
/** {@hide} */public abstract class ApplicationThreadNative extends Binder        implements IApplicationThread {    /**     * Cast a Binder object into an application thread interface, generating     * a proxy if needed.     */    static public IApplicationThread asInterface(IBinder obj) {        if (obj == null) {            return null;        }        IApplicationThread in =            (IApplicationThread)obj.queryLocalInterface(descriptor);        if (in != null) {            return in;        }        return new ApplicationThreadProxy(obj);    }    public ApplicationThreadNative() {        attachInterface(this, descriptor);    }

看到没? 是一个binder。
最终AcitityManagerService还要用它来与这边的进程通信呢。
好了,言归正传,看ActivityManagerService的attachApplication方法。
ActivityManagerService.java

   @Override    public final void attachApplication(IApplicationThread thread) {        synchronized (this) {            int callingPid = Binder.getCallingPid();            final long origId = Binder.clearCallingIdentity();            attachApplicationLocked(thread, callingPid);            Binder.restoreCallingIdentity(origId);        }    }
private final boolean attachApplicationLocked(IApplicationThread thread,            int pid) {       ....            ProfilerInfo profilerInfo = profileFile == null ? null                    : new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,                    enableTrackAllocation, isRestrictedBackupMode || !normalMode, app.persistent,                    new Configuration(mConfiguration), app.compat,                    getCommonServicesLocked(app.isolated),                    mCoreSettingsObserver.getCoreSettingsLocked());            updateLruProcessLocked(app, false, null);            app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();        } catch (Exception e) {         ...        return true;    }

可以看到它调用了ApplicaitonThread 的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 enableOpenGlTrace, boolean trackAllocation, boolean isRestrictedBackupMode,                boolean persistent, Configuration config, CompatibilityInfo compatInfo,                Map<String, IBinder> services, Bundle coreSettings) {            if (services != null) {                // Setup the service cache in the ServiceManager                ServiceManager.initServiceCache(services);            }            setCoreSettings(coreSettings);            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.enableOpenGlTrace = enableOpenGlTrace;            data.trackAllocation = trackAllocation;            data.restrictedBackupMode = isRestrictedBackupMode;            data.persistent = persistent;            data.config = config;            data.compatInfo = compatInfo;            data.initProfilerInfo = profilerInfo;            sendMessage(H.BIND_APPLICATION, data);        }

可以看到它使用 H 这个handle发送了一个消息:

sendMessage(H.BIND_APPLICATION, data);

我们来看接收到之后的执行:

 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;

它又调用了ActivityThread的handleBindApplication(data);方法

 private void handleBindApplication(AppBindData data) {         ......          final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();        try {            // If the app is being launched for full backup or restore, bring it up in            // a restricted environment with the base application class.            Application app = data.info.makeApplication(data.restrictedBackupMode, null);            mInitialApplication = app;            // don't bring up providers in restricted mode; they may depend on the            // app's custom Application class            if (!data.restrictedBackupMode) {                List<ProviderInfo> providers = data.providers;                if (providers != null) {                    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, 10*1000);                }            }            // Do this after providers, since instrumentation tests generally start their            // test thread at this point, and we don't want that racing.            try {                mInstrumentation.onCreate(data.instrumentationArgs);            }            catch (Exception e) {                throw new RuntimeException(                    "Exception thrown in onCreate() of "                    + data.instrumentationName + ": " + e.toString(), e);            }            try {                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);        }    }

可以看到他调用了

 installContentProviders(app, providers);

接着看:

private void installContentProviders(            Context context, List<ProviderInfo> providers) {        final ArrayList<IActivityManager.ContentProviderHolder> results =            new ArrayList<IActivityManager.ContentProviderHolder>();        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 {            ActivityManagerNative.getDefault().publishContentProviders(                getApplicationThread(), results);        } catch (RemoteException ex) {        }    }

可以看到又调用了

installProvider(context, null, cpi,                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
private IActivityManager.ContentProviderHolder installProvider(Context context,            IActivityManager.ContentProviderHolder holder, ProviderInfo info,            boolean noisy, boolean noReleaseNeeded, boolean stable) {        ContentProvider localProvider = null;    .....     try {                final java.lang.ClassLoader cl = c.getClassLoader();                localProvider = (ContentProvider)cl.                    loadClass(info.name).newInstance();                provider = localProvider.getIContentProvider();                if (provider == null) {                    Slog.e(TAG, "Failed to instantiate class " +                          info.name + " from sourceDir " +                          info.applicationInfo.sourceDir);                    return null;                }                if (DEBUG_PROVIDER) Slog.v(                    TAG, "Instantiating local provider " + info.name);                // XXX Need to create the correct context for this provider.                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 {.....

可以看到它使用反射创建出了了 ContentProvider,而且还调用了他的attachInfo(c, info);方法
我们接着看
ContentProvider:

    public void attachInfo(Context context, ProviderInfo info) {        attachInfo(context, info, false);    }    private void attachInfo(Context context, ProviderInfo info, boolean testing) {        mNoPerms = testing;        /*         * Only allow it to be set once, so after the content service gives         * this to us clients can't change it.         */        if (mContext == null) {            mContext = context;            if (context != null) {                mTransport.mAppOpsManager = (AppOpsManager) context.getSystemService(                        Context.APP_OPS_SERVICE);            }            mMyUid = Process.myUid();            if (info != null) {                setReadPermission(info.readPermission);                setWritePermission(info.writePermission);                setPathPermissions(info.pathPermissions);                mExported = info.exported;                mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;                setAuthorities(info.authority);            }            ContentProvider.this.onCreate();        }    }

看最后调用了

 ContentProvider.this.onCreate();

这就执行了onCreate()

这里写图片描述

终于完了~~
最后补充一下 因为 handleBindApplication 是H 这个handle调用的,在看这H创建

他是ActivityThread的成员方法   final H mH = new H();

在结合ActivityThread的main方法中的:

 Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        // End of event ActivityThreadMain.        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();

可以看到这是个主线程的Handle,所以就是说handleBindApplication 方法 以及后面的方法都发生在线程,那么ContentProvider.this.OnCreate()也在主线程中了。

这就解释了上篇文章中说到了 ContentProvider的onCreate发生在主线程,而其他的方法发生在Binder线程池中了。

大体流程就分析完了,其中很懂源码我也不是很懂,如有错误请批评指正~

1 0