美文网首页
谈谈AMS管理ContentProvider

谈谈AMS管理ContentProvider

作者: 我叫王菜鸟 | 来源:发表于2017-11-01 20:47 被阅读0次

    重要数据结

    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方法

    相关文章

      网友评论

          本文标题:谈谈AMS管理ContentProvider

          本文链接:https://www.haomeiwen.com/subject/vcfnpxtx.html