谈谈AMS管理ContentProvider

重要数据结

ContentProviderRecord

  • provider:在ActivityThread的installProvider()过程,会创建ContentProvider对象

  • proc:记录provider所在的进程

  • launchingApp:记录等待provider所在进程启动

  • connections:记录该ContentProvider的所有连接信息

ContentProviderConnection

功能:连接contentProvider与请求该provider所对应的进程

  1. provider:目标provider所对应的ContentProviderRecord结构体;
  2. client:请求该provider的客户端进程
  3. waiting:该连接的client进程正在等待该provider发布

ProcessRecord

  • pubProviders: ArrayMap<String, ContentProviderRecord>记录发布的provider
  • conProviders: ArrayList 记录当前进程跟其他进程provider所建立的连接

AMS

  • mProviderMap记录系统所有的provider信息;
  • mLaunchingProviders记录当前正在启动的provider;

ActivityThread

  • mProviderMap: 记录App端的所有provider信息;
  • mProviderRefCountMap:记录App端的所有provider引用信息;

查询切入

首先通过查询ContentProvider来切入

ContentResolver cr = getContentResolver();  //获取ContentResolver
Cursor cursor = cr.query(uri, null, null, null, null);  //执行查询操作

其中getContentResolver()是ContextImpl中的方法

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

其中ContextImpl的构造方法中给变量mContentResolver赋值

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

从结构上看:


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

在构造中得到了ActivityThread对象,这个对象是管理四大组件的核心对象

2

我们继续顺着查询来找

public final  Cursor query( Uri uri,  String[] projection,
         String selection,  String[] selectionArgs,
         String sortOrder) {
    return query(uri, projection, selection, selectionArgs, sortOrder, null);
}

public final  Cursor query(final  Uri uri,  String[] projection,
             String selection,  String[] selectionArgs,
             String sortOrder,  CancellationSignal cancellationSignal) {
        //获取unstable provider
        IContentProvider unstableProvider = acquireUnstableProvider(uri);
        if (unstableProvider == null) {
            return null;
        }
        IContentProvider stableProvider = null;
        Cursor qCursor = null;
        try {
            long startTime = SystemClock.uptimeMillis();
            ...
            try {
                //执行查询操作
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            } catch (DeadObjectException e) {
                // 远程进程死亡,处理unstable provider死亡过程
                unstableProviderDied(unstableProvider);
                //unstable类型死亡后,再创建stable类型的provider
                stableProvider = acquireProvider(uri);
                if (stableProvider == null) {
                    return null;
                //再次执行查询操作
                qCursor = stableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);

            }
            if (qCursor == null) {
                return null;
            }

            //强制执行查询操作,可能会失败并跑出RuntimeException
            qCursor.getCount();
            //创建对象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);
            }
        }
    }

这段代码可以看出来,首先获取的是unstable的ContentProvider;然后执行对应query方法。

当有DeadObjectException时候代表ContentProvider在的进程已经挂掉了在重新获取stable的ContentProvider:

  • 先调用unstableProviderDied(),清理刚创建的unstable的ContentProvider;
  • 调用acquireProvider(),尝试获取stable的ContentProvider; 此时当ContentProvider进程死亡,则会杀掉该ContentProvider的客户端进程。
    然后执行query操作;
public final IContentProvider acquireUnstableProvider(Uri uri) {
    if (!SCHEME_CONTENT.equals(uri.getScheme())) {
        return null;
    }
    String auth = uri.getAuthority();
    if (auth != null) {
        return acquireUnstableProvider(mContext, uri.getAuthority());
    }
    return null;
}

ContextImpl.java

    @Override
    protected IContentProvider acquireUnstableProvider(Context c, String auth) {
        return mMainThread.acquireProvider(c,
                ContentProvider.getAuthorityWithoutUserId(auth),
                resolveUserIdFromAuthority(auth), false);
    }
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;
}

我们看到无论时那一种方法,都是调用ActivityThread.acquireProvider方法
怎么看出来的?

private static final class ApplicationContentResolver extends ContentResolver {

知道这个关系,然后在这个类中找对应acquireUnstableProvider方法

于是有:

@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
    return mMainThread.acquireProvider(c,
            ContentProvider.getAuthorityWithoutUserId(auth),
            resolveUserIdFromAuthority(auth), false);
}
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;
    }
    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;
    }

    holder = installProvider(c, holder, holder.info,
            true /*noisy*/, holder.noReleaseNeeded, stable);
    return holder.provider;
}

首先会找看看有没有已经存在的IContentProvider如果有就用有的。没有就会调用AMS.getContentProvider()方法得到一个ContentProviderHolder对象,如果出错返回null。
我们详细看

public final IContentProvider acquireExistingProvider(
        Context c, String auth, int userId, boolean stable) {
    synchronized (mProviderMap) {
        final ProviderKey key = new ProviderKey(auth, userId);
        //从AT.mProviderMap查询是否存在相对应的provider
        final ProviderClientRecord pr = mProviderMap.get(key);
        if (pr == null) {
            return null;
        }

        IContentProvider provider = pr.mProvider;
        IBinder jBinder = provider.asBinder();
        if (!jBinder.isBinderAlive()) {
            //当provider所在进程已经死亡则返回
            handleUnstableProviderDiedLocked(jBinder, true);
            return null;
        }

        ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
        if (prc != null) {
            //增加引用计数
            incProviderRefLocked(prc, stable);
        }
        return provider;
    }
}

final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
    = new ArrayMap<ProviderKey, ProviderClientRecord>();

这个集合是包括本地对象和引用对象在内的所有ContentProvider对象。但是如果Provider进程挂掉了,就返回空。比高且要处理进程死亡的一些清理工作。

如果第一次调用肯定是空,空的话干什么,空的话

try {
    holder = ActivityManagerNative.getDefault().getContentProvider(
            getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}

空就要通过AMS了

@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);
    }
    return getContentProviderImpl(caller, name, null, stable, userId);
}

其中getContentProviderImpl太长了

我们分部分进行吧。


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

得到getRecordForAppLocked记录,这里看调用者的进程是不是存在,如果不存在抛出异常。

// 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;
        }
    }
}

content provider是否已经发布,如果发布继续执行,没有发布则看是不是存在用户0。

boolean providerRunning = cpr != null;
if (providerRunning) {
    cpi = cpr.info;
    String msg;
    if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))
            != null) {
        throw new SecurityException(msg);
    }

    if (r != null && cpr.canRunHere(r)) {
    //当允许运行在调用者进程且已发布,则直接返回
        ContentProviderHolder holder = cpr.newHolder(null);
        holder.provider = null;
        return holder;
    }

    final long origId = Binder.clearCallingIdentity();

//增加引用计数
    conn = incProviderCountLocked(r, cpr, token, stable);
    if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
        if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
            //更新进程LRU队列
            updateLruProcessLocked(cpr.proc, false, null);
        }
    }

    if (cpr.proc != null) {
        if (false) {
            if (cpr.name.flattenToShortString().equals(
                    "com.android.providers.calendar/.CalendarProvider2")) {
                Process.killProcess(cpr.proc.pid);
            }
        }
        //更新进程adj
        boolean success = updateOomAdjLocked(cpr.proc);
        maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
            //如果没有更新成功说明进程不存在,不存则则减少引用计数
            boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
            appDiedLocked(cpr.proc);
            if (!lastRef) {
                return null;
            }
            providerRunning = false;
            conn = null;
        }
    }

    Binder.restoreCallingIdentity(origId);
}

这里主要介绍的时Provider进程存在的情况,当进程存在的时候,做的事情如下:

  • 首先进行权限检查
  • 看content provider是否已经发布,当允许运行在调用者进程且已发布,则直接返回
  • 增加引用计数
  • 更新进程优先级,如果更新失败,说明此时进程被杀,则减少引用计数并且设置未发布状态

当目标provider不存在呢?


if (!providerRunning) {
            //根据authority,获取ProviderInfo对象,存储这ContentProvider的信息
            cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
                    STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
            ...
            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);
            ...

            if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
                    && !cpi.processName.equals("system")) {
                throw new IllegalArgumentException(...);
            }
            //当拥有该provider的用户并没有运行,则直接返回
            if (!isUserRunningLocked(userId, false)) {
                return null;
            }

            ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
            cpr = mProviderMap.getProviderByClass(comp, userId);
            final boolean firstClass = cpr == null;
            if (firstClass) {//此时并没有通过名称找到ContentProviderRecord对象
            
                final long ident = Binder.clearCallingIdentity();
                try {
                //得到包含Provider的应用信息
                    ApplicationInfo ai = AppGlobals.getPackageManager().
                      getApplicationInfo(cpi.applicationInfo.packageName, STOCK_PM_FLAGS, userId);

                    ai = getAppInfoForUser(ai, userId);
                    //通过应用信息与Provider信息创建对象ContentProviderRecord
                    cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                } finally {
                    Binder.restoreCallingIdentity(ident);
                }
            }

            //如果调用者进程不为空,并且cpr,能运行在调用者进程中,则返回一个空对象
            if (r != null && cpr.canRunHere(r)) {
                return cpr.newHolder(null);
            }

            final int N = mLaunchingProviders.size();
            int i;
            //从mLaunchingProviders中查询是否存在该cpr
            for (i = 0; i < N; i++) {
                if (mLaunchingProviders.get(i) == cpr) {
                    break;
                }
            }
            //当provider并没有处于mLaunchingProviders队列,则启动它
            if (i >= N) {
                final long origId = Binder.clearCallingIdentity();
                try {
                     AppGlobals.getPackageManager().setPackageStoppedState(
                                cpr.appInfo.packageName, false, userId);
                    //查询进程记录ProcessRecord,得到provider所在进程记录
                    ProcessRecord proc = getProcessRecordLocked(
                            cpi.processName, cpr.appInfo.uid, false);

                    //如果进程记录存在,把ContentProvider保存到pubProvidrts中
                    if (proc != null && proc.thread != null) {
                        if (!proc.pubProviders.containsKey(cpi.name)) {
                            proc.pubProviders.put(cpi.name, cpr);
                            //启动provider进程启动并发布provider
                            proc.thread.scheduleInstallProvider(cpi);
                        }
                    } else {
                        // 启动进程
                        proc = startProcessLocked(cpi.processName,
                                cpr.appInfo, false, 0, "content provider",
                                new ComponentName(cpi.applicationInfo.packageName,
                                        cpi.name), false, false, false);
                        if (proc == null) {
                            return null;
                        }
                    }
                    cpr.launchingApp = proc;
                    //将cpr添加到mLaunchingProviders
                    mLaunchingProviders.add(cpr);
                } finally {
                    Binder.restoreCallingIdentity(origId);
                }
            }

            if (firstClass) {
                mProviderMap.putProviderByClass(comp, cpr);
            }
            mProviderMap.putProviderByName(name, cpr);
            //增加引用计数
            conn = incProviderCountLocked(r, cpr, token, stable);
            if (conn != null) {
                conn.waiting = true;
            }
        }
    }
    ...

我们之前讨论的是进程存在的情况,provider所在进程存在的时候如果允许在调用者进程中发布provider则直接返回,然后更新进程优先级。

然后我们就进入到了provider目标进程不存在的情况
-首先获取ProviderInfo

  • 然后进行权限检查
  • if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate && !cpi.processName.equals("system")) {当系统没有准备好,并且ProviderInfo得到的进程名不是system,也就是说provider进程并不是system进程的时候返回异常
  • 当拥有该provider的用户并没有运行,则直接返回
  • 根据ComponentName,从AMS.mProviderMap中查找对应的ContentProviderRecord。AMS中mProviderMap存储所有ContentProviderRecord的本地对象和引用对象。
  • 如果没找到,说明是首次调用,首次调用则通过PMS拿到对应应用的ApplicationInfo,然后根据ProviderInfo和ApplicationInfo创建ContentProviderRecord
  • 此时目标进程存在&新创建的ContentProviderRecord允许运行在调用者进程中则返回通过ContentProviderRecord创建的ContentProviderHolder
  • provider并没有处于mLaunchingProviders队列,则启动它
    • 当ProcessRecord不为空,则加入到pubProviders,并开始安装provider;
    • 当ProcessRecord为空,则启动进程
  • 增加引用计数

小结

上面说的那些大概什么意思?这里总结一下

主要分成两个大的部分:

第一部分:如果请求的ContentProvider已经发布,但是通过cpr.canRunHere()调用判断ContentProvider能不能运行在请求者进程中,如果可以发布在请求者进程中将不会将已经发布的ContentProvider返回,返回的ContentProviderHolder对象中ContentProvider对象是null,这里注意canRunHere判断条件之一就是provider设置了""multiprovess"属性,并且两个进程uid相同。

说白了就是两个进程一样,然后这种情况下ContentProvider已经发布了,那么返回的ContentProvider就是null

第二种情况就是ContentProvider没有发布,首先检查ContentProvider能不能在调用者进程中创建,如果包含ContentProvider进程没有创建,则启动进程,如果进程启动了,则给Provider进程中安装ContentProvider,然后将ContentProvider加入到mProviderMap中

最后还有一部分:

synchronized (cpr) {
        while (cpr.provider == null) {
            if (cpr.launchingApp == null) {
                return null;
            }
            try {
                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;

一直等到provider发布完才退出

3

我们多次提到,provider能不能运行在调用者进程中,那么通过方法判断是不是在调用者进程中

public boolean canRunHere(ProcessRecord app) {
    return (info.multiprocess || info.processName.equals(app.processName))
            && uid == app.info.uid;
}
  • 我们在清单文件中配置的multiprocess=true或者调用者进程与ContentProvider在同一个进程一个中
  • ContentProvider进程跟调用者所在进程是同一个uid

我们需要重新简化过程再来一次这个复杂的方法:

r = getRecordForAppLocked(caller);

得到调用者进程记录

ContentProviderRecord cpr = mProviderMap.getProviderByName(name, userId);

通过名字和uid查找对应ContentProviderRecord

boolean providerRunning = cpr != null;

用变量providerRunning区分ContentProviderRecord是不是可以从AMS的缓存中得到


下面时得到的情况

 if (providerRunning) {
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, checkCrossUser))

检查权限

if (r != null && cpr.canRunHere(r)) {
    ContentProviderHolder holder = cpr.newHolder(null);
    holder.provider = null;
    return holder;
}

如果调用者进程存在&&provider可以运行在调用者进程中,判断条件上面已经给出,那么就返回一个没有provider的ContentProviderHolder

conn = incProviderCountLocked(r, cpr, token, stable);

增加引用计数&&新建链接信息

updateLruProcessLocked(cpr.proc, false, null);
boolean success = updateOomAdjLocked(cpr.proc);

更新provider所在进程信息

if (!success) {
    boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
    appDiedLocked(cpr.proc);
    if (!lastRef) {
        return null;
    }
    providerRunning = false;
    conn = null;
}

如果进程已经挂掉了,那就做清理工作


if (!providerRunning) {

没有得到provider的情况下

cpi = AppGlobals.getPackageManager().
        resolveContentProvider(name,
            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);

先通过PM得到ProviderInfo

cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);

然后设置应用信息

if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))

检查权限

if (!mProcessesReady && !mDidUpdate && !mWaitingUpdate
                        && !cpi.processName.equals("system")) {

然后进行判断,当provider不是运行在system进程,且系统未准备好,则抛出IllegalArgumentException

f (!isUserRunningLocked(userId, false)) {

当拥有该provider的用户并没有运行,则直接返回

然后根据应用的包名和清单文件中列举那个名字

/**
 * Public name of this item. From the "android:name" attribute.
 */
public String name;

/**
 * Name of the package that this item is in.
 */
public String packageName;
    
cpr = mProviderMap.getProviderByClass(comp, userId);

通过这些名称获取ContentProviderRecord

final boolean firstClass = cpr == null;

用这个看有没有获取到

if (firstClass) {
    ApplicationInfo ai =
        AppGlobals.getPackageManager().
            getApplicationInfo(
                    cpi.applicationInfo.packageName,
                    STOCK_PM_FLAGS, userId);
    ai = getAppInfoForUser(ai, userId);
    cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
}

当没有获取到的时候根据信息新创建一个

到了这里说明已经有ContentProviderRecord了无论如何

if (r != null && cpr.canRunHere(r)) {
    return cpr.newHolder(null);
}

然后再次检查看是不是在同一个进程中,如果在那就返回一个空的provider

final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
    if (mLaunchingProviders.get(i) == cpr) {
        break;
    }
}

在mLaunchingProviders中寻找cpr是不是存在,

if (i >= N) {

如果不存在

ProcessRecord proc = getProcessRecordLocked(cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null) {
    if (!proc.pubProviders.containsKey(cpi.name)) {
        proc.pubProviders.put(cpi.name, cpr);
        try {
            proc.thread.scheduleInstallProvider(cpi);
        } catch (RemoteException e) {
        }
    }

如果不存在&&provider所在进程存在,则添加并且安装到对应进程和对应进程所在集合中去。

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

否则启动进程

mLaunchingProviders.add(cpr);

最后将对应cpr添加mLaunchingProviders中

if (firstClass) {
    mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);

同时添加到AMS中不同的集合中

if (conn != null) {
    conn.waiting = true;
}

设置等待

synchronized (cpr) {
    while (cpr.provider == null) {
        try {
            if (conn != null) {
                conn.waiting = true;
            }
            cpr.wait();
        } catch (InterruptedException ex) {
        } finally {
            if (conn != null) {
                conn.waiting = false;
            }
        }
    }
}

等待到provider发布完成

4

public final IContentProvider acquireProvider(
        Context c, String auth, int userId, boolean stable) {
    final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
    if (provider != null) {
        //成功获取已经存在的ContentProvider对象,则直接返回
        return provider;
    }

    IActivityManager.ContentProviderHolder holder = null;
    try {
        holder = ActivityManagerNative.getDefault().getContentProvider(
                getApplicationThread(), auth, userId, stable);
    } catch (RemoteException ex) {
    }
    if (holder == null) {
        //无法获取auth所对应的provider则直接返回
        return null;
    }

    //安装provider将会增加引用计数
    holder = installProvider(c, holder, holder.info,
            true , holder.noReleaseNeeded, stable);
    return holder.provider;
}

我们已经将AMS中getContentProvider方法分析了下面我们就继续看看如何安装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) {
        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 {
        //得到ContentProvider对象是一个Binder对象
            final java.lang.ClassLoader cl = c.getClassLoader();
            localProvider = (ContentProvider)cl.
                loadClass(info.name).newInstance();
            provider = localProvider.getIContentProvider();
            localProvider.attachInfo(c, info);
        } catch (java.lang.Exception e) {
            if (!mInstrumentation.onException(null, e)) {
            }
            return null;
        }
    } else {
        provider = holder.provider;
    }

    IActivityManager.ContentProviderHolder retHolder;

    synchronized (mProviderMap) {
        IBinder jBinder = provider.asBinder();
        if (localProvider != null) {
        //根据名称查看应用是否已经创建了Provider
            ComponentName cname = new ComponentName(info.packageName, info.name);
            ProviderClientRecord pr = mLocalProvidersByName.get(cname);
            if (pr != null) {
                provider = pr.mProvider;
            } else {
            //当Provider不存在列表中时候,创建并加入到列表
                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, 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;
}

这个方法干什么,主要是和AMS中那个得到Holder的方法对应,如果传递的参数
ContentProviderHolder==null,说明要创建在当前进程中,然后代码就创建一个ContentProvider,如果不等于null说明安装的时其他进程中的ContentProvider的引用,那么做一些引用计数的相关处理。

实际上最终会调用到ContentProvider中的query方法。

怎么理解,就是ContentProvider可以放入到一个进程中,这个进程可以时当前应用所在进程也可以不是。不管怎么样AMS中都有记录,能知道这个进程,当发送消息的时候找到对应Binder,然后进行通信就行。

我们下面就用文字说明一下Provider的进程

1.(Provider进程尚未启动):system_server进程调用startProcessLocked()创建provider进程且attach到system_server后, 通过binder call到provider进程执行AT.bindApplication()方法

2.场景2provider进程已经启动但是没有发布。首先通过AMS获取provider如果发现进程已经存在attach到system_server中但所对应的provider还没有发布, 通过binder call到provider进程执行AT.scheduleInstallProvider方法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,012评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,589评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,819评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,652评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,954评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,381评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,687评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,404评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,082评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,355评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,880评论 1 255
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,249评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,864评论 3 232
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,007评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,760评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,394评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,281评论 2 259

推荐阅读更多精彩内容