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/
网友评论