android菜鸟笔记

ContentProvider流程解析

2019-08-08  本文已影响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~~

上一篇下一篇

猜你喜欢

热点阅读