美文网首页android菜鸟笔记
ContentProvider流程解析

ContentProvider流程解析

作者: 李发糕 | 来源:发表于2019-08-08 22:44 被阅读0次

    ContentProvider流程分析

    我们先从数据请求的客户端进行分析,我们通过getContentResolver获取contentResolver

    @Override
        public ContentResolver getContentResolver() {
            return mBase.getContentResolver();
        }
    

    我们就随便选一个方法进行分析 比如delete

    public final int delete(@RequiresPermission.Write @NonNull Uri url, @Nullable String where,
                @Nullable String[] selectionArgs) {
            Preconditions.checkNotNull(url, "url");
            IContentProvider provider = acquireProvider(url);//获取provider的ibinder
            if (provider == null) {
                throw new IllegalArgumentException("Unknown URL " + url);
            }
            try {
                long startTime = SystemClock.uptimeMillis();
                int rowsDeleted = provider.delete(mPackageName, url, where, selectionArgs);//调用delete方法
                long durationMillis = SystemClock.uptimeMillis() - startTime;
                maybeLogUpdateToEventLog(durationMillis, url, "delete", where);
                return rowsDeleted;
            } catch (RemoteException e) {
                // Arbitrary and not worth documenting, as Activity
                // Manager will kill this process shortly anyway.
                return -1;
            } finally {
                releaseProvider(provider);//释放
            }
        }
    

    acquireProvider方法一路跟踪下去,ActivityThread中的ApplicationContentResolver实现了此方法

    ActivityThread

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

    可以看到,直接调用了activityThread的acquireProvider方法

    在看这个方法之前,我们先看几个相关的类

    ContentProviderHolder
    public class ContentProviderHolder implements Parcelable {
        public final ProviderInfo info;
        public IContentProvider provider;
        public IBinder connection;
        public boolean noReleaseNeeded;
            ···
    }
    

    这个类持有了providerinfo,provider Binder的客户端引用,其与服务端的链接conn以及是否需要释放的noReleaseNeeded属性,实际就代表了一条provider链接及信息

    ProviderClientRecord
    final class ProviderClientRecord {
        final String[] mNames;//追踪一下发现存的就是provider们的auth
        final IContentProvider mProvider;//持有的其他进程的provider binder引用
        final ContentProvider mLocalProvider;//本地的provider
        final ContentProviderHolder mHolder;//provider链接
        ···
        }
    

    这个类看名字就猜得出了,用于存储provider客户端的记录

    ProviderRefCount
    private static final class ProviderRefCount {
        public final ContentProviderHolder holder;//一个provider链接
        public final ProviderClientRecord client;//客户端记录
        public int stableCount;//稳定引用数量
        public int unstableCount;//不稳定数量
      
      //当这个值是true,要把stable 和 unstable 引用数归零并且有一个从activitymanager中移除引用数的任务等待运行。我们在activitymanager中依然持有一个unstable引用,但这里的数不会体现
        public boolean removePending;//默认false
        ···
        }
    

    表示对一个provider的引用数量,上面的stable和unstable的区别猜不出是什么,我们先放一放

    下面我们看一下acquireProvider方法

    这里面有三个方法我们重点看一下

    public final IContentProvider acquireProvider(
                Context c, String auth, int userId, boolean stable) {
            final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);//先查找是否有已经存在的
      
            ···
            
            holder = ActivityManager.getService().getContentProvider(
                        getApplicationThread(), auth, userId, stable);
              //调用ams获取provider
            ··· //最后install
            holder = installProvider(c, holder, holder.info,
                    true /*noisy*/, holder.noReleaseNeeded, stable);
            return holder.provider;
        }
    
    我们先看看第一个acquireExistingProvider
    public final IContentProvider acquireExistingProvider(
            Context c, String auth, int userId, boolean stable) {
        synchronized (mProviderMap) {
            final ProviderKey key = new ProviderKey(auth, userId);//根据auth和userid取出来
            final ProviderClientRecord pr = mProviderMap.get(key);//这里看到第一个全局变量mProviderMap,用于存储当前进程持有的Provider
            if (pr == null) {//没有,直接返回
                return null;
            }
            IContentProvider provider = pr.mProvider;//获取存储的provider
            IBinder jBinder = provider.asBinder();//转换成客户端ibinder
            if (!jBinder.isBinderAlive()) {//这个binder已经死了
                handleUnstableProviderDiedLocked(jBinder, true);//处理移除
                return null;
            }
          
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);//这里看到了第二个全局变量,mProviderRefCountMap,以及一个ProviderRefCount类,下面看一下
            if (prc != null) {
                incProviderRefLocked(prc, stable);//什么意思呢
            }
            return provider;
        }
    }
    

    这里我们先分析binder没有死的情况,调用了incProviderRefLocked方法,增加provider的引用数量

    private final void incProviderRefLocked(ProviderRefCount prc, boolean stable) {
            if (stable) {//在当前请求的是稳定引用provider的情况下
                prc.stableCount += 1;//stablecount数量+1
                if (prc.stableCount == 1) {
                    //正在请求一个对此provider的新的稳定引用
                    int unstableDelta;
                    if (prc.removePending) {//这种情况我们之前的属性注释看到过,我们还持有最后一个unstable的引用,我们把他变成stable的
                        unstableDelta = -1;//不稳定引用-1
                        // Cancel the removal of the provider.
                        prc.removePending = false;
                        mH.removeMessages(H.REMOVE_PROVIDER, prc);//取消移除provider的message
                    } else {
                        unstableDelta = 0;//不稳定数不变
                    }
                    try {
                        ActivityManager.getService().refContentProvider(
                                prc.holder.connection, 1, unstableDelta);//通过binder调用AMS的refContentProvider方法更新对provider的引用数,稳定+1,不稳定-1或不变
                    } catch (RemoteException e) {
                    }
                }
            } else {//不稳定的引用请求
                prc.unstableCount += 1;
                if (prc.unstableCount == 1) {
                    // 之前没有不稳定的引用
                    if (prc.removePending) {//这种情况下还是正在移除,实际上依然持有一个不稳定引用
                        prc.removePending = false;
                        mH.removeMessages(H.REMOVE_PROVIDER, prc);//取消通知移除provider的消息
                    } else {
                        try {
                            ActivityManager.getService().refContentProvider(
                                    prc.holder.connection, 0, 1);//通知AMS,不稳定的引用+1
                        } catch (RemoteException e) {
                            //do nothing content provider object is dead any way
                        }
                    }
                }
            }
        }
    

    下面我们再看看当这个找到的binder已经死了的情况

    final void handleUnstableProviderDiedLocked(IBinder provider, boolean fromClient) {
            ProviderRefCount prc = mProviderRefCountMap.get(provider);
            if (prc != null) {
                mProviderRefCountMap.remove(provider);//清除对这个provider的引用数的存储
                for (int i=mProviderMap.size()-1; i>=0; i--) {
                    ProviderClientRecord pr = mProviderMap.valueAt(i);
                    if (pr != null && pr.mProvider.asBinder() == provider) {
                        mProviderMap.removeAt(i);//把这个死了的provider的引用们都从当前缓存中移除
                    }
                }
    
                if (fromClient) {//客户端发现并通知的
                    // We found out about this due to execution in our client
                    // code.  Tell the activity manager about it now, to ensure
                    // that the next time we go to do anything with the provider
                    // it knows it is dead (so we don't race with its death
                    // notification).
                    try {
                        ActivityManager.getService().unstableProviderDied(
                                prc.holder.connection);//通知ams这个链接死了~
                    } catch (RemoteException e) {
                        //do nothing content provider object is dead any way
                    }
                }
            }
        }
    
    然后我们进入AMS中看看获取provider及其他相关一系列方法

    AMS

    @Override
    public final ContentProviderHolder getContentProvider(
                IApplicationThread caller, String name, int userId, boolean stable) {
            ···
            return getContentProviderImpl(caller, name, null, stable, userId);
        }
    

    和之前一样,这里我们也要先看几个类

    ContentProviderConnection

    表示provider和客户端之间的链接

    public final class ContentProviderConnection extends Binder {
        public final ContentProviderRecord provider;//对一个provider的记录,下面会介绍
        public final ProcessRecord client;//客户端进程记录
        public final long createTime;//创建时间
        public int stableCount;//稳定引用数
        public int unstableCount;//不稳定引用数
        // The client of this connection is currently waiting for the provider to appear.
        // Protected by the provider lock.
        public boolean waiting;//是否在等待
        // The provider of this connection is now dead.
        public boolean dead;//是不是死了
    }
    

    可以看到,这个链接还是一个Binder,可以用来和客户端通信

    然后就是对provider的记录类

    ContentProviderRecord

    简单看几个属性

    final class ContentProviderRecord {
        final ActivityManagerService service;
        public final ProviderInfo info;
        final int uid;
        final ApplicationInfo appInfo;
        final ComponentName name;
        final boolean singleton;
        public IContentProvider provider;
        public boolean noReleaseNeeded;
        // All attached clients
        final ArrayList<ContentProviderConnection> connections
                = new ArrayList<ContentProviderConnection>();
                ···
                  
        public boolean canRunHere(ProcessRecord app) {//能够在这个客户端进程直接运行
            return (info.multiprocess || info.processName.equals(app.processName))
                    && uid == app.info.uid;
                  //如果是设置了multiprocess或者本身就是同一进程
        }
              
                }
    

    可以看到他持有相关信息,对服务端provider的引用以及所有和客户端之间的链接

    关于multiprocess,谷歌是这么说的

    如果multiprocess为true,不管在哪个进程中调用provider将会使用该进程中的provider实例,并不会共用,如

    multiprocess为false,那么provider声明在哪个进程,provider就只会在这个进程中存在实例

    其他属性等下看到再说,我们先按照流程详细看一下方法

    getContentProviderImpl
    private 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.uptimeMillis();
    
                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);
                    }
                }
    
                boolean checkCrossUser = true;
    
                checkTime(startTime, "getContentProviderImpl: getProviderByName");
    
                // First check if this content provider has been published...
                cpr = mProviderMap.getProviderByName(name, userId);//根据名字(也就是provider的auth)和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_SYSTEM) {//这里不是很理解,验证单例权限?
                    ···
                }
    
                boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;//需求的provider是不是正在运行?
                if (providerRunning) {//如果正在运行
                    cpi = cpr.info;
                    if (r != null && cpr.canRunHere(r)) {//如果这个provider允许在客户端的进程进行实例化
                        ContentProviderHolder holder = cpr.newHolder(null);
                        holder.provider = null;
                        return holder;//返回一个provider为null的holder,客户端接收到后会在自己的进程去创建provider的实例
                    }
                    try {
                        if (AppGlobals.getPackageManager()
                                .resolveContentProvider(name, 0 /*flags*/, userId) == null) {
                            return null;//看看这个provider是不是一个正常app的provider
                        }
                    } 
                    final long origId = Binder.clearCallingIdentity();
                    conn = incProviderCountLocked(r, cpr, token, stable);//对此provider的引用计数自增,并返回一个包装的conn链接
                    if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {//首次引用
                        if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
                          updateLruProcessLocked(cpr.proc, false, null);//更新服务端进程的lru缓存
                          }
                    }
                    final int verifiedAdj = cpr.proc.verifiedAdj;
                    boolean success = updateOomAdjLocked(cpr.proc, true);//更新adj
                    if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
                        success = false;
                    }
                    maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
                    if (!success) {//失败
                        // Uh oh...  it looks like the provider's process
                        // has been killed on us.  We need to wait for a new
                        // process to be started, and make sure its death
                        // doesn't kill our process.
                        Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
                                + " is crashing; detaching " + r);
                        boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);//引用计数-1,判断是不是最后一个引用
                        appDiedLocked(cpr.proc);//
                        if (!lastRef) {//如果不是最后一个引用,那就死了,不然就假装没有这个,按照没有provider的方法继续
                            // This wasn't the last ref our process had on
                            // the provider...  we have now been killed, bail.
                            return null;
                        }
                        providerRunning = false;
                        conn = null;
                    } else {
                        cpr.proc.verifiedAdj = cpr.proc.setAdj;
                    }
    
                    Binder.restoreCallingIdentity(origId);
                }
    
                if (!providerRunning) {//需要的服务端没有运行
                   cpi = AppGlobals.getPackageManager().
                            resolveContentProvider(name,
                                STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);//查找到需要的provider信息
                     //单利相关,不理解,暂时跳过
                    ···
                    cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
                    ···
    
                    ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
                    cpr = mProviderMap.getProviderByClass(comp, userId);
                  //根据class查找有没有对应的缓存?
                    final boolean firstClass = cpr == null;
                    if (firstClass) {
                        final long ident = Binder.clearCallingIdentity();
    
                        // If permissions need a review before any of the app components can run,
                        // we return no provider and launch a review activity if the calling app
                        // is in the foreground.
                        if (mPermissionReviewRequired) {//判断权限
                            if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
                                return null;
                            }
                        }
    
                        try {
                            checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
                            ApplicationInfo ai =
                                AppGlobals.getPackageManager().
                                    getApplicationInfo(
                                            cpi.applicationInfo.packageName,
                                            STOCK_PM_FLAGS, userId);
                            checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
                            if (ai == null) {
                                Slog.w(TAG, "No package info for content provider "
                                        + cpi.name);
                                return null;
                            }
                            ai = getAppInfoForUser(ai, userId);
                            cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);//获取服务端信息等生成cpr
                        } catch (RemoteException ex) {
                            // pm is in same process, this will never happen.
                        } finally {
                            Binder.restoreCallingIdentity(ident);
                        }
                    }
    
                    checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
    
                    if (r != null && cpr.canRunHere(r)) {//如果客户端可以自己生成,那就叫他自己生成
                        return cpr.newHolder(null);
                    }
    
                    if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
                                + (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
                                + cpr.info.name + " callers=" + Debug.getCallers(6));
    
                    // This is single process, and our app is now connecting to it.
                    // See if we are already in the process of launching this
                    // provider.
                    final int N = mLaunchingProviders.size();
                    int i;
                    for (i = 0; i < N; i++) {
                        if (mLaunchingProviders.get(i) == cpr) {
                            break;//查找需要的是不是正在启动中的provider
                        }
                    }
    
                    if (i >= N) {//如果没找到,那就启动这个provider
                        final long origId = Binder.clearCallingIdentity();
                                            //设置不要让这个服务端的app给关了
                        AppGlobals.getPackageManager().setPackageStoppedState(
                                        cpr.appInfo.packageName, false, userId);
                        ProcessRecord proc = getProcessRecordLocked(
                                    cpi.processName, cpr.appInfo.uid, false);//看看这个服务端的进程在不在
                            if (proc != null && proc.thread != null && !proc.killed) {//如果还在运行
                                if (!proc.pubProviders.containsKey(cpi.name)) {//如果未发布
                                   proc.pubProviders.put(cpi.name, cpr);//放到服务端发布的队列中
                                    try {
                                        proc.thread.scheduleInstallProvider(cpi);//发送消息通知服务端主线程install
                                    } catch (RemoteException e) {
                                    }
                                }
                            } else {//如果服务端进程不存在
                                proc = startProcessLocked(cpi.processName,
                                        cpr.appInfo, false, 0, "content provider",
                                        new ComponentName(cpi.applicationInfo.packageName,
                                                cpi.name), false, false, false);//开启服务端进程
                              ···
                            }
                            cpr.launchingApp = proc;//给provider记录设置正在启动的进程
                            mLaunchingProviders.add(cpr);//把这个provider添加到启动中列表里
                        } finally {
                            Binder.restoreCallingIdentity(origId);
                        }
                    }
    
                    checkTime(startTime, "getContentProviderImpl: updating data structures");
    
                    if (firstClass) {
                        mProviderMap.putProviderByClass(comp, cpr);//如果是第一次启动,把它的class信息等存起来省的下次找了
                    }
    
                    mProviderMap.putProviderByName(name, cpr);//也把这个provider存起来
                    conn = incProviderCountLocked(r, cpr, token, stable);//引用计数自增并生成conn
                    if (conn != null) {
                        conn.waiting = true;//链接等待
                    }
                }
               ···
            }
    
            // Wait for the provider to be published...
            synchronized (cpr) {//这里循环等待直到provider被发布
                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;//返回
        }
    

    到这里为止,我们客户端就从ams获取到了要用的provider的holder,上面的代码中有几个方法我们详细看一下

    首先就是关于引用计数的方法

    incProviderCountLocked
    ContentProviderConnection incProviderCountLocked(ProcessRecord r,//这个代表客户端的进程记录
                final ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
            if (r != null) {
                for (int i=0; i<r.conProviders.size(); i++) {
                    ContentProviderConnection conn = r.conProviders.get(i);//先遍历客户端进程所链接的的privoder
                    if (conn.provider == cpr) {//如果有,那就引用计数+1就好了
                        if (stable) {
                            conn.stableCount++;
                            conn.numStableIncs++;
                        } else {
                            conn.unstableCount++;
                            conn.numUnstableIncs++;
                        }
                        return conn;
                    }
                }
                ContentProviderConnection conn = new ContentProviderConnection(cpr, r);//如果之前客户端并没有对此provider的链接,那就new一个
                if (stable) {//初始化引用计数
                    conn.stableCount = 1;
                    conn.numStableIncs = 1;
                } else {
                    conn.unstableCount = 1;
                    conn.numUnstableIncs = 1;
                }
                cpr.connections.add(conn);//把链接添加给provider记录
                r.conProviders.add(conn);//把链接添加给客户端进程中的链接队列
                startAssociationLocked(r.uid, r.processName, r.curProcState,
                        cpr.uid, cpr.name, cpr.info.processName);
                return conn;//返回链接
            }
            cpr.addExternalProcessHandleLocked(externalProcessToken);
            return null;
        }
    
    decProviderCountLocked
    boolean decProviderCountLocked(ContentProviderConnection conn,
            ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
        if (conn != null) {
            cpr = conn.provider;
            if (DEBUG_PROVIDER) Slog.v(TAG_PROVIDER,
                    "Removing provider requested by "
                    + conn.client.processName + " from process "
                    + cpr.info.processName + ": " + cpr.name.flattenToShortString()
                    + " scnt=" + conn.stableCount + " uscnt=" + conn.unstableCount);
            if (stable) {
                conn.stableCount--;
            } else {
                conn.unstableCount--;
            }//引用计数--
            if (conn.stableCount == 0 && conn.unstableCount == 0) {//如果没有了
                cpr.connections.remove(conn);//移除
                conn.client.conProviders.remove(conn);//移除
                if (conn.client.setProcState < ActivityManager.PROCESS_STATE_LAST_ACTIVITY) {
                    // The client is more important than last activity -- note the time this
                    // is happening, so we keep the old provider process around a bit as last
                    // activity to avoid thrashing it.
                    if (cpr.proc != null) {
                        cpr.proc.lastProviderTime = SystemClock.uptimeMillis();
                    }
                }
                stopAssociationLocked(conn.client.uid, conn.client.processName, cpr.uid, cpr.name);
                return true;
            }
            return false;
        }
        cpr.removeExternalProcessHandleLocked(externalProcessToken);
        return false;
    }
    
    refContentProvider
    //这个方法是在ActivityThread中调用的,就是修改ams端conn的引用计数
    public boolean refContentProvider(IBinder connection, int stable, int unstable) {
        ContentProviderConnection conn;
        try {
            conn = (ContentProviderConnection)connection;
        } catch (ClassCastException e) {
            String msg ="refContentProvider: " + connection
                    + " not a ContentProviderConnection";
            Slog.w(TAG, msg);
            throw new IllegalArgumentException(msg);
        }
        if (conn == null) {
            throw new NullPointerException("connection is null");
        }
    
        synchronized (this) {
            if (stable > 0) {
                conn.numStableIncs += stable;
            }
            stable = conn.stableCount + stable;
            if (stable < 0) {
                throw new IllegalStateException("stableCount < 0: " + stable);
            }
    
            if (unstable > 0) {
                conn.numUnstableIncs += unstable;
            }
            unstable = conn.unstableCount + unstable;
            if (unstable < 0) {
                throw new IllegalStateException("unstableCount < 0: " + unstable);
            }
    
            if ((stable+unstable) <= 0) {
                throw new IllegalStateException("ref counts can't go to zero here: stable="
                        + stable + " unstable=" + unstable);
            }
            conn.stableCount = stable;
            conn.unstableCount = unstable;
            return !conn.dead;
        }
    }
    

    第二个就是InstallProvider方法,这个方法实际上在ActivityThread中,我们上面看到有多个地方调用了

    比如

    1 服务端进程启动了,但是没有发布需要的provider,ams让服务端发送消息给服务端主线程安装这个provider

    2 服务端进程没启动,那么ams会先启动服务端进程,而在服务端的ActivityThread的main方法中会对其所有的

    provider调用此方法

    3 我们在客户端的ActivityThread中看到,获取provider时当ams返回了provider的handler后会调用此方法。下面我们就看

    看这个方法是怎么运行的,都干了啥

    回到ActivityThread

    首先我们看看上面说的前两种情况

    前两种最后都会调用

    installContentProviders
    private void installContentProviders(
            Context context, List<ProviderInfo> providers) {
        final ArrayList<ContentProviderHolder> results = new ArrayList<>();
    
        for (ProviderInfo cpi : providers) {
            if (DEBUG_PROVIDER) {
                StringBuilder buf = new StringBuilder(128);
                buf.append("Pub ");
                buf.append(cpi.authority);
                buf.append(": ");
                buf.append(cpi.name);
                Log.i(TAG, buf.toString());
            }
            ContentProviderHolder cph = installProvider(context, null, cpi,
                    false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);//循环对其调用installProvider
            if (cph != null) {
                cph.noReleaseNeeded = true;//刚安装好,设置现在不允许被释放
                results.add(cph);
            }
        }
    
        try {
            ActivityManager.getService().publishContentProviders(
                getApplicationThread(), results);//通知ams发布providers
        } catch (RemoteException ex) {
            throw ex.rethrowFromSystemServer();
        }
    }
    

    下面我们就看看installProvider干了啥

    installProvider
    private ContentProviderHolder installProvider(Context context,
            ContentProviderHolder holder, ProviderInfo info,
            boolean noisy, boolean noReleaseNeeded, boolean stable) {
        ContentProvider localProvider = null;
        IContentProvider provider;
        if (holder == null || holder.provider == null) {//这种情况表示需要需要本进程生成provider的实例,比如服务端发布provider或者provider允许客户端的进程自己生成实例
           Context c = null;
            ApplicationInfo ai = info.applicationInfo;
          //先获取provider需要的context
            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 {
                final java.lang.ClassLoader cl = c.getClassLoader();
                localProvider = (ContentProvider)cl.
                    loadClass(info.name).newInstance();//反射获取provider的实例
                provider = localProvider.getIContentProvider();//获取provider用于通信的binder
                ···
                localProvider.attachInfo(c, info);//给本地provider记录添加相关信息
            } catch (java.lang.Exception e) {
                ···
            }
        } else {//这种情况就是在客户端获取服务端的provider啦,我们已经有了provider给客户端的引用~
            provider = holder.provider;
        }
    
        ContentProviderHolder retHolder;
    
        synchronized (mProviderMap) {
            IBinder jBinder = provider.asBinder();//转换成binder
            if (localProvider != null) {//如果provider在本地
                ComponentName cname = new ComponentName(info.packageName, info.name);
                ProviderClientRecord pr = mLocalProvidersByName.get(cname);
                if (pr != null) {
                    provider = pr.mProvider;//如果本地之前有了,那就用之前的
                } else {
                    holder = new ContentProviderHolder(info);//否则新建一个holder,存起来
                    holder.provider = provider;
                    holder.noReleaseNeeded = true;
                    pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
                    mLocalProviders.put(jBinder, pr);
                    mLocalProvidersByName.put(cname, pr);
                }
                retHolder = pr.mHolder;
            } else {//远程provider
                ProviderRefCount prc = mProviderRefCountMap.get(jBinder);//查找计数
                if (prc != null) {
                    if (!noReleaseNeeded) {//存在此计数并且需要移除
                        incProviderRefLocked(prc, stable);//计数自增
                        try {
                            ActivityManager.getService().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;//返回这个holder
    }
    

    上面这段代码有几个方法我们需要搞清楚 首先就是

    installProviderAuthoritiesLocked
    private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
            ContentProvider localProvider, ContentProviderHolder holder) {
        final String auths[] = holder.info.authority.split(";");
        final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
    
        if (provider != null) {
            // If this provider is hosted by the core OS and cannot be upgraded,
            // then I guess we're okay doing blocking calls to it.
            for (String auth : auths) {
                switch (auth) {
                    case ContactsContract.AUTHORITY:
                    case CallLog.AUTHORITY:
                    case CallLog.SHADOW_AUTHORITY:
                    case BlockedNumberContract.AUTHORITY:
                    case CalendarContract.AUTHORITY:
                    case Downloads.Impl.AUTHORITY:
                    case "telephony":
                        Binder.allowBlocking(provider.asBinder());
                }
            }
        }
    
        final ProviderClientRecord pcr = new ProviderClientRecord(
                auths, provider, localProvider, holder);
        for (String auth : auths) {
            final ProviderKey key = new ProviderKey(auth, userId);
            final ProviderClientRecord existing = mProviderMap.get(key);
            if (existing != null) {
                Slog.w(TAG, "Content provider " + pcr.mHolder.info.name
                        + " already published as " + auth);
            } else {
                mProviderMap.put(key, pcr);//依次存到本地缓存中
            }
        }
        return pcr;
    }
    

    回到AMS

    removeContentProvider
        public void removeContentProvider(IBinder connection, boolean stable) {
            long ident = Binder.clearCallingIdentity();
            try {
                synchronized (this) {
                    ContentProviderConnection conn;
                    try {
                        conn = (ContentProviderConnection)connection;
                    } catch (ClassCastException e) {
                    }
                    if (conn == null) {
                        throw new NullPointerException("connection is null");
                    }
                    if (decProviderCountLocked(conn, null, null, stable)) {//-1 如果没了,就移除这个链接
                        updateOomAdjLocked();
                    }
                }
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    

    最后就是在AMS中发布了

    publishContentProviders
    public final void publishContentProviders(IApplicationThread caller,
            List<ContentProviderHolder> providers) {
        synchronized (this) {
            final ProcessRecord r = getRecordForAppLocked(caller);
           
            final long origId = Binder.clearCallingIdentity();
    
            final int N = providers.size();
            for (int i = 0; i < N; i++) {
                ContentProviderHolder src = providers.get(i);//遍历需要发布的providers
                ContentProviderRecord dst = r.pubProviders.get(src.info.name);//查找是否需要发布
                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++) {//从正在发布状态的list中移除
                        if (mLaunchingProviders.get(j) == dst) {
                            mLaunchingProviders.remove(j);
                            wasInLaunchingProviders = true;
                            j--;
                            launchingCount--;
                        }
                    }
                    if (wasInLaunchingProviders) {
                        mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);//移除超时消息
                    }
                    synchronized (dst) {//更新发布的provider记录
                        dst.provider = src.provider;//设置provider引用
                        dst.proc = r;//设置服务端进程
                        dst.notifyAll();//解除wait(之前我们看到过在客户端请求AMSprovider时,最后通过此记录wait了,现在provider已经发布了,自然要解锁)
                    }
                    updateOomAdjLocked(r, true);//更新adj
                    maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                            src.info.authority);
                }
            }
    
            Binder.restoreCallingIdentity(origId);
        }
    }
    

    到这里,我们就正式使用客户端通过AMS请求到了服务端的provider了

    下一步我们看一下增删改查等操作是怎么传递给服务端的,还是上面最早的栗子

    客户端

    在ContentResolver的delete中调用了

    provider.delete(mPackageName, url, where, selectionArgs);//调用delete方法
    

    我们知道当远程调用的时候,这里的provider实际上是一个远程代理

    ContentProviderProxy

    我们i简单看看delete方法

    @Override
    public int delete(String callingPkg, Uri url, String selection, String[] selectionArgs)
            throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        try {
            data.writeInterfaceToken(IContentProvider.descriptor);
    
            data.writeString(callingPkg);
            url.writeToParcel(data, 0);
            data.writeString(selection);
            data.writeStringArray(selectionArgs);
    
            mRemote.transact(IContentProvider.DELETE_TRANSACTION, data, reply, 0);
    
            DatabaseUtils.readExceptionFromParcel(reply);
            int count = reply.readInt();
            return count;
        } finally {
            data.recycle();
            reply.recycle();
        }
    }
    

    和一般的binder通信没什么两样

    再看看服务端 我们可以看到在ContentProvider中是持有一个binder对象Transport的,transport继承自ContentProviderNative

    服务端

    ContentProviderNative

    onTransact:

    case DELETE_TRANSACTION:
    {
        data.enforceInterface(IContentProvider.descriptor);
        String callingPkg = data.readString();
        Uri url = Uri.CREATOR.createFromParcel(data);
        String selection = data.readString();
        String[] selectionArgs = data.readStringArray();
    
        int count = delete(callingPkg, url, selection, selectionArgs);//delete
    
        reply.writeNoException();
        reply.writeInt(count);
        return true;
    }
    
    Transport
    @Override
    public int delete(String callingPkg, Uri uri, String selection, String[] selectionArgs) {
        validateIncomingUri(uri);//验证合法
        uri = maybeGetUriWithoutUserId(uri);
        if (enforceWritePermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
            return 0;
        }
        final String original = setCallingPackage(callingPkg);
        try {
            return ContentProvider.this.delete(uri, selection, selectionArgs);//这里,就调用了我们自己写的ContentProvider的delete方法了~~
        } finally {
            setCallingPackage(original);
        }
    }
    

    最后,在客户端中还对此provider进行了释放

    释放

    releaseProvider(provider);//释放 此方法最后也会掉用ActivityThread中的releaseProvider方法
    
    releaseProvider
    public final boolean releaseProvider(IContentProvider provider, boolean stable) {
        if (provider == null) {
            return false;
        }
    
        IBinder jBinder = provider.asBinder();//转换成ibinder
        synchronized (mProviderMap) {
            ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
            if (prc == null) {
                // The provider has no ref count, no release is needed.
                return false;
            }
    
            boolean lastRef = false;
            if (stable) {
                if (prc.stableCount == 0) {
                    if (DEBUG_PROVIDER) Slog.v(TAG,
                            "releaseProvider: stable ref count already 0, how?");
                    return false;
                }
                prc.stableCount -= 1;
                if (prc.stableCount == 0) {
                    // What we do at this point depends on whether there are
                    // any unstable refs left: if there are, we just tell the
                    // activity manager to decrement its stable count; if there
                    // aren't, we need to enqueue this provider to be removed,
                    // and convert to holding a single unstable ref while
                    // doing so.
                    lastRef = prc.unstableCount == 0;
                    try {
                        if (DEBUG_PROVIDER) {
                            Slog.v(TAG, "releaseProvider: No longer stable w/lastRef="
                                    + lastRef + " - " + prc.holder.info.name);
                        }
                        ActivityManager.getService().refContentProvider(
                                prc.holder.connection, -1, lastRef ? 1 : 0);
                    } catch (RemoteException e) {
                        //do nothing content provider object is dead any way
                    }
                }
            } else {
                if (prc.unstableCount == 0) {
                    if (DEBUG_PROVIDER) Slog.v(TAG,
                            "releaseProvider: unstable ref count already 0, how?");
                    return false;
                }
                prc.unstableCount -= 1;
                if (prc.unstableCount == 0) {
                    // If this is the last reference, we need to enqueue
                    // this provider to be removed instead of telling the
                    // activity manager to remove it at this point.
                    lastRef = prc.stableCount == 0;
                    if (!lastRef) {
                        try {
                            if (DEBUG_PROVIDER) {
                                Slog.v(TAG, "releaseProvider: No longer unstable - "
                                        + prc.holder.info.name);
                            }
                            ActivityManager.getService().refContentProvider(
                                    prc.holder.connection, 0, -1);
                        } catch (RemoteException e) {
                            //do nothing content provider object is dead any way
                        }
                    }
                }
            }
    
         //对本地的引用及远程AMS的引用计数统统-1
            if (lastRef) {//如果是最后一个引用了
                if (!prc.removePending) {
                    // Schedule the actual remove asynchronously, since we don't know the context
                    // this will be called in.
                    // TODO: it would be nice to post a delayed message, so
                    // if we come back and need the same provider quickly
                    // we will still have it available.
                    if (DEBUG_PROVIDER) {
                        Slog.v(TAG, "releaseProvider: Enqueueing pending removal - "
                                + prc.holder.info.name);
                    }
                    prc.removePending = true;//意图移除
                    Message msg = mH.obtainMessage(H.REMOVE_PROVIDER, prc);//发送移除的msg
                    mH.sendMessage(msg);
                } else {
                    Slog.w(TAG, "Duplicate remove pending of provider " + prc.holder.info.name);
                }
            }
            return true;
        }
    }
    

    客户端主线程收到这个消息后

    completeRemoveProvider
    final void completeRemoveProvider(ProviderRefCount prc) {
        synchronized (mProviderMap) {
            if (!prc.removePending) {//如果有别的地方又请求了,我们之前看到过,会把这个变成false,并移除消息,也就是说先不删啦
                return;
            }
    
            // More complicated race!! Some client managed to acquire the
            // provider and release it before the removal was completed.
            // Continue the removal, and abort the next remove message.
            prc.removePending = false;//到此为止,要真的删除了
    
            final IBinder jBinder = prc.holder.provider.asBinder();
            ProviderRefCount existingPrc = mProviderRefCountMap.get(jBinder);
            if (existingPrc == prc) {
                mProviderRefCountMap.remove(jBinder);//本地移除引用计数
            }
    
            for (int i=mProviderMap.size()-1; i>=0; i--) {
                ProviderClientRecord pr = mProviderMap.valueAt(i);
                IBinder myBinder = pr.mProvider.asBinder();
                if (myBinder == jBinder) {
                    mProviderMap.removeAt(i);//移除缓存
                }
            }
        }
    
        try {
            if (DEBUG_PROVIDER) {
                Slog.v(TAG, "removeProvider: Invoking ActivityManagerService."
                        + "removeContentProvider(" + prc.holder.info.name + ")");
            }
            ActivityManager.getService().removeContentProvider(
                    prc.holder.connection, false);//通知AMS释放
        } catch (RemoteException e) {
            //do nothing content provider object is dead any way
        }
    }
    
    AMS:removeContentProvider

    此方法之前已经看过了,就不再说啦~

    最后,我们看看当服务端进程被杀死的时候发生了啥?

    Die

    在我们进程创建的时候,可以看到在ActivityThread中的main方法中

    thread.attach(false);
    => mgr.attachApplication(mAppThread);//mgr就是AMS
    => AMS::attachApplicationLocked
    => AMS::attachApplicationLocked(thread, callingPid)
    
    AMS::attachApplicationLocked
    try {
        AppDeathRecipient adr = new AppDeathRecipient(
                app, pid, thread);//可以看到添加了一个死亡代理
        thread.asBinder().linkToDeath(adr, 0);
        app.deathRecipient = adr;
    } catch (RemoteException e) {
        app.resetPackageList(mProcessStats);
        startProcessLocked(app, "link fail", processName);
        return false;
    }
    //下面是这个死亡代理的实现
    private final class AppDeathRecipient implements IBinder.DeathRecipient {
            final ProcessRecord mApp;
            final int mPid;
            final IApplicationThread mAppThread;
    
            AppDeathRecipient(ProcessRecord app, int pid,
                    IApplicationThread thread) {
                if (DEBUG_ALL) Slog.v(
                    TAG, "New death recipient " + this
                    + " for thread " + thread.asBinder());
                mApp = app;
                mPid = pid;
                mAppThread = thread;
            }
    
            @Override
            public void binderDied() {
                if (DEBUG_ALL) Slog.v(
                    TAG, "Death received in " + this
                    + " for thread " + mAppThread.asBinder());
                synchronized(ActivityManagerService.this) {
                    appDiedLocked(mApp, mPid, mAppThread, true);//当进程死亡时会调用appDiedLocked
                }
            }
        }
    

    我们对appDiedLocked一路跟踪下去

    appDiedLocked
    => handleAppDiedLocked
    => cleanUpApplicationRecordLocked
    
    cleanUpApplicationRecordLocked
    ​```
    // Remove published content providers.
            for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
                ContentProviderRecord cpr = app.pubProviders.valueAt(i);
                final boolean always = app.bad || !allowRestart;
                boolean inLaunching = removeDyingProviderLocked(app, cpr, always);//这个方法等下要看一下
                if ((inLaunching || always) && cpr.hasConnectionOrHandle()) {
                    // We left the provider in the launching list, need to
                    // restart it.
                    restart = true;
                }
    
                cpr.provider = null;
                cpr.proc = null;
            }
            app.pubProviders.clear();//移除发布的provider
    
            // Take care of any launching providers waiting for this process.
            if (cleanupAppInLaunchingProvidersLocked(app, false)) { //处理正在启动并且是有client端正在等待的ContentProvider
                restart = true;
            }
    
            // Unregister from connected content providers.
            if (!app.conProviders.isEmpty()) {//移除
                for (int i = app.conProviders.size() - 1; i >= 0; i--) {
                    ContentProviderConnection conn = app.conProviders.get(i);
                    conn.provider.connections.remove(conn);
                    stopAssociationLocked(app.uid, app.processName, conn.provider.uid,
                            conn.provider.name);
                }
                app.conProviders.clear();
            }
    
            if (false) {
                for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
                    ContentProviderRecord cpr = mLaunchingProviders.get(i);
                    if (cpr.connections.size() <= 0 && !cpr.hasExternalProcessHandles()) {
                        synchronized (cpr) {
                            cpr.launchingApp = null;
                            cpr.notifyAll();
                        }
                    }
                }
            }
    ​```
    
    removeDyingProviderLocked
    private final boolean removeDyingProviderLocked(ProcessRecord proc,
            ContentProviderRecord cpr, boolean always) {
        final boolean inLaunching = mLaunchingProviders.contains(cpr);//这个provider是不是正在启动中
    
        if (!inLaunching || always) {
            synchronized (cpr) {
                cpr.launchingApp = null;
                cpr.notifyAll(); 
            }
            mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid));//移除缓存
            String names[] = cpr.info.authority.split(";");
            for (int j = 0; j < names.length; j++) {
                mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid));//移除缓存
            }
        }
    
        for (int i = cpr.connections.size() - 1; i >= 0; i--) {//遍历
            ContentProviderConnection conn = cpr.connections.get(i);
            if (conn.waiting) {//还在等待
                // If this connection is waiting for the provider, then we don't
                // need to mess with its process unless we are always removing
                // or for some reason the provider is not currently launching.
                if (inLaunching && !always) {
                    continue;
                }
            }
            ProcessRecord capp = conn.client;//拿到客户端
            conn.dead = true;//设置此链接死了
            if (conn.stableCount > 0) {//稳定链接
                if (!capp.persistent && capp.thread != null
                        && capp.pid != 0
                        && capp.pid != MY_PID) {
                    capp.kill("depends on provider "
                            + cpr.name.flattenToShortString()
                            + " in dying proc " + (proc != null ? proc.processName : "??")
                            + " (adj " + (proc != null ? proc.setAdj : "??") + ")", true);//直接杀死
                }
            } else if (capp.thread != null && conn.provider.provider != null) {
                try {
                    capp.thread.unstableProviderDied(conn.provider.provider.asBinder());//通知客户端这个死了
                } catch (RemoteException e) {
                }
                // In the protocol here, we don't expect the client to correctly
                // clean up this connection, we'll just remove it.
                cpr.connections.remove(i);//移除
                if (conn.client.conProviders.remove(conn)) {
                    stopAssociationLocked(capp.uid, capp.processName, cpr.uid, cpr.name);
                }
            }
        }
    
        if (inLaunching && always) {
            mLaunchingProviders.remove(cpr);//移除
        }
        return inLaunching;
    }
    
    handleUnstableProviderDiedLocked

    无论是上面中进程被杀死或者是客户端发现某个provider进程死了,都会调用此方法 这个方法我们最开始就看过了

    当是客户端发现时,会调用

    AMS::unstableProviderDied

    public void unstableProviderDied(IBinder connection) {
        ```
            try {
                appDiedLocked(proc);//最后还是调用了这个方法
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }
    

    最后,这个stable或者unstable怎么控制呢?我们查看ContentResolver的几个方法发现

    insert update delete都会直接请求stable的provider链接,query则会先请求unstable的,如果在运行中发现死了,就会发送通知告诉AMS,然后再请求stable的~ 开发者是不能控制的

    到这里就结束了~本文只是自己整理provider流程记录的,赶时间写的比较混乱TT,有错误的辛苦大佬帮忙指正嘻嘻嘻

    想要详细了解推荐看Gityuan大佬的博客,我觉得很详细 http://gityuan.com/2016/07/30/content-provider/

    END~~

    相关文章

      网友评论

        本文标题:ContentProvider流程解析

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