android之基础学习攻克

ContentProvider相关学习(2)-服务端instal

2018-12-12  本文已影响0人  weiinter105

下面主要针对第二种情况,install Provider和publish Provider
注意,从这里开始针对的是服务端了

ActivityThread#scheduleInstallProvider

服务端安装provider

1380        @Override
1381        public void scheduleInstallProvider(ProviderInfo provider) {
1382            sendMessage(H.INSTALL_PROVIDER, provider);
1383        }
1841                case INSTALL_PROVIDER:
1842                    handleInstallProvider((ProviderInfo) msg.obj);
1843                    break;

ActivityThread#handleInstallProvider

3159    public void handleInstallProvider(ProviderInfo info) {
3160        final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
3161        try {
3162            installContentProviders(mInitialApplication, Lists.newArrayList(info));
3163        } finally {
3164            StrictMode.setThreadPolicy(oldPolicy);
3165        }
3166    }

ActivityThread#installContentProviders

5937    private void installContentProviders(
5938            Context context, List<ProviderInfo> providers) {
5939        final ArrayList<ContentProviderHolder> results = new ArrayList<>();
5940
5941        for (ProviderInfo cpi : providers) {
5942            if (DEBUG_PROVIDER) {
5943                StringBuilder buf = new StringBuilder(128);
5944                buf.append("Pub ");
5945                buf.append(cpi.authority);
5946                buf.append(": ");
5947                buf.append(cpi.name);
5948                Log.i(TAG, buf.toString());
5949            }
                  //安装provider
5950            ContentProviderHolder cph = installProvider(context, null, cpi,
5951                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
5952            if (cph != null) {
5953                cph.noReleaseNeeded = true;
5954                results.add(cph);
5955            }
5956        }
5957
5958        try {
                    //发布provider
5959            ActivityManager.getService().publishContentProviders(
5960                getApplicationThread(), results);
5961        } catch (RemoteException ex) {
5962            throw ex.rethrowFromSystemServer();
5963        }
5964    }

ActivityThread#installProvider

前半部分主要是针对服务端的,首次安装ContentProvider时创建实例,并调用onCreate
后半段主要针对客户端,创建客户端需要保存的ProviderRefCount,ContentProviderHolder,ProviderClientRecord等数据结构,并增加相应的引用计数

6367     * Installs the provider.
6368     *
6369     * Providers that are local to the process or that come from the system server
6370     * may be installed permanently which is indicated by setting noReleaseNeeded to true.
6371     * Other remote providers are reference counted.  The initial reference count
6372     * for all reference counted providers is one.  Providers that are not reference
6373     * counted do not have a reference count (at all).
6374     *
6375     * This method detects when a provider has already been installed.  When this happens,
6376     * it increments the reference count of the existing provider (if appropriate)
6377     * and returns the existing provider.  This can happen due to concurrent
6378     * attempts to acquire the same provider.
6379     */
6380    private ContentProviderHolder installProvider(Context context,
6381            ContentProviderHolder holder, ProviderInfo info,
6382            boolean noisy, boolean noReleaseNeeded, boolean stable) {
               //当provider还没起来,用于安装provider时, ContentProviderHolder = null
6383        ContentProvider localProvider = null;
6384        IContentProvider provider;
                //如果provider尚未实例化,则需要在这个宿主进程中进行”安装”
6385        if (holder == null || holder.provider == null) { //holder为null,holder中保存的IContentProvider为null,首次安装
6386            if (DEBUG_PROVIDER || noisy) {
6387                Slog.d(TAG, "Loading provider " + info.authority + ": "
6388                        + info.name);
6389            }
6390            Context c = null;
6391            ApplicationInfo ai = info.applicationInfo;
6392            if (context.getPackageName().equals(ai.packageName)) {
6393                c = context;
6394            } else if (mInitialApplication != null &&
6395                    mInitialApplication.getPackageName().equals(ai.packageName)) {
6396                c = mInitialApplication;
6397            } else {
6398                try {
6399                    c = context.createPackageContext(ai.packageName,
6400                            Context.CONTEXT_INCLUDE_CODE);
6401                } catch (PackageManager.NameNotFoundException e) {
6402                    // Ignore
6403                }
6404            }
6405            if (c == null) {
                    //无法获取context对象则直接返回,用于通过反射创建ContentProvider对象实
6406                Slog.w(TAG, "Unable to get context for package " +
6407                      ai.packageName +
6408                      " while loading content provider " +
6409                      info.name);
6410                return null;
6411            }
6412
6413            if (info.splitName != null) {
6414                try {
6415                    c = c.createContextForSplit(info.splitName);
6416                } catch (NameNotFoundException e) {
6417                    throw new RuntimeException(e);
6418                }
6419            }
6420
6421            try {
6422                final java.lang.ClassLoader cl = c.getClassLoader();
6423                localProvider = (ContentProvider)cl.
6424                    loadClass(info.name).newInstance();
6425                provider = localProvider.getIContentProvider(); //创建ContentProvider实例,并得到其binder代理对象
6426                if (provider == null) {
6427                    Slog.e(TAG, "Failed to instantiate class " +
6428                          info.name + " from sourceDir " +
6429                          info.applicationInfo.sourceDir);
6430                    return null;
6431                }
6432                if (DEBUG_PROVIDER) Slog.v(
6433                    TAG, "Instantiating local provider " + info.name);
6434                // XXX Need to create the correct context for this provider.
6435                localProvider.attachInfo(c, info);
                        //设置ContentProvider的成员变量,并调用其onCreate
6436            } catch (java.lang.Exception e) {
6438                UserManager userManager = (UserManager)c.getSystemService(Context.USER_SERVICE);
6439                if (!userManager.isUserUnlockingOrUnlocked(c.getUserId())
6440                        && !info.directBootAware) {
6441                    Slog.w(TAG, "Current user Id = " + c.getUserId() + " is stopped, "
6442                        + "kill this process!");
                            //将ContentProvider的宿主进程杀掉
6443                    Process.killProcess(Process.myPid());
6444                }
6446                if (!mInstrumentation.onException(null, e)) {
6447                    throw new RuntimeException(
6448                            "Unable to get provider " + info.name
6449                            + ": " + e.toString(), e);
6450                }
6451                return null;
6452            }
6453        } else {
6454            provider = holder.provider;
6455            if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
6456                    + info.name);
6457        }
6458
6459        ContentProviderHolder retHolder;
6460        //进行引用方面的操纵;在宿主进程进行provider的缓存
               //在宿主进程中创建相关的数据结构,进行provider的相关缓存
6461        synchronized (mProviderMap) {
                   //前面是服务端创建ContentProvider实例及对应的IContentProvider操作
                   //下面是关于ProviderClientRecord对象,是用来存储访问过该ContentProvider的客户端的对象
                   //ContentProvider宿主进程(服务端进程)需要保存访问其的客户端进程,这是用于连带死亡时的逻辑
                   //类似于ServiceRecord中的final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
6462            if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
6463                    + " / " + info.name);
                    // 获取provider代理
6464            IBinder jBinder = provider.asBinder();
                   // 如果这个provider在上一个操作刚被创建
6465            if (localProvider != null) {
6466                ComponentName cname = new ComponentName(info.packageName, info.name);
6467                ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                        // 本地缓存
                        
6468                if (pr != null) {
6469                    if (DEBUG_PROVIDER) {
6470                        Slog.v(TAG, "installProvider: lost the race, "
6471                                + "using existing local provider");
6472                    }
6473                    provider = pr.mProvider;
6474                } else {
6475                    holder = new ContentProviderHolder(info);
6476                    holder.provider = provider;
6477                    holder.noReleaseNeeded = true;
                             // 根据Uri authority name进行分类缓存
6478                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
6479                    mLocalProviders.put(jBinder, pr);
6480                    mLocalProvidersByName.put(cname, pr);
6481                }
6482                retHolder = pr.mHolder;
6483            } else {
6484                ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
6485                if (prc != null) {
6486                    if (DEBUG_PROVIDER) {
6487                        Slog.v(TAG, "installProvider: lost the race, updating ref count");
6488                    }
6489                    // We need to transfer our new reference to the existing
6490                    // ref count, releasing the old one...  but only if
6491                    // release is needed (that is, it is not running in the
6492                    // system process).
6493                    if (!noReleaseNeeded) {
6494                        incProviderRefLocked(prc, stable); 
6495                        try {
6496                            ActivityManager.getService().removeContentProvider(
6497                                    holder.connection, stable);
6498                        } catch (RemoteException e) {
6499                            //do nothing content provider object is dead any way
6500                        }
6501                    }
6502                } else {
6503                    ProviderClientRecord client = installProviderAuthoritiesLocked(
6504                            provider, localProvider, holder);
6505                    if (noReleaseNeeded) {
6506                        prc = new ProviderRefCount(holder, client, 1000, 1000);
6507                    } else {
6508                        prc = stable
6509                                ? new ProviderRefCount(holder, client, 1, 0)
6510                                : new ProviderRefCount(holder, client, 0, 1);
6511                    }
6512                    mProviderRefCountMap.put(jBinder, prc);
6513                }
6514                retHolder = prc.holder;
6515            }
6516        }
6517        return retHolder;
6518    }

ActivityThread#installProviderAuthoritiesLocked

6329    private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
6330            ContentProvider localProvider, ContentProviderHolder holder) {
6331        final String auths[] = holder.info.authority.split(";");
6332        final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
6333
6334        if (provider != null) {
6335            // If this provider is hosted by the core OS and cannot be upgraded,
6336            // then I guess we're okay doing blocking calls to it.
6337            for (String auth : auths) {
6338                switch (auth) {
6339                    case ContactsContract.AUTHORITY:
6340                    case CallLog.AUTHORITY:
6341                    case CallLog.SHADOW_AUTHORITY:
6342                    case BlockedNumberContract.AUTHORITY:
6343                    case CalendarContract.AUTHORITY:
6344                    case Downloads.Impl.AUTHORITY:
6345                    case "telephony":
6346                        Binder.allowBlocking(provider.asBinder());
6347                }
6348            }
6349        }
6350
6351        final ProviderClientRecord pcr = new ProviderClientRecord(
6352                auths, provider, localProvider, holder);
6353        for (String auth : auths) {
6354            final ProviderKey key = new ProviderKey(auth, userId);
6355            final ProviderClientRecord existing = mProviderMap.get(key);
6356            if (existing != null) {
6357                Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
6358                        + " already published as " + auth);
6359            } else {
6360                mProviderMap.put(key, pcr);
6361            }
6362        }
6363        return pcr;
6364    }

相当于客户端和服务端都有机会走到installProvider,服务端调用时,都保存了相关的数据结构ProviderClientRecord,ProviderRefCount

5950            ContentProviderHolder cph = installProvider(context, null, cpi,
5951                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);

客户端调用时(aquireProvider中)
//如果ContentProvider install过了,这个功能只是增加引用计数

5872        holder = installProvider(c, holder, holder.info,
5873                true /*noisy*/, holder.noReleaseNeeded, stable);

这样是为了使installProvider这个函数公用,客户端主要是用其来增加
引用计数,服务端是用来创建ContentProvider实例的

ActivityManagerService#publishContentProviders

将创建的ContentProviderRecord这种数据结构保存在AMS中的mProviderMap和ProcessRecord.pubProviders

12302    public final void publishContentProviders(IApplicationThread caller,
12303            List<ContentProviderHolder> providers) {
12304        if (providers == null) {
12305            return;
12306        }
12307
12308        enforceNotIsolatedCaller("publishContentProviders");
12309        synchronized (this) {
12310            final ProcessRecord r = getRecordForAppLocked(caller);
                      //获取provider宿主进程
12311            if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
12312            if (r == null) {
12313                throw new SecurityException(
12314                        "Unable to find app for caller " + caller
12315                      + " (pid=" + Binder.getCallingPid()
12316                      + ") when publishing content providers");
12317            }
12318
12319            final long origId = Binder.clearCallingIdentity();
12320
12321            final int N = providers.size();
12322            for (int i = 0; i < N; i++) {
12323                ContentProviderHolder src = providers.get(i);
12324                if (src == null || src.info == null || src.provider == null) {
12325                    continue;
12326                }
12327                ContentProviderRecord dst = r.pubProviders.get(src.info.name);  //从服务端进程得到ContentProviderRecord
12328                if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
12329                if (dst != null) {
12330                    ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
                              //将ContentProviderRecord加入到mProviderMap中
12331                    mProviderMap.putProviderByClass(comp, dst);
12332                    String names[] = dst.info.authority.split(";");
12333                    for (int j = 0; j < names.length; j++) {
12334                        mProviderMap.putProviderByName(names[j], dst);
12335                    }
12336                    //将服务端创建的ContentProviderRecord结构添加到AMS中,相当于publish
12337                    int launchingCount = mLaunchingProviders.size();
12338                    int j;
12339                    boolean wasInLaunchingProviders = false;
12340                    for (j = 0; j < launchingCount; j++) {
12341                        if (mLaunchingProviders.get(j) == dst) { 
                                     //正式publish之后,从mLaunchingProviders移除相关ContentProviderRecord
12342                            mLaunchingProviders.remove(j);
12343                            wasInLaunchingProviders = true;
12344                            j--;
12345                            launchingCount--;
12346                        }
12347                    }
12348                    if (wasInLaunchingProviders) {
12349                        mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r); 
                                 //对应发送的地方在attachApplicationLocked中,对应宿主进程启动的地方
12350                    }
12351                    synchronized (dst) {
12352                        dst.provider = src.provider;
12353                        dst.proc = r;
12354                        dst.notifyAll();  //唤醒AMS中的wait方法,在getContentProviderImpl中等待
12355                    }
12356                    updateOomAdjLocked(r, true);
12357                    maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
12358                            src.info.authority);
12359                }
12360            }
12361
12362            Binder.restoreCallingIdentity(origId);
12363        }
12364    }

AMS缓存ContentProviderRecord后,客户端也会缓存ContentProviderRecord,在acquireExistingProvider中就已获得IContentProvider,后续无需通过AMS,而是直接通过IContentProvider binder proxy来调用ContentProvider实例的override函数,类似bindService中的onServiceConnected的IBinder,代表Service binder proxy

这里最后理一下ContentProvider客户端操作时的大致流程:
1.首先有一个进程A需要使用B进程的Provider,通过binder call到system_server查询;在system_server中进行判断要请求的provider是否已经正在运行,也就是要请求的provider是否由B进程已经publish过了
2.1 如果要请求的provider已经在运行,那么就建立A和B之间的链接,并返回一个ContentProviderHolder
2.2 如果要请求的provider不在运行,那么首先需要启动B进程,并把需要provider增加到mLaunchingProviders中
2.2.1 B进程在启动过程中attach到system_server的时候会设置一个10s的定时消息,然后在bindApplication中客户端执行installProvider
2.2.2 B进程installProvider成功之后,会publish provider到system_server,并移除上面的10s的定时消息
2.3 因为启动进程的过程是异步的,所以在等待对方进程启动并publish的时候,通过A进程binder call到system_server的线程一直会处在wait状态,直到等待的provider被publish或者由于进程被杀/启动超时等原因被remove掉


ContentProvider_query.png
上一篇下一篇

猜你喜欢

热点阅读