Android之ContentProvider的启动过程源码分析

ContentProvider组件一次传递的数据量可能非常大,如果直接使用Binder进程间通信机制来传递数据的话,传输效率是个问题。不同的应用程序进程可以通过匿名共享内存来传输大数据,因为无论多大的数据,对匿名共享内存来说,需要在进程间传递的仅仅是一个文件描述符而已。这样,结合Binder进程间通信机制和匿名共享内存机制,ContentProvider组件就可以实现高效的文件传输了。

ContentProvider中query方法返回的保存在cursor对象中的数据是通过匿名共享内存来传输的,call方法返回的数据是保存在Bundle对象中的,它直接使用Binder进程间通信机制来传输的。当传输的数据量比较小时,使用匿名共享内存就得不偿失了,因为它的创建过程和映射过程都是需要开销的。

Provider的启动过程大致分为几个步骤:

1.调用者通过URI访问目标Provider。

2.调用者所运行在的应用程序进程发现不存在要访问的目标Provider的代理对象,就会通过URI来请求ActivityManagerService返回一个用来访问目标Provider组件的代理对象。

3.AMS发现这个Provider组件还没有启动起来,就会先创建一个新的应用程序进程,然后在这个进程中启动目标Provider组件。

4.目标Provider组件启动起来后,就会将自己发布到AMS中,以便AMS可以将它的一个代理对象返回给调用者使用。

使用Provider时需要先调用getContentProvider()方法来获取ContentResolver对象,惯例先看时序图:

先看ContextWrapper类中的getContentResolver方法:

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


调用到ContextImpl类中的getContentResolver方法:

private final ApplicationContentResolver mContentResolver;

private ContextImpl(ContextImpl container, ActivityThread mainThread,
        LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
        Display display, Configuration overrideConfiguration, int createDisplayWithId) {

    mMainThread = mainThread;
    . . .

    mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}

@Override
public ContentResolver getContentResolver() {
    return mContentResolver;
}

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
    public boolean releaseProvider(IContentProvider provider) {
        return mMainThread.releaseProvider(provider, true);
    }

    /** @hide */
    protected int resolveUserIdFromAuthority(String auth) {
        return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier());
    }
    . . .

}


上面ApplicationContentResolver是ContextImpl的内部类。到这里调用者就获取到了ContentResolver对象。

获取到对象后,假设调用者要访问目标Provider的insert方法(其他方法的流程基本一致),先看下时序图:

先看ContentResolver类的insert方法:

public static final String SCHEME_CONTENT = "content";

public ContentResolver(Context context) {
    mContext = context != null ? context : ActivityThread.currentApplication();
    mPackageName = mContext.getOpPackageName();
}

public final @Nullable Uri insert(@NonNull Uri url, @Nullable ContentValues values) {
    android.util.SeempLog.record_uri(37, url);
    Preconditions.checkNotNull(url, "url");
	// 获取provider
    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 {
	    // 释放provider
        releaseProvider(provider);
    }
}

/**
 * Returns the content provider for the given content URI.
 *
 * @param uri The URI to a content provider
 * @return The ContentProvider for the given URI, or null if no content provider is found.
 * @hide
 */
public final IContentProvider acquireProvider(Uri uri) {
    // 判断scheme是否以content开头,如果不是说明这个uri不是用来访问provider的
    if (!SCHEME_CONTENT.equals(uri.getScheme())) {
        return null;
    }
    final String auth = uri.getAuthority();
    if (auth != null) {
	    // 获取provider对象
        return acquireProvider(mContext, auth);
    }
    return null;
}

// 抽象方法,由子类实现
/** @hide */
protected abstract IContentProvider acquireProvider(Context c, String name);


调用到这里,又回到了ContextImpl的内部类ApplicationContentResolver中的acquireProvider方法,该方法中又调用了ActivityThread类中的acquireProvider方法,看该方法之前,先看下传递的参数:

getUserIdFromAuthority方法获取userId:
/**
 * Removes userId part from authority string. Expects format:
 * userId@some.authority
 * If there is no userId in the authority, it symply returns the argument
 * @hide
 */
public static String getAuthorityWithoutUserId(String auth) {
    if (auth == null) return null;
    int end = auth.lastIndexOf('@');
    // 截取authority
    return auth.substring(end+1);
}

/** @hide */
public static int getUserIdFromAuthority(String auth, int defaultUserId) {
    if (auth == null) return defaultUserId;
    int end = auth.lastIndexOf('@');
    if (end == -1) return defaultUserId;
    // 截取userId
    String userIdString = auth.substring(0, end);
    try {
        return Integer.parseInt(userIdString);
    } catch (NumberFormatException e) {
        Log.w(TAG, "Error parsing userId.", e);
        return UserHandle.USER_NULL;
    }
}


上面两个方法主要是截取不规则的authority和获取userId的。再接着看下后续的时序图:

根据上面时序图,先看下ActivityThread类中的acquireProvider方法:

public final IContentProvider acquireProvider(
        Context c, String auth, int userId, boolean stable) {
    // 调用acquireExistingProvider检查该provider代理对象是否已经存在
    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 {
        // 通过BInder代理对象调用AMS的getContentProvider方法获取到目标Provider的代理对象
        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;
}

// 用来保存当前应用程序进程中访问过的Content Provider组件代理对象
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
= new ArrayMap<ProviderKey, ProviderClientRecord>();
// 各Provider被引用次数map
final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
= new ArrayMap<IBinder, ProviderRefCount>();

public final IContentProvider acquireExistingProvider(
        Context c, String auth, int userId, boolean stable) {
    synchronized (mProviderMap) {
        final ProviderKey key = new ProviderKey(auth, userId);
        // 检查mProviderMap中是否已经有目标Provider代理对象
        final ProviderClientRecord pr = mProviderMap.get(key);
        // 如果没有则返回null
        if (pr == null) {
            return null;
        }

        IContentProvider provider = pr.mProvider;
        IBinder jBinder = provider.asBinder();
        // 判断目标Provider代理对象所运行在的进程是否还在运行
        if (!jBinder.isBinderAlive()) {
            // The hosting process of the provider has died; we can't
            // use this one.
            Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
                    + ": existing object's process dead");
            handleUnstableProviderDiedLocked(jBinder, true);
            return null;
        }

        // Only increment the ref count if we have one.  If we don't then the
        // provider is not reference counted and never needs to be released.
        ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
        // 判断mProviderRefCountMap中是否有目标Provider,如果有则其引用次数加1
        if (prc != null) {
            incProviderRefLocked(prc, stable);
        }
        return provider;
    }
}


接着看下ActivityManagerService类中的getContentProvider方法:

@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);
}

final ProviderMap mProviderMap;

private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
        String name, IBinder token, boolean stable, int userId) {
    // 在AMS中,每个已经启动的Provider组件都使用一个ContentProviderRecord对象来描述,并保存在mProviderMap中
    ContentProviderRecord cpr;
    ContentProviderConnection conn = null;
    ProviderInfo cpi = null;

    /*在这里可以准备自启动黑白名单的初始化操作*/

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

        ProcessRecord r = null;
        if (caller != null) {
            // 获取目标Provider组件代理对象的应用程序进程的信息
            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;

        // 判断从startTime到这里的操作是否超过1秒
        checkTime(startTime, "getContentProviderImpl: getProviderByName");

        // First check if this content provider has been published...
        // mProviderMap在构造方法中初始化
        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");

            // 判断目标Provider的android:multiprocess属性是否为true
            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.
                // 为true说明目标Provider可以运行在调用者所在进程,故这里不用建立连接,因为调用者可以自己实例化目标Provider
                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);
            // 如果稳定连接和不稳定连接之和为1
            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");
                    // 开启Provider成本较高,故这里做下备份以后续访问时减小开销
                    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");
                // 更新目标Provider所在进程的Adj值,如果返回false说明进程被杀
                boolean success = updateOomAdjLocked(cpr.proc);
                // 更新目标Provider最近使用时间
                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);
                    // 连接数减1后是否还有连接,如果没有则为true
                    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;
        // 目标Provider没有在运行中
        if (!providerRunning) {
            try {
                checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
                // 到PMS中查找android:authorities属性值等于name的Provider组件的信息
                cpi = AppGlobals.getPackageManager().
                    resolveContentProvider(name,
                        STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
                checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
            } catch (RemoteException ex) {
            }
            // cpi为null说明没有任何应用提供该Provider
            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;
            }else{
                //SmartContainer modified begin
                if (!SmartContainerConfig.WITH_OUT_VIRTUAL_BOX){
                    userId = UserHandle.getUserId(cpi.applicationInfo.uid);
                }
                //SmartContainer modified end
            }
            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;
            }

            // cpi.name是Provider组件的类名
            ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
            checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
            // 根据从PMS中查询到的Provider类名到mProviderMap查找是否有与类名一致的cpr对象
            cpr = mProviderMap.getProviderByClass(comp, userId);
            checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
            final boolean firstClass = cpr == null;
            // firstClass为true说明目标Provider组件还没有启动起来
            if (firstClass) {
                final long ident = Binder.clearCallingIdentity();
                try {
                    checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
                    // 到PMS中查找目标Provider所属应用程序的信息
                    ApplicationInfo ai =
                        AppGlobals.getPackageManager().
                            getApplicationInfo(
                                    cpi.applicationInfo.packageName,
                                    STOCK_PM_FLAGS, userId);
                    checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
                    // 如果为null说明不存在,直接返回null
                    if (ai == null) {
                        Slog.w(TAG, "No package info for content provider "
                                + cpi.name);
                        return null;
                    }
                    ai = getAppInfoForUser(ai, userId);
                    // 将cpi、ai等信息封装成一个cpr对象,用来描述即将要启动的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");

            // 启动之前先检查先检查multiprocess属性是否为true
            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.
            // AMS把所有正在启动的Provider组件都保存在mLaunchingProviders中
            final int N = mLaunchingProviders.size();
            int i;
            // 遍历查找要启动的Provider是否正在启动中
            for (i = 0; i < N; i++) {
                if (mLaunchingProviders.get(i) == cpr) {
                    break;
                }
            }

            // If the provider is not already being launched, then get it
            // started.
            // i >= N说明要启动的Provider没有在启动中
            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);
                    // 如果要启动的Provider所在的进程已经启动,则直接在进程中安装该Provider即可
                    if (proc != null && proc.thread != null) {
                        if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
                                "Installing in existing process " + proc);
                        // 判断目标Provider是否已经发布
                        if (!proc.pubProviders.containsKey(cpi.name)) {
                            checkTime(startTime, "getContentProviderImpl: scheduling install");
                            // 把目标Provider保存在pubProviders中
                            proc.pubProviders.put(cpi.name, cpr);
                            try {
                                // 都有ActivityThread类中的scheduleInstallProvider方法安装模板Provider
                                proc.thread.scheduleInstallProvider(cpi);
                            } catch (RemoteException e) {
                            }
                        }
                    // 目标Provider所运行在的进程还没有启动,则需要先启动进程再安装Provider
                    } 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;
                    // 把cpr放到正在启动的Provider列表中
                    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) {
                // 保存cpr对象
                mProviderMap.putProviderByClass(comp, cpr);
            }

            // 保存cpr对象
            mProviderMap.putProviderByName(name, cpr);
            // 获取连接
            conn = incProviderCountLocked(r, cpr, token, stable);
            if (conn != null) {
                // 因为目标Provider组件需要等待进程启动后才能启动,故需要等待进程启动完成
                conn.waiting = true;
            }
        }
        checkTime(startTime, "getContentProviderImpl: done!");
    }

    // Wait for the provider to be published...
    synchronized (cpr) {
        // 循环等待cpr所描述的Provider组件启动完成
        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;
}

// 判断每个操作是否超过1秒
private void checkTime(long startTime, String where) {
    long now = SystemClock.elapsedRealtime();
    if ((now-startTime) > 1000) {
        // If we are taking more than a second, log about it.
        Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where);
    }
}


下面看ActivityThread类中的scheduleInstallProvider方法:

@Override
public void scheduleInstallProvider(ProviderInfo provider) {
    sendMessage(H.INSTALL_PROVIDER, provider);
}

private class H extends Handler {

    public static final int INSTALL_PROVIDER        = 145;
    . . .

    public void handleMessage(Message msg) {
        switch (msg.what) {
            . . .
            case INSTALL_PROVIDER:
                handleInstallProvider((ProviderInfo) msg.obj);
                break;
        }
    }
}

public void handleInstallProvider(ProviderInfo info) {
    final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
    try {
        installContentProviders(mInitialApplication, Lists.newArrayList(info));
    } finally {
        StrictMode.setThreadPolicy(oldPolicy);
    }
}

private void installContentProviders(
        Context context, List<ProviderInfo> providers) {
    final ArrayList<IActivityManager.ContentProviderHolder> results =
        new ArrayList<IActivityManager.ContentProviderHolder>();

    // 循环调用installProvider方法在当前应用程序进程中启动保存在providers列表中的所有Provider组件
    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 {
        // 将所有的cph对象传递给AMS,以便AMS可以获取到它们所描述的Provider组件的一个访问接口
        ActivityManagerNative.getDefault().publishContentProviders(
            getApplicationThread(), results);
    } catch (RemoteException ex) {
    }
}


接下来先分析installProvider方法在当前应用程序进程中启动一个Provider组件的过程,然后再分析AMS的publishContentProviders方法将启动完成之后的Provider组件发布到AMS中的过程:

publishContentProviders方法将启动完成之后的Provider组件发布到AMS中的过程:
/**
 * Installs the provider.
 *
 * Providers that are local to the process or that come from the system server
 * may be installed permanently which is indicated by setting noReleaseNeeded to true.
 * Other remote providers are reference counted.  The initial reference count
 * for all reference counted providers is one.  Providers that are not reference
 * counted do not have a reference count (at all).
 *
 * This method detects when a provider has already been installed.  When this happens,
 * it increments the reference count of the existing provider (if appropriate)
 * and returns the existing provider.  This can happen due to concurrent
 * attempts to acquire the same provider.
 */
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) {
        if (DEBUG_PROVIDER || noisy) {
            Slog.d(TAG, "Loading provider " + info.authority + ": "
                    + info.name);
        }
        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
            }
        }
        if (c == null) {
            Slog.w(TAG, "Unable to get context for package " +
                  ai.packageName +
                  " while loading content provider " +
                  info.name);
            return null;
        }
        try {
            final java.lang.ClassLoader cl = c.getClassLoader();
            // info.name描述了要在当前进程中启动的Provider组件的类名
            // 这里根据类名在进程中创建了一个Provider组件的实例
            localProvider = (ContentProvider)cl.
                loadClass(info.name).newInstance();
            // 获得一个IContentProvider接口,该接口是要发布到AMS中的,以便AMS可以将它返回给那些需要
            // 访问它所描述的Provider组件的应用程序进程
            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.
            // 进一步初始化创建的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 {
        provider = holder.provider;
        if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
                + info.name);
    }

    IActivityManager.ContentProviderHolder retHolder;

    synchronized (mProviderMap) {
        if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
                + " / " + info.name);
        IBinder jBinder = provider.asBinder();
        if (localProvider != null) {
            ComponentName cname = new ComponentName(info.packageName, info.name);
            // 根据组件名到mLocalProvidersByName中查询是否已经存在
            ProviderClientRecord pr = mLocalProvidersByName.get(cname);
            if (pr != null) {
                if (DEBUG_PROVIDER) {
                    Slog.v(TAG, "installProvider: lost the race, "
                            + "using existing local provider");
                }
                provider = pr.mProvider;
            } else {
                holder = new IActivityManager.ContentProviderHolder(info);
                holder.provider = provider;
                holder.noReleaseNeeded = true;
                // 将provider组件封装成一个pr对象
                pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                // 对一个应用程序进程来说,它所访问的Provider组件有可能是在当前应用程序进程中运行,也有可能是在
                // 其他应用程序进程中运行。为了区分这两种情况,用mLocalProviders变量来保存运行在当前进程中的Provider
                mLocalProviders.put(jBinder, pr);
                mLocalProvidersByName.put(cname, pr);
            }
            retHolder = pr.mHolder;
        } else {
            // 根据Provider的Binder对象获取prc对象
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) {
                if (DEBUG_PROVIDER) {
                    Slog.v(TAG, "installProvider: lost the race, updating ref count");
                }
                // We need to transfer our new reference to the existing
                // ref count, releasing the old one...  but only if
                // release is needed (that is, it is not running in the
                // system process).
                if (!noReleaseNeeded) {
                    // Provider的引用数量加1
                    incProviderRefLocked(prc, stable);
                    try {
                        ActivityManagerNative.getDefault().removeContentProvider(
                                holder.connection, stable);
                    } catch (RemoteException e) {
                        //do nothing content provider object is dead any way
                    }
                }
            } else {
                // 如果prc对象为null,说明不存在目标Provider对象,需要创建
                ProviderClientRecord client = installProviderAuthoritiesLocked(
                        provider, localProvider, holder);
                if (noReleaseNeeded) {
                    prc = new ProviderRefCount(holder, client, 1000, 1000);
                } else {
                    prc = stable
                            ? new ProviderRefCount(holder, client, 1, 0)
                            : new ProviderRefCount(holder, client, 0, 1);
                }
                mProviderRefCountMap.put(jBinder, prc);
            }
            retHolder = prc.holder;
        }
    }

    return retHolder;
}

private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
        ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
    // authority描述了android:authorities属性值,它是一个多值属性
    final String auths[] = holder.info.authority.split(";");
    final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);

    // 创建一个pcr对象
    final ProviderClientRecord pcr = new ProviderClientRecord(
            auths, provider, localProvider, holder);
    // 循环根据auth创建ProviderKey对象并保存在mProviderMap中
    for (String auth : auths) {
        final ProviderKey key = new ProviderKey(auth, userId);
        final ProviderClientRecord existing = mProviderMap.get(key);
        if (existing != null) {
            Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
                    + " already published as " + auth);
        } else {
            mProviderMap.put(key, pcr);
        }
    }
    return pcr;
}


每一个Provider组件内部都有一个类型为Transport的Binder本地对象,这个Binder本地对象是用来传递给AMS的,然后AMS再将引用了它的一个Binder代理对象返回给需要访问该Provider组件的其他应用程序进程。这样,其他应用程序进程就可以通过这个Binder代理对象来间接地访问一个Provider组件中的数据了。

下面看ContentProvider类中的getIContentProvider方法和attachInfo方法:

private Transport mTransport = new Transport();

/**
 * Binder object that deals with remoting.
 * @hide
 */
class Transport extends ContentProviderNative {
    . . .
}

/**
 * Returns the Binder object for this provider.
 * @hide
 */
public IContentProvider getIContentProvider() {
    return mTransport;
}

/**
 * After being instantiated, this is called to tell the content provider
 * about itself.
 */
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) {
            // 将Provider的访问权限保存
            setReadPermission(info.readPermission);
            setWritePermission(info.writePermission);
            setPathPermissions(info.pathPermissions);
            mExported = info.exported;
            mSingleUser = (info.flags & ProviderInfo.FLAG_SINGLE_USER) != 0;
            setAuthorities(info.authority);
        }
        // 回调ContentProvider的onCreate方法
        ContentProvider.this.onCreate();
    }
}


最后看AMS中的publishContentProviders方法:

public final void publishContentProviders(IApplicationThread caller,
        List<ContentProviderHolder> providers) {
    if (providers == null) {
        return;
    }

    enforceNotIsolatedCaller("publishContentProviders");
    synchronized (this) {
        final ProcessRecord r = getRecordForAppLocked(caller);
        if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
        if (r == null) {
            throw new SecurityException(
                    "Unable to find app for caller " + caller
                  + " (pid=" + Binder.getCallingPid()
                  + ") when publishing content providers");
        }

        final long origId = Binder.clearCallingIdentity();

        final int N = providers.size();
        // 循环取出保存在providers中的每一个ContentProviderHolder对象src,
        // 然后在AMS中找到与它对应的ContentProviderHolder对象dst
        for (int i = 0; i < N; i++) {
            ContentProviderHolder src = providers.get(i);
            if (src == null || src.info == null || src.provider == null) {
                continue;
            }
            ContentProviderRecord dst = r.pubProviders.get(src.info.name);
            if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
            if (dst != null) {
                ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                mProviderMap.putProviderByClass(comp, dst);
                String names[] = dst.info.authority.split(";");
                for (int j = 0; j < names.length; j++) {
                    mProviderMap.putProviderByName(names[j], dst);
                }

                int launchingCount = mLaunchingProviders.size();
                int j;
                boolean wasInLaunchingProviders = false;
                for (j = 0; j < launchingCount; j++) {
                    if (mLaunchingProviders.get(j) == dst) {
                        mLaunchingProviders.remove(j);
                        wasInLaunchingProviders = true;
                        j--;
                        launchingCount--;
                    }
                }
                if (wasInLaunchingProviders) {
                    mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
                }
                synchronized (dst) {
                    // 将src所描述的一个Provider组件的一个IContentProvider访问接口保存在dst的成员变量provider中
                    dst.provider = src.provider;
                    dst.proc = r;
                    dst.notifyAll();
                }
                updateOomAdjLocked(r);
                maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                        src.info.authority);
            }
        }

        Binder.restoreCallingIdentity(origId);
    }
}


到这里Provider已经启动完成了,并且将它的一个代理对象即一个类型为Transport的Binder代理对象发布到AMS中了。

内容有理解错误或偏差之处,请包涵指正,谢谢!

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值