首页 > 其他分享 >Android Framework AMS(15)ContentProvider分析-2(getContentResolver及ContentResolver.query流程解读)

Android Framework AMS(15)ContentProvider分析-2(getContentResolver及ContentResolver.query流程解读)

时间:2024-11-15 20:17:14浏览次数:3  
标签:... ContentProvider 15 getContentResolver ContentResolver provider cpr null hold

该系列文章总纲链接:专题总纲目录 Android Framework 总纲


本章关键点总结 & 说明:

说明:本章节主要解读ContentProvider组件的基本知识。关注思维导图中左上侧部分即可。

有了前面activity组件分析、service组件分析、广播组件分析、ContentProvider组件的基本流程分析、基于此,接下来我们来分析上一章节提到的第2个流程。ContentProvider组件的基本流程,ContentProvider主要涉及2个:

  1. ContentProvider的注册,开即启动后解析和处理ContentProvider组件。
  2. getContentResolver,然后执行对应ContentProvider.query方法。

本章,我们详细分析第二个流程。结合代码,主要针对这两句关键的语句来进行分析,代码如下:

ContentResolver contentResolver = getContentResolver();
Cursor cursor = contentResolver.query(CONTENT_URI, null, null, null, null);

接下来开始我们的详细分析。

1 getContentResolver流程完整解读

Context.getContentResolver方法是从Context中的getContentResolver开始调用的,接口代码实现如下:

//Context
    public abstract ContentResolver getContentResolver();

其真正的实现是在ContextImpl中,代码实现如下:


//ContextImpl
    private final ApplicationContentResolver mContentResolver;
    @Override
    public ContentResolver getContentResolver() {
        return mContentResolver;
    }

这里直接返回了一个ApplicationContentResolver类型的成员变量mContentResolver。这里我们关注ApplicationContentResolver类,该类的解读如下:

//ContextImpl
private static final class ApplicationContentResolver extends ContentResolver {
    // 成员变量,保存主线程ActivityThread的引用和用户标识UserHandle
    private final ActivityThread mMainThread;
    private final UserHandle mUser;

    // 构造函数,接收Context、ActivityThread和UserHandle对象,并保存到成员变量
    public ApplicationContentResolver(
            Context context, ActivityThread mainThread, UserHandle user) {
        super(context); // 调用父类的构造函数
        mMainThread = Preconditions.checkNotNull(mainThread); // 确保主线程对象不为空
        mUser = Preconditions.checkNotNull(user); // 确保用户对象不为空
    }

    // 重写acquireProvider方法,用于获取一个稳定的ContentProvider连接
    @Override
    protected IContentProvider acquireProvider(Context context, String auth) {
        return mMainThread.acquireProvider(context, // 主线程对象
                ContentProvider.getAuthorityWithoutUserId(auth), // 从auth中解析出authority
                resolveUserIdFromAuthority(auth), true); // 获取provider,true表示稳定的连接
    }

    // 重写acquireExistingProvider方法,用于获取一个已经存在的ContentProvider连接
    @Override
    protected IContentProvider acquireExistingProvider(Context context, String auth) {
        return mMainThread.acquireExistingProvider(context, // 主线程对象
                ContentProvider.getAuthorityWithoutUserId(auth), // 从auth中解析出authority
                resolveUserIdFromAuthority(auth), true); // 获取provider,true表示稳定的连接
    }

    // 重写releaseProvider方法,用于释放一个ContentProvider连接
    @Override
    public boolean releaseProvider(IContentProvider provider) {
        return mMainThread.releaseProvider(provider, true); // 释放provider,true表示稳定的连接
    }

    // 重写acquireUnstableProvider方法,用于获取一个不稳定的ContentProvider连接
    @Override
    protected IContentProvider acquireUnstableProvider(Context c, String auth) {
        return mMainThread.acquireProvider(c, // 上下文对象
                ContentProvider.getAuthorityWithoutUserId(auth), // 从auth中解析出authority
                resolveUserIdFromAuthority(auth), false); // 获取provider,false表示不稳定的连接
    }

    // 重写releaseUnstableProvider方法,用于释放一个不稳定的ContentProvider连接
    @Override
    public boolean releaseUnstableProvider(IContentProvider icp) {
        return mMainThread.releaseProvider(icp, false); // 释放provider,false表示不稳定的连接
    }

    // 重写unstableProviderDied方法,当一个不稳定的ContentProvider死亡时调用
    @Override
    public void unstableProviderDied(IContentProvider icp) {
        mMainThread.handleUnstableProviderDied(icp.asBinder(), true); // 处理provider死亡,true表示稳定的连接
    }

    // 重写appNotRespondingViaProvider方法,当ContentProvider无响应时调用
    @Override
    public void appNotRespondingViaProvider(IContentProvider icp) {
        mMainThread.appNotRespondingViaProvider(icp.asBinder()); // 处理provider无响应
    }

    // 解析authority中包含的用户ID
    /** @hide */
    protected int resolveUserIdFromAuthority(String auth) {
        return ContentProvider.getUserIdFromAuthority(auth, mUser.getIdentifier()); // 根据authority和用户标识解析用户ID
    }
}

这个内部类ApplicationContentResolver主要负责管理ContentProvider的生命周期,包括获取和释放稳定的或不稳定的ContentProvider连接。它通过ActivityThread来实际获取ContentProvider的代理对象,并处理ContentProvider的异常情况,如无响应或崩溃。这个类是Android系统中ContentResolver机制的一部分,用于确保ContentProvider的稳定性和正确性。

本质上这里就是获取了该类型的一个成员变量,接下来在query的流程中我们会使用该类中的一些方法,比如acquireProvider、releaseProvider等。

2 ContentResolver的query查询流程解读

ContentResolver.query 方法在ApplicationContentResolver中没有实现,因此我们看它的父类ContentResolver中的代码实现,具体如下:

//ContentResolver
    //关键流程:step1
    public final Cursor query(Uri uri, String[] projection,
            String selection, String[] selectionArgs, String sortOrder) {
        return query(uri, projection, selection, selectionArgs, sortOrder, null);
    }
    //关键流程:step2
    public final Cursor query(final Uri uri, String[] projection,
        String selection, String[] selectionArgs, String sortOrder,
        CancellationSignal cancellationSignal) {
        // 获取一个不稳定的ContentProvider连接
        IContentProvider unstableProvider = acquireUnstableProvider(uri);
        if (unstableProvider == null) {
            return null; // 如果获取失败,返回null
        }
        IContentProvider stableProvider = null; // 用于存储稳定的ContentProvider连接
        Cursor qCursor = null; // 用于存储查询结果的Cursor对象

        try {
            long startTime = SystemClock.uptimeMillis(); // 记录查询开始时间

            // 如果提供了CancellationSignal,则创建远程取消信号,并设置关联
            ICancellationSignal remoteCancellationSignal = null;
            if (cancellationSignal != null) {
                cancellationSignal.throwIfCanceled(); // 检查是否已经取消
                remoteCancellationSignal = unstableProvider.createCancellationSignal(); // 创建远程取消信号
                cancellationSignal.setRemote(remoteCancellationSignal); // 设置远程取消信号
            }
            try {
                // 通过不稳定的ContentProvider执行查询
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            } catch (DeadObjectException e) {
                // 如果ContentProvider死亡,则标记为不稳定,并尝试获取一个新的稳定的ContentProvider
                unstableProviderDied(unstableProvider);
                stableProvider = acquireProvider(uri); // 获取稳定的ContentProvider
                if (stableProvider == null) {
                    return null; // 如果获取失败,返回null
                }
                // 使用新的稳定的ContentProvider执行查询
                qCursor = stableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            }
            if (qCursor == null) {
                return null; // 如果查询结果为空,返回null
            }

            // 获取查询结果的行数,并计算查询持续时间
            qCursor.getCount();
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder); // 记录查询日志

            // 将查询结果的Cursor包装成CursorWrapperInner对象
            CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
                    stableProvider != null ? stableProvider : acquireProvider(uri));
            stableProvider = null; // 重置stableProvider
            qCursor = null; // 重置qCursor
            return wrapper; // 返回包装后的Cursor对象
        } catch (RemoteException e) {
            return null; // 如果发生远程异常,返回null
        } finally {
            // 最后,关闭查询结果的Cursor,并释放ContentProvider连接
            if (qCursor != null) {
                qCursor.close();
            }
            if (cancellationSignal != null) {
                cancellationSignal.setRemote(null); // 清除远程取消信号
            }
            if (unstableProvider != null) {
                releaseUnstableProvider(unstableProvider); // 释放不稳定的ContentProvider
            }
            if (stableProvider != null) {
                releaseProvider(stableProvider); // 释放稳定的ContentProvider
            }
        }
    }

query方法是一个用于从ContentProvider查询数据并返回Cursor对象的过程,它首先尝试通过不稳定的ContentProvider进行查询,如果遇到DeadObjectException异常,则会获取一个稳定的ContentProvider重新查询。查询成功后,方法会记录查询日志,并将结果Cursor包装在CursorWrapperInner对象中返回。如果在查询过程中发生远程异常或者查询结果为空,则会返回null。此外,方法还会处理CancellationSignal以支持查询的取消操作,并在最后释放所有相关资源。

这里我们要知道,ContentProvider的核心代码就是从acquireProvider中获取provider,然后执行query操作。那么为什么非要搞出一个unstable的provider呢?先尝试从不稳定(unstable)的ContentProvider获取数据,如果失败再从稳定(stable)的ContentProvider获取,是基于性能和资源管理的考虑。详细解读如下:

  • 性能优化:不稳定的ContentProvider连接(acquireUnstableProvider)通常比稳定的连接(acquireProvider)更快地建立,因为它们不需要进行额外的状态检查和同步操作。这意味着,如果ContentProvider是健康的,使用不稳定连接可以减少查询的延迟,提高性能。
  • 资源管理:稳定的ContentProvider连接需要更多的资源来维护,因为它们需要确保在ContentProvider的整个生命周期内保持稳定。如果每次查询都直接使用稳定的连接,可能会导致不必要的资源占用,特别是在高频率查询的场景下。
  • 容错机制DeadObjectException异常表明ContentProvider可能已经崩溃或不稳定。在这种情况下,系统会尝试获取一个新的稳定的ContentProvider连接,这可以看作是一种容错机制。通过这种方式,系统可以确保即使在ContentProvider不稳定的情况下,也能够尽可能地提供服务。

这种设计允许系统在大多数情况下快速响应查询请求,同时在遇到异常时能够提供一种可靠的后备方案,确保系统的鲁棒性和数据的一致性。

接下来我们分析acquireProvider获取provider的具体流程。

2.1 acquireProvider流程详细解读

从之前的分析中可知,这里的acquireProvider实际上就是ContentProvider的子类ApplicationContentResolver中的方法,对应的代码实现如下:

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

这里可以看出是调用ActivityThread中的acquireProvider方法,对应代码实现如下:

//ActivityThread
    public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
        // 尝试获取一个已经存在的ContentProvider实例
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            // 如果已经存在,直接返回这个provider
            return provider;
        }

        // 如果不存在,尝试从ActivityManager获取ContentProviderHolder
        IActivityManager.ContentProviderHolder holder = null;
        try {
            // 通过ActivityManager的getContentProvider方法获取ContentProviderHolder
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), auth, userId, stable);
        } catch (RemoteException ex) {
            //...
        }
        if (holder == null) {
            return null;
        }

        // 如果成功获取到holder,调用installProvider方法来安装provider
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        // 返回安装后的provider实例
        return holder.provider;
    }

这里针对3个关键点进行分析:acquireExistingProvider、AMS的getContentProvider方法调用(因为ActivityManagerNative.getDefault().getContentProvider本质上就是调用AMS的getContentProvider方法)、installProvider方法,分别进行解读。

2.1.1 acquireExistingProvider方法解读

acquireExistingProvider代码实现如下:

//ActivityThread
    public final IContentProvider acquireExistingProvider(
            Context c, String auth, int userId, boolean stable) {
        synchronized (mProviderMap) {
            // 创建一个ProviderKey对象,用于标识ContentProvider的authority和用户ID
            final ProviderKey key = new ProviderKey(auth, userId);
            // 从mProviderMap中获取对应的ProviderClientRecord对象
            final ProviderClientRecord pr = mProviderMap.get(key);
            if (pr == null) {
                // 如果没有找到对应的ProviderClientRecord,返回null
                return null;
            }

            // 获取IContentProvider实例
            IContentProvider provider = pr.mProvider;
            // 获取IBinder实例,用于与ContentProvider进行通信
            IBinder jBinder = provider.asBinder();
            // 检查Binder是否存活,即ContentProvider的进程是否还活着
            if (!jBinder.isBinderAlive()) {
                // 处理不稳定的ContentProvider死亡情况
                handleUnstableProviderDiedLocked(jBinder, true);
                return null;
            }

            // 如果ProviderRefCount不为null,说明这个provider是引用计数的,需要增加引用计数
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc != null) {
                // 增加引用计数
                incProviderRefLocked(prc, stable);
            }
            // 返回IContentProvider实例
            return provider;
        }
    }

acquireExistingProvider方法用于尝试获取一个已经存在的ContentProvider实例,它通过检查mProviderMap映射表来查找与给定authority和用户ID对应的ProviderClientRecord。如果找到,并且对应的IBinder是活跃的,那么方法会增加该ContentProvider的引用计数(如果需要),并返回IContentProvider实例;如果Binder不活跃或没有找到对应的ProviderClientRecord,则返回null。这个方法确保了对现有ContentProvider实例的安全访问,并处理了ContentProvider进程可能已经死亡的情况。

2.1.2 AMS.getContentProvider方法解读

AMS.getContentProvider代码实现如下:

//AMS
    //关键流程:step1
    @Override
    public final ContentProviderHolder getContentProvider(
            IApplicationThread caller, String name, int userId, boolean stable) {
        enforceNotIsolatedCaller("getContentProvider");
        if (caller == null) {
            //...
        }
        return getContentProviderImpl(caller, name, null, stable, userId);
    }
    //关键流程:step2
    private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, boolean stable, int userId) {
        // 初始化ContentProviderRecord、ContentProviderConnection和ProviderInfo对象
        ContentProviderRecord cpr;
        ContentProviderConnection conn = null;
        ProviderInfo cpi = null;

        synchronized(this) {
            // 记录方法开始执行的时间
            long startTime = SystemClock.elapsedRealtime();

            // 获取调用者的ProcessRecord
            ProcessRecord r = null;
            //...

            // 检查是否需要跨用户访问ContentProvider
            boolean checkCrossUser = true;
            // 根据名称和用户ID获取ContentProviderRecord
            cpr = mProviderMap.getProviderByName(name, userId);
            // 如果没有找到,并且用户ID不是主用户,则尝试获取主用户的ContentProvider
            if (cpr == null && userId != UserHandle.USER_OWNER) {
                cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
                if (cpr != null) {
                    cpi = cpr.info;
                    // 如果是单例ContentProvider,并且调用合法,则使用主用户的ContentProvider
                    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;
                    }
                }
            }

            // 检查ContentProvider是否正在运行
            boolean providerRunning = cpr != null;
            if (providerRunning) {
                cpi = cpr.info;
                //...

                // 如果调用者可以在这个应用中运行ContentProvider,则直接返回一个新的ContentProviderHolder
                if (r != null && cpr.canRunHere(r)) {
                    ContentProviderHolder holder = cpr.newHolder(null);
                    holder.provider = null;
                    return holder;
                }

                // 增加ContentProvider的引用计数
                final long origId = Binder.clearCallingIdentity();
                conn = incProviderCountLocked(r, cpr, token, stable);
                //...

                Binder.restoreCallingIdentity(origId);
            }

            // 如果ContentProvider尚未运行,则尝试解析ContentProvider的信息
            boolean singleton;
            if (!providerRunning) {
                try {
                    cpi = AppGlobals.getPackageManager().resolveContentProvider(name,
                            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
                } catch (RemoteException ex) {
                }
                //...
                // 如果是单例ContentProvider,并且调用合法,则使用主用户的ContentProvider
                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);
                //...

                // 获取ContentProvider的ComponentName
                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 {
                        ApplicationInfo ai =
                            AppGlobals.getPackageManager().getApplicationInfo(cpi.applicationInfo.packageName,STOCK_PM_FLAGS, userId);
                        //...
                        ai = getAppInfoForUser(ai, userId);
                        cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
                    } catch (RemoteException ex) {
                        //...
                    } finally {
                        Binder.restoreCallingIdentity(ident);
                    }
                }

                // 如果调用者可以在这个应用中运行ContentProvider,则直接返回一个新的ContentProviderHolder
                if (r != null && cpr.canRunHere(r)) {
                    return cpr.newHolder(null);
                }

                // 检查是否已经在启动ContentProvider的列表中
                final int N = mLaunchingProviders.size();
                int i;
                for (i=0; i<N; i++) {
                    if (mLaunchingProviders.get(i) == cpr) {
                        break;
                    }
                }

                // 如果不在启动列表中,则启动ContentProvider
                if (i >= N) {
                    final long origId = Binder.clearCallingIdentity();
                    try {
                        try {
                            AppGlobals.getPackageManager().setPackageStoppedState(cpr.appInfo.packageName, false, userId);
                        } catch (Exception e) {
                            //...
                        }
                        ProcessRecord proc = getProcessRecordLocked(
                                cpi.processName, cpr.appInfo.uid, false);
                        if (proc != null && proc.thread != null) {
                            proc.pubProviders.put(cpi.name, cpr);
                            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);
                            //...
                        }
                        cpr.launchingApp = proc;
                        mLaunchingProviders.add(cpr);
                    } finally {
                        Binder.restoreCallingIdentity(origId);
                    }
                }

                // 如果是首次创建ContentProviderRecord,则添加到映射中
                if (firstClass) {
                    mProviderMap.putProviderByClass(comp, cpr);
                }

                // 将ContentProvider添加到映射中
                mProviderMap.putProviderByName(name, cpr);
                conn = incProviderCountLocked(r, cpr, token, stable);
                if (conn != null) {
                    conn.waiting = true;
                }
            }
        }

        // 等待ContentProvider被创建
        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;
                    }
                }
            }
        }
        // 返回ContentProviderHolder对象
        return cpr != null ? cpr.newHolder(conn) : null;
    }

getContentProviderImpl方法用于获取一个ContentProviderHolder对象,该对象封装了对ContentProvider的引用以及与之相关的信息。如果ContentProvider已经存在并且可以被调用者访问,则直接返回一个新的ContentProviderHolder。如果ContentProvider尚未运行,则解析其信息并启动它。如果ContentProvider是单例并且调用合法,则使用主用户的ContentProvider。

该方法还处理了跨用户访问和进程启动的逻辑。解读如下:

  • 如果ProcessRecord不为空,说明进程已经启动,则在该进程中安装ContentProvider。
  • 如果ProcessRecord不存在或其thread为空,说明需要启动一个新的进程。startProcessLocked方法用于启动新进程,它需要进程名、应用信息、标志、进程组ID、进程名称、组件名等参数。

最后,若ContentProvider成功创建,则返回包含ContentProvider引用的ContentProviderHolder;否则,返回null。

2.1.3 installProvider方法解读

installProvider方法代码实现如下:

//ActivityThread
    private IActivityManager.ContentProviderHolder installProvider(Context context,
        IActivityManager.ContentProviderHolder holder, ProviderInfo info,
        boolean noisy, boolean noReleaseNeeded, boolean stable) {
        ContentProvider localProvider = null;
        IContentProvider provider;
        // 如果传入的holder或holder中的provider为空,则创建一个新的ContentProvider实例
        if (holder == null || holder.provider == null) {
            Context c = null;
            ApplicationInfo ai = info.applicationInfo;
            // 尝试获取Context对象,用于创建ContentProvider
            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) {
                    //...
                }
            }
            // 创建ContentProvider实例
            try {
                final java.lang.ClassLoader cl = c.getClassLoader();
                localProvider = (ContentProvider)cl.loadClass(info.name).newInstance();
                provider = localProvider.getIContentProvider();
                if (provider == null) {
                    return null;
                }
                localProvider.attachInfo(c, info);
            } catch (java.lang.Exception e) {
                //...
            }
        } else {
            // 如果holder非空,则直接使用holder中的provider
            provider = holder.provider;
        }

        IActivityManager.ContentProviderHolder retHolder;
        synchronized (mProviderMap) {
            IBinder jBinder = provider.asBinder();
            // 如果localProvider非空,表示这是一个本地ContentProvider
            if (localProvider != null) {
                ComponentName cname = new ComponentName(info.packageName, info.name);
                ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                if (pr != null) {
                    provider = pr.mProvider;
                } else {
                    holder = new IActivityManager.ContentProviderHolder(info);
                    holder.provider = provider;
                    holder.noReleaseNeeded = true;
                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                    mLocalProviders.put(jBinder, pr);
                    mLocalProvidersByName.put(cname, pr);
                }
                retHolder = pr.mHolder;
            } else {
                // 对于非本地ContentProvider,处理引用计数和生命周期管理
                ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
                if (prc != null) {
                    if (!noReleaseNeeded) {
                        incProviderRefLocked(prc, stable);
                        try {
                            ActivityManagerNative.getDefault().removeContentProvider(
                                    holder.connection, stable);
                        } catch (RemoteException e) {
                            //...
                        }
                    }
                } 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;
    }

installProvider方法负责根据提供的ContentProviderHolder和ProviderInfo安装一个ContentProvider。如果holder或holder.provider为空,实际上会创建一个新的ContentProvider实例,但本流程中不涉及。方法内部会处理本地和非本地ContentProvider的安装,更新引用计数,并管理ContentProvider的生命周期。最终,方法返回安装好的ContentProvider的ContentProviderHolder。

至此,acquireProvider的3个关键流程就解读完了。这里接下来就是调用对应ContentProvider的query操作了。接下来主要针对acquireProvider中AMS.getContentProvider的启动流程进行分析,因为这里也会涉及ContentProvider的初始化相关操作。

2.2 AMS.getContentProvider启动流程分析

从之前2.1.2 中AMS.getContentProvider的启动流程进行分析。如果ProcessRecord不存在或其thread为空,说明需要启动一个新的进程。startProcessLocked方法用于启动新进程,启动相关的代码可参考文章:

Android Framework AMS(04)startActivity分析-1(am启动到ActivityThread启动)

Android Framework AMS(05)startActivity分析-2(ActivityThread启动到Activity拉起)

这里我们主要从AMS的attachApplicationLocked方法入手进行分析。代码实现如下:

//AMS
    private final boolean attachApplicationLocked(IApplicationThread thread,
            int pid) {
        ProcessRecord app;
        // 根据传入的pid获取对应的ProcessRecord对象
        if (pid != MY_PID && pid >= 0) {
            synchronized (mPidsSelfLocked) {
                app = mPidsSelfLocked.get(pid); // 从mPidsSelfLocked中获取ProcessRecord
            }
        } else {
            app = null; // 如果pid无效,则设置app为null
        }

        // 检查应用程序是否处于正常模式
        boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
        //关键代码1:如果在正常模式下,生成应用程序的ContentProvider信息
        List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;

        try {
            //...
            //关键代码2:绑定应用程序到指定的线程
            thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                    profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                    app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                    isRestrictedBackupMode || !normalMode, app.persistent,
                    new Configuration(mConfiguration), app.compat,
                    getCommonServicesLocked(app.isolated),
                    mCoreSettingsObserver.getCoreSettingsLocked());
            // 更新最近使用的进程列表
            updateLruProcessLocked(app, false, null);
            //...
        } catch (Exception e) {
            //...
        }
        //...
        return true;
    }

这里我们主要关注generateApplicationProvidersLocked方法和ActivityThread的bindApplication方法,前者是通过PMS获取provider,后者是绑定App后的处理。

2.2.1 generateApplicationProvidersLocked方法解读

generateApplicationProvidersLocked方法,它的代码实现如下:

//AMS
    private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
        List<ProviderInfo> providers = null;
        try {
            // 尝试查询PackageManager以获取该应用程序进程名下的所有ContentProvider信息
            providers = AppGlobals.getPackageManager().
                queryContentProviders(app.processName, app.uid,
                        STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
        } catch (RemoteException ex) {
            //...
        }
        
        int userId = app.userId;
        if (providers != null) {
            int N = providers.size();
            // 确保pubProviders的容量足够
            app.pubProviders.ensureCapacity(N + app.pubProviders.size());
            for (int i=0; i<N; i++) {
                ProviderInfo cpi = (ProviderInfo)providers.get(i);
                // 检查ContentProvider是否是单例,并且不是主用户的ContentProvider
                boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                        cpi.name, cpi.flags);
                if (singleton && UserHandle.getUserId(app.uid) != 0) {
                    // 如果是单例并且不是主用户的ContentProvider,则移除
                    providers.remove(i);
                    N--;
                    i--;
                    continue;
                }

                // 创建ComponentName对象,用于标识ContentProvider
                ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                // 尝试从mProviderMap中获取现有的ContentProviderRecord
                ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
                if (cpr == null) {
                    // 如果不存在,则创建新的ContentProviderRecord
                    cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
                    mProviderMap.putProviderByClass(comp, cpr);
                }
                // 将ContentProviderRecord添加到应用程序的pubProviders映射中
                app.pubProviders.put(cpi.name, cpr);
                // 如果ContentProvider不是多进程的,或者不是系统应用,则添加包名到应用程序的包列表中
                if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
                    app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
                            mProcessStats);
                }
                // 确保包的Dex优化完成
                ensurePackageDexOpt(cpi.applicationInfo.packageName);
            }
        }
        // 返回ContentProvider列表
        return providers;
    }

generateApplicationProvidersLocked方法负责生成和返回一个应用程序提供的ContentProvider列表。它查询PackageManager以获取ContentProvider信息,创建ContentProviderRecord,并进行必要的初始化和配置。这个方法确保了应用程序的ContentProvider可以被正确地管理和访问。

关于queryContentProviders功能解读:开机启动后PMS存储了解析各个APP中AndroidManifest.xml定义的ContentProviders信息。通过queryContentProviders可以查询到这些信息。了解更多,可参考上一章节文章:

标签:...,ContentProvider,15,getContentResolver,ContentResolver,provider,cpr,null,hold
From: https://blog.csdn.net/vviccc/article/details/143694653

相关文章

  • 大数据学习15之Scala集合与泛型
    1.概述        大部分编程语言都提供了数据结构对应的编程库,并称之为集合库(CollectionLibrary),Scala也不例外,且它还拥有以下优点:易用:灵活组合运用集合库提供的方法,可以解决大部分集合问题简洁:拜类型推断和函数式编程所赐,帮助程序员写出更简洁,更优雅的代码安全:......
  • SS241115C. 排序(sort)
    SS241115C.排序(sort)题意给你一个长度为\(n\)的序列\(a\),每次操作对\([1,\frac{n}{2}],[\frac{n}{2}+1,n]\)进行归并排序。有\(q\)次询问,给出\(t,x\),问进行\(t\)次操作后\(a_x\)的值。思路考虑一次操作发生了什么。假设\(x<y\),那么\(x\)和它后面的一坨都会排......
  • Android15音频进阶之input调节CarAudioService音量过程(九十四)
    简介:CSDN博客专家、《Android系统多媒体进阶实战》一书作者新书发布:《Android系统多媒体进阶实战》......
  • 比赛讲解:图论算法(11.11~11.15)
    图论算法T1-U502532找水杯一道水题,基本上和P4779一样(我连样例都搬过来了,能不一样吗?)所以呢,你们可以直接用\(Dijikstra\)1.最初起点到达所有点的距离都是未知的,记作无穷大。2.在对起点的邻接点进行扫描后发现,起点可以通过某些边抵达一些节点,那么就更新d数组(d[i]用于记录起点s......
  • 2024.11.15 test
    A一个\(n\timesm\)的矩形已经给出了\(k\)个位置的数,判断是否有方案使得填入非负整数后,每一个\(2\times2\)的子矩形都满足左上+右下=左下+右上。\(n,m,k\le1e5\)。注意到,矩形合法的条件可以转化为对于任意相邻的两列,在每行中,这两列值的差都相同。也就是对于所有行的每......
  • 11.15随笔
    这里是11.15随笔。前两天玩的有点欢,忘写随笔了。作业留档:有两张非递增有序的线性表A,B,采用顺序存储结构,两张表合并用c表存,要求C为非递减有序的,然后删除C表中值相同的多余元素。元素类型为整型输入格式:第一行输入输入表A的各个元素,以-1结束,中间用空格分隔;第二行输入表B的各个元......
  • 深入理解 MySQL 大小写敏感性:配置、问题与实践指南20241115
    深入理解MySQL大小写敏感性:配置、问题与实践指南在开发和部署MySQL数据库时,表名的大小写敏感性问题常常被忽略,却可能在跨平台迁移、团队协作或工具兼容性方面引发复杂的故障。本文将结合实际案例,深入探讨MySQL的lower_case_table_names参数,剖析其行为、配置方法以......
  • 列表数据隔离--采购申请单只能看当前用户的单据信息 过滤,PrepareFilterParameter 2
    region<<版本注释>>/*===================================================类名称:PUR_Requisition_listFilter类描述:列表数据隔离--采购申请单只能看当前用户的单据信息过滤,PrepareFilterParameter创建人:luohong创建时间:2024/11/1516:18:04电子邮箱:it_lu......
  • 2024.11.15 NOIP 模拟 - 模拟赛记录
    返乡(home)不给大样例是怕我找规律出答案吗?但是我还是找到规律了。题解说是结论题,但是这个结论即使观察小样例也很好猜(如果我是出题人就把样例打乱一下顺序)。首先考虑只有二维偏序时的最优放置方法:首先第一个数是不能重复的,因为一旦重复,第二个数无论怎么选,都会构成偏序;第二个......
  • 241115 noip 模拟赛
    省流:\(90+100+25+10\)。T1题意:给定一个长为\(n\)的排列,定义一次操作为选出排列中至多\(4\)个不同的数,将它们任意重排,求最少操作次数让这个排列单调递增。\(n\leq10^6\)。找出排列的所有置换环,设环长为\(t_1,t_2,t_3,\cdots,t_m\),则答案为:\[\sum_{i=1}^m\lflo......