美文网首页android之基础学习攻克
ContentProvider相关学习(2)-服务端instal

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

作者: weiinter105 | 来源:发表于2018-12-12 15:37 被阅读0次

    下面主要针对第二种情况,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

    相关文章

      网友评论

        本文标题:ContentProvider相关学习(2)-服务端instal

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