四大组件之ContentProviderRecord

一. 引言

作为四大组件之一的ContentProvider,相比来说是设计得稍逊色,有些地方不太合理,比如provider级联被杀, 请求provider时占用system_server的binder线程来wait()等。

即便很少自定义ContentProvider,但你也可以会需要使用到ContentProvider,比如通信录,Settings等; 使用Provider往往跟数据库结合起来使用,所以这里需要注意不要再主线程用provider做过多的io操作。

二. ContentProvider数据结构

先以一幅图来展示AMS管理ContentProvider所涉及的相关数据结构: 点击查看大图

四大组件之ContentProviderRecord_第1张图片

2.1 ContentProviderRecord

  • provider:在ActivityThread的installProvider()过程,会创建ContentProvider对象, 该对象有一个成员变量Transport,继承于ContentProviderNative对象,作为binder服务端。经过binder传递到system_server 进程的便是ContentProvider.Transport的binder代理对象, 由publishContentProviders()过程完成赋值;
  • proc:记录provider所在的进程,是在publishContentProviders()过程完成赋值;
  • launchingApp:记录等待provider所在进程启动,getContentProviderImpl()过程执行创建进程之后赋值;
  • connections:记录该ContentProvider的所有连接信息,
    • 添加连接过程:incProviderCountLocked
    • 减少连接过程:decProviderCountLocked,removeDyingProviderLocked,cleanUpApplicationRecordLocked;
  • externalProcessTokenToHandle: 数据类型为HashMap.
    • AMS.getContentProviderExternalUnchecked()过程会添加externalProcessTokenToHandle值;
    • CPR.hasConnectionOrHandle()或hasExternalProcessHandles()都会判断该变量是否为空.

2.2 ContentProviderConnection

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

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

2.3 ProcessRecord

  • pubProviders: ArrayMap
    • 记录当前进程所有已发布的provider;
  • conProviders: ArrayList
    • 记录当前进程跟其他进程provider所建立的连接

2.4 AMS

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

2.5 ActivityThread

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

三. Provider使用过程

点击查看大图

四大组件之ContentProviderRecord_第2张图片

更多源码详细过程,见理解ContentProvider原理

以上博文转自gityuan的四大组件之ContentProviderRecord

 

------------------------------------------------------分割线--------------------------------------------------

以下是本人的一些备注:

ActivityThread中的相关成员:

mProviderMap:ProviderKey由ContentProvider的authorith和userId组成;mProviderMap里面包含了acquireProvider得来的Transport,也包含和从本进程publish的ContentProvider。就是说ProviderClientRecord是本地Provider和从远端进程获得的Provider共用的一个结构体,即ProviderClientRecord可以表示一个本地Provider,也可以表示从远端进程获得的Provider(后面会称为远端Provider)。如果表示从远端进程获得的Provider,那么ContentProvider mLocalProvider成员为null。ContentProviderHolder是两者都有的一个成员。但是ContentProviderHolder#ContentProviderConnection只有表示从远端进程获得的Provider才不为null。

mProviderRefCountMap:是专门用于对远端Provider计数的。

mLocalProviders和mLocalProvidersByName:两者都只是包含本地Provider,两者的区别只在于key不一样。一个是IContentProvider作为key,一个是ComponentName作为key。

 

ContentProviderRecord创建于ActivityThread调用AMS#attachApplication时(如果Client acquireProvider()时,ContentProviderRecord没创建,则会创建,那么attachApplication时就不会重复创建),而installContentPrivders是在AMS调用IApplicationThread#bindApplication时,在AT中执行的。

AMS#attachApplication

List providers = normalMode ? generateApplicationProvidersLocked(app) : null;

generateApplicationProvidersLocked

    private final List generateApplicationProvidersLocked(ProcessRecord app) {
        List providers = null;
        try {
            providers = AppGlobals.getPackageManager()
                    .queryContentProviders(app.processName, app.uid,
                            STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
                                    | MATCH_DEBUG_TRIAGED_MISSING, /*metadastaKey=*/ null)
                    .getList();
        } catch (RemoteException ex) {
        }
        if (DEBUG_MU) Slog.v(TAG_MU,
                "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
        int userId = app.userId;
        if (providers != null) {
            int N = providers.size();
            app.pubProviders.ensureCapacity(N + app.pubProviders.size());
            for (int i=0; i

ActivityThread#handleBindApplication(AppBindData data)

            // don't bring up providers in restricted mode; they may depend on the
            // app's custom Application class
            if (!data.restrictedBackupMode) {
                if (!ArrayUtils.isEmpty(data.providers)) {
                    installContentProviders(app, data.providers);
                    // For process that contains content providers, we want to
                    // ensure that the JIT is enabled "at some point".
                    mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
                }
            }

 

ContentProviderConnection在应用进程向AMS获取IContentProvider时创建

getContentProviderImpl(IApplicationThread caller,
            String name, IBinder token, boolean stable, int userId)

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

 ContentProviderConnection incProviderCountLocked(ProcessRecord r,
            final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable)

        if (r != null) {
            for (int i=0; i        // Wait for the provider to be published...
        synchronized (cpr) {
            while (cpr.provider == null) {
                if (cpr.launchingApp == null) {
                    Slog.w(TAG, "Unable to launch app "
                            + cpi.applicationInfo.packageName + "/"
                            + cpi.applicationInfo.uid + " for provider "
                            + name + ": launching app became null");
                    EventLog.writeEvent(EventLogTags.AM_PROVIDER_LOST_PROCESS,
                            UserHandle.getUserId(cpi.applicationInfo.uid),
                            cpi.applicationInfo.packageName,
                            cpi.applicationInfo.uid, name);
                    return null;
                }
                try {
                    if (DEBUG_MU) Slog.v(TAG_MU,
                            "Waiting to start provider " + cpr
                            + " launchingApp=" + cpr.launchingApp);
                    if (conn != null) {
                        conn.waiting = true;
                    }
                    cpr.wait();//Object.wait(),在这里等待provider发布
                } catch (InterruptedException ex) {
                } finally {
                    if (conn != null) {
                        conn.waiting = false;
                    }
                }
            }
        }

 

AMS#publishContentProviders()

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) {
                        dst.provider = src.provider;
                        dst.proc = r;
                        dst.notifyAll();//Object.notifyAll(),唤醒在等待队列中的binder线程
                    }

 

你可能感兴趣的:(android系统相关)