简介
基于Android 9.0的源码剖析, 分析Android ContentProvider原理。
一、概述
ContentProvider作为四大组件之一,在开发过程中经常被使用到。我们的常规做法是定义一个ContentProvider,然后在使用的时候使用ContentResolver提供的接口来访问数据。一个进程可以访问自己定义的ContentProvider,也可以访问其他进程定义的ContentProvider。
1.1 继承关系图
1.2 类简介
1.2.1 ContentProvider
ContentProvider作为Android四大组件之一,并没有Activity那样复杂的生命周期,只有简单地onCreate过程。ContentProvider是一个抽象类,当实现自己的ContentProvider类,只需继承于ContentProvider,并且实现以下六个abstract方法即可:
insert(Uri, ContentValues):插入新数据; delete(Uri, String, String[]):删除已有数据; update(Uri, ContentValues, String, String[]):更新数据; query(Uri, String[], String, String[], String):查询数据; onCreate():执行初始化工作; getType(Uri):获取数据MIME类型。
1.2.2?ContentResolver
其他app或者进程想要操作ContentProvider,则需要先获取其相应的ContentResolver,再利用ContentResolver类来完成对数据的增删改查操作。
ContextImpl.java
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
1.2.3?ContentProviderHolder
ContentProviderHolder主要是承载ContentProvider的信息和ContentProvider接口内容,并在SystemServer和App进程间传递。
public class ContentProviderHolder implements Parcelable {
...
//描述该ContentProvider的信息
public final ProviderInfo info;
//描述该ContentProvider对应的ContentProvider接口,它是一个Binder代理对象
public IContentProvider provider;
public IBinder connection;
public boolean noReleaseNeeded;
}
1.2.4?ContentProviderRecord
一个表示应用层定义的ContentProvider的数据结构,在Framework中可以理解为一个ContentProviderRecord对应应用层中的一个ContentProvider。
final class ContentProviderRecord implements ComponentName.WithComponentName {
final ActivityManagerService service;
//描述该ContentProvider的具体信息
public final ProviderInfo info;
final int uid;
//描述定义该ContentProvider的应用的信息
final ApplicationInfo appInfo;
//描述标识该ContentProvider的ComponentName
final ComponentName name;
//表示该ContentProvider是否是跨用户单例的
//所谓跨用户单例即系统中只会保存一个这样的ContentProviderRecord结构,多个用户使用的是同一个ContentProviderRecord
//当第三方应用的ContentProvider想要定义为跨用户单例时,需要添加INTERACT_ACROSS_USERS权限
final boolean singleton;
public IContentProvider provider;
public boolean noReleaseNeeded;
// All attached clients
//保存访问该ContentProvider的客户端的连接,用于在比如当前ContentProvider所在进程挂掉等时刻通知客户端进程
//因为一个ContentProvider定义后可以被系统中不同的进程访问,所以此处使用一个容器来存储
final ArrayList<ContentProviderConnection> connections
= new ArrayList<ContentProviderConnection>();
//final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
// Handles for non-framework processes supported by this provider
HashMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
// Count for external process for which we have no handles.
int externalProcessNoHandleCount;
ProcessRecord proc; // if non-null, hosting process.
ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
String stringName;
String shortStringName;
...
}
1.2.5?ProviderInfo?
真正描述应用层定义的ContentProvider的属性信息,该结构中基本就是保存定义ContentProvider时声明的各个属性,PMS去扫描AndroidManifest文件时得到的也是该结构。
/**
* Holds information about a specific
* {@link android.content.ContentProvider content provider}. This is returned by
* {@link android.content.pm.PackageManager#resolveContentProvider(java.lang.String, int)
* PackageManager.resolveContentProvider()}.
*/
public final class ProviderInfo extends ComponentInfo implements Parcelable {
/** The name provider is published under content:// */
//定义ContentProvider时指定的authority
public String authority = null;
/** Optional permission required for read-only access this content
* provider. */
//定义ContentProvider时指定的readPermission
public String readPermission = null;
/** Optional permission required for read/write access this content
* provider. */
//定义ContentProvider时指定的writePermission
public String writePermission = null;
/** If true, additional permissions to specific Uris in this content
* provider can be granted, as per the
* {@link android.R.styleable#AndroidManifestProvider_grantUriPermissions
* grantUriPermissions} attribute.
*/
//定义ContentProvider时指定的grantUriPermissions
public boolean grantUriPermissions = false;
...
}
1.2.6??ContentProviderConnection?
表示一个访问ContentProvider的客户端连接。该结构主要是用于描述一个访问ContentProvider的客户端连接,并保存了客户端在访问ContentProvider时的一些属性。系统中运行的一个ContentProvider是可能被多个客户端访问的,系统就用该结构来记录一个客户端到它访问的ContentProvider之间的连接。
/**
* Represents a link between a content provider and client.
*/
public final class ContentProviderConnection extends Binder {
//描述其访问的是哪个ContentProvider
public final ContentProviderRecord 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;
// For debugging.
public int numStableIncs;
public int numUnstableIncs;
...
}
stableCount、unstableCount 这两个连接数来帮助系统判断当前的ContentProvider还有没有客户端在访问。站在系统的角度看稳定连接与非稳定连接的区别主要是:在ContentProvider发生一些事件时,采用两种不同的连接访问该ContentProvider的客户端会被不同的策略处理。比如当ContentProvider所在的进程挂掉时,系统会遍历该ContentProviderRecord的connections,处理正在访问该ContentProvider的客户端,如果此时客户端采用稳定连接访问,那么系统会连同该客户端一起kill。如果此时客户端采用非稳定连接访问,则系统只是通知客户端访问的ContentProvider已经死亡。那么具体什么时候是稳定连接,什么时候是非稳定连接。这取决于访问数据的方式,一般来说,查询数据会使用非稳定的连接,而增删改则使用的是稳定的连接。
1.2.7?ProviderMap
ProviderMap是服务于AMS的一个类,主要负责管理ContentProviderRecord。
/**
* Keeps track of content providers by authority (name) and class. It separates the mapping by
* user and ones that are not user-specific (system providers).
*/
public final class ProviderMap {
private static final String TAG = "ProviderMap";
private static final boolean DBG = false;
private final ActivityManagerService mAm;
private final HashMap<String, ContentProviderRecord> mSingletonByName
= new HashMap<String, ContentProviderRecord>();
private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
= new HashMap<ComponentName, ContentProviderRecord>();
private final SparseArray<HashMap<String, ContentProviderRecord>> mProvidersByNamePerUser
= new SparseArray<HashMap<String, ContentProviderRecord>>();
private final SparseArray<HashMap<ComponentName, ContentProviderRecord>> mProvidersByClassPerUser
= new SparseArray<HashMap<ComponentName, ContentProviderRecord>>();
...
}
1.3 大致流程
假设App B定义了一个ContentProvider,App A需要访问该ContentProvider。整个调用过程简单梳理会经过以下几个步骤: (1) App A先向SystemServer查询要访问的ContentProvider接口 (2) SystemServer将查询到的ContentProvider接口返回给App ,该ContentProvider接口是定义在App B中的ContentProvider的Binder代理 (3) App A再通过该Binder代理调用定义在App B中的ContentProvider的逻辑
1.4?本地缓存
ActivityThread内部会缓存当前进程已经访问过的ContentProvider或者是当前进程内自己定义的ContentProvider。缓存在其成员变量mProviderMap中。这里注意,在AMS中也有个同名的成员变量mProviderMap,可以大致理解为他们都用来缓存ContentProvider接口,只不过一个是在本地进程中缓存,一个是在SystemServer中全局缓存。
1.5 整体流程图
二、源码分析
?2.1 getContentResolver
Context中调用getContentResolver,经过层层调用来到ContextImpl类。返回值mContentResolver赋值是在ContextImpl对象创建过程完成赋值。
class ContextImpl extends Context {
public ContentResolver getContentResolver() {
return mContentResolver;
}
private ContextImpl(...) {
...
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
}
2.2 ContentResolver.query
public abstract class ContentResolver {
...
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
IContentProvider unstableProvider = acquireUnstableProvider(uri);
...
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
...
try {
qCursor = unstableProvider.query(mPackageName, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died... but we only hold an unstable
// reference though, so we might recover!!! Let's try!!!!
// This is exciting!!1!!1!!!!1
// 远程进程死亡,处理unstable provider死亡过程
unstableProviderDied(unstableProvider);
//unstable类型死亡后,再创建stable类型的provider
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
qCursor = stableProvider.query(
mPackageName, uri, projection, queryArgs, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
// Force query execution. Might fail and throw a runtime exception here.
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
// Wrap the cursor object into CursorWrapperInner object.
//创建对象CursorWrapperInner
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
} finally {
if (qCursor != null) {
qCursor.close();
}
if (cancellationSignal != null) {
cancellationSignal.setRemote(null);
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}
...
}
一般地获取unstable的provider:
(1) 调用acquireUnstableProvider(),尝试获取unstable的ContentProvider (2) 然后执行query操作 (3) 当执行query过程抛出DeadObjectException,即代表ContentProvider所在进程死亡,则尝试获取stable的ContentProvider
(4) 先调用unstableProviderDied(), 清理刚创建的unstable的ContentProvider (5) 调用acquireProvider(),尝试获取stable的ContentProvider; 此时当ContentProvider进程死亡,则会杀掉该ContentProvider的客户端进程 (6) 然后执行query操作
stable与unstable的区别:采用unstable类型的ContentProvider的app不会因为远程ContentProvider进程的死亡而被杀,stable则恰恰相反。这便是ContentProvider坑爹之处,对于app无法事先决定创建的ContentProvider是stable,还是unstable 类型的,也便无法得知自己的进程是否会依赖于远程ContentProvider的生死。
2.3?ContentResolver.acquireUnstableProvider
public abstract class ContentResolver {
...
/**
* Returns the content provider for the given content URI.
*
* @param uri The URI to a content provider
* @return The ContentProvider for the given URI, or null if no content provider is found.
* @hide
*/
public final IContentProvider acquireUnstableProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
String auth = uri.getAuthority();
if (auth != null) {
return acquireUnstableProvider(mContext, uri.getAuthority());
}
return null;
}
...
}
class ContextImpl extends Context {
...
private static final class ApplicationContentResolver extends ContentResolver {
private final ActivityThread mMainThread;
public ApplicationContentResolver(Context context, ActivityThread mainThread) {
super(context);
mMainThread = Preconditions.checkNotNull(mainThread);
}
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
@Override
protected IContentProvider acquireExistingProvider(Context context, String auth) {
return mMainThread.acquireExistingProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
@Override
public boolean releaseProvider(IContentProvider provider) {
return mMainThread.releaseProvider(provider, true);
}
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
@Override
public boolean releaseUnstableProvider(IContentProvider icp) {
return mMainThread.releaseProvider(icp, false);
}
@Override
public void unstableProviderDied(IContentProvider icp) {
mMainThread.handleUnstableProviderDied(icp.asBinder(), true);
}
@Override
public void appNotRespondingViaProvider(IContentProvider icp) {
mMainThread.appNotRespondingViaProvider(icp.asBinder());
}
/** @hide */
protected int resolveUserIdFromAuthority(String auth) {
return ContentProvider.getUserIdFromAuthority(auth, getUserId());
}
}
...
}
public final class ActivityThread extends ClientTransactionHandler {
...
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
//成功获取已经存在的ContentProvider对象,则直接返回
return provider;
}
// There is a possible race here. Another thread may try to acquire
// the same provider at the same time. When this happens, we want to ensure
// that the first one wins.
// Note that we cannot hold the lock while acquiring and installing the
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
ContentProviderHolder holder = null;
try {
synchronized (getGetProviderLock(auth, userId)) {
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), auth, userId, stable);
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
//无法获取auth所对应的provider则直接返回
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
// Install provider will increment the reference count for us, and break
// any ties in the race.
//安装provider将会增加引用计数
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
...
}
不论是acquireUnstableProvider还是acquireProvider方法,最终都会调用ActivityThread的同一个方法acquireProvider()。该方法的主要功能:
(1) 首先,尝试获取已存储的provider,当成功获取则直接返回,否则继续执行 (2) 通过AMS来获取provider,当无法获取auth所对应的provider则直接返回,否则继续执行 (3) 采用installProvider安装provider,并该provider的增加引用计数
2.4?ActivityThread.acquireExistingProvider
public final class ActivityThread extends ClientTransactionHandler {
...
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
//从AT.mProviderMap查询是否存在相对应的provider
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
if (!jBinder.isBinderAlive()) {
// The hosting process of the provider has died; we can't
// use this one.
Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+ ": existing object's process dead");
//当provider所在进程已经死亡则返回
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
// Only increment the ref count if we have one. If we don't then the
// provider is not reference counted and never needs to be released.
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
//增加引用计数
incProviderRefLocked(prc, stable);
}
return provider;
}
}
...
}
(1) 首先从ActivityThread的mProviderMap查询是否存在相对应的provider,若不存在则直接返回 (2) 当provider记录存在,但其所在进程已经死亡,则调用handleUnstableProviderDiedLocked清理provider信息,并返回 (3) 当provider记录存在,且进程存活的情况下,则在provider引用计数不为空时则继续增加引用计数
2.5?AMS.getContentProvider
public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
// The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
// with cross-user grant.
//此处name就是前面的auth,对应于AndroidManifest.xml中provider标签里面的android:authorities的值
return getContentProviderImpl(caller, name, null, stable, userId);
}
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) {
//获取调用者的进程记录ProcessRecord
r = getRecordForAppLocked(caller);
...
}
...
// First check if this content provider has been published...
//从AMS中查询相应的ContentProviderRecord
cpr = mProviderMap.getProviderByName(name, 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) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
if (cpr != null) {
cpi = cpr.info;
if (isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
// 目标provider已存在的情况
if (providerRunning) {
...
}
// 目标provider不存在的情况
if (!providerRunning) {
...
}
...
}
// Wait for the provider to be published...
//循环等待provider发布完成
synchronized (cpr) {
while (cpr.provider == null) {
...
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}
...
}
该方法比较长,也是获取provider的核心实现代码,这里分成以下3部分:
(1) 目标provider已存在的情况 (2) 目标provider不存在的情况 (3) 循环等待provider发布完成
2.5.1?目标provider已存在
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) {
//获取调用者的进程记录ProcessRecord
r = getRecordForAppLocked(caller);
...
}
...
// First check if this content provider has been published...
//从AMS中查询相应的ContentProviderRecord
cpr = mProviderMap.getProviderByName(name, 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) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
if (cpr != null) {
cpi = cpr.info;
if (isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
// 目标provider已存在的情况
if (providerRunning) {
cpi = cpr.info;
String msg;
...
//当允许运行在调用者进程且已发布,则直接返回
if (r != null && cpr.canRunHere(r)) {
// This provider has been published or is in the process
// of being published... but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
ContentProviderHolder holder = cpr.newHolder(null);
// don't give caller the provider object, it needs
// to make its own.
holder.provider = null;
return holder;
}
// Don't expose providers between normal apps and instant apps
try {
if (AppGlobals.getPackageManager()
.resolveContentProvider(name, 0 /*flags*/, userId) == null) {
return null;
}
} catch (RemoteException e) {
}
final long origId = Binder.clearCallingIdentity();
...
// In this case the provider instance already exists, so we can
// return it right away.
//增加引用计数
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// If this is a perceptible app accessing the provider,
// make sure to count it as being accessed and thus
// back up on the LRU list. This is good because
// content providers are often expensive to start.
checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
//更新进程LRU队列
updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
}
}
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
final int verifiedAdj = cpr.proc.verifiedAdj;
boolean success = updateOomAdjLocked(cpr.proc, true);
// XXX things have changed so updateOomAdjLocked doesn't actually tell us
// if the process has been successfully adjusted. So to reduce races with
// it, we will check whether the process still exists. Note that this doesn't
// completely get rid of races with LMK killing the process, but should make
// them much smaller.
if (success && verifiedAdj != cpr.proc.setAdj && !isProcessAliveLocked(cpr.proc)) {
success = false;
}
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
if (DEBUG_PROVIDER) Slog.i(TAG_PROVIDER, "Adjust success: " + success);
// NOTE: there is still a race here where a signal could be
// pending on the process even though we managed to update its
// adj level. Not sure what to do about this, but at least
// the race is now smaller.
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);
//provider进程被杀,则减少引用计数
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
checkTime(startTime, "getContentProviderImpl: before appDied");
appDiedLocked(cpr.proc);
checkTime(startTime, "getContentProviderImpl: after appDied");
if (!lastRef) {
// 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);
}
}
...
}
当ContentProvider所在进程已存在时的功能:
(1) 权限检查 (2) 当允许运行在调用者进程且已发布,则直接返回 (3) 增加引用计数 (4) 更新进程LRU队列 (5) 更新进程adj (6) 当provider进程被杀时,则减少引用计数并调用appDiedLocked,且设置ContentProvider为没有发布的状态
2.5.2?目标provider不存在
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) {
//获取调用者的进程记录ProcessRecord
r = getRecordForAppLocked(caller);
...
}
...
// First check if this content provider has been published...
//从AMS中查询相应的ContentProviderRecord
cpr = mProviderMap.getProviderByName(name, 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) {
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
if (cpr != null) {
cpi = cpr.info;
if (isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
// 目标provider不存在的情况
if (!providerRunning) {
try {
checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
//根据authority,获取ProviderInfo对象
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
} catch (RemoteException ex) {
}
if (cpi == null) {
return null;
}
// If the provider is a singleton AND
// (it's a call within the same user || the provider is a
// privileged app)
// Then allow connecting to the singleton provider
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_SYSTEM;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
checkTime(startTime, "getContentProviderImpl: got app info for user");
String msg;
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
...
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
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);
//创建对象ContentProviderRecord
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} 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)) {
// If this is a multiprocess provider, then just return its
// info and allow the caller to instantiate it. Only do
// this if the provider is the same user as the caller's
// process, or can run as root (so can be in any process).
return cpr.newHolder(null);
}
// 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;
//从mLaunchingProviders中查询是否存在该cpr
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// If the provider is not already being launched, then get it
// started.
//当provider并没有处于mLaunchingProviders队列,则启动它
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
// Content provider is now in use, its package can't be stopped.
try {
checkTime(startTime, "getContentProviderImpl: before set stopped state");
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
checkTime(startTime, "getContentProviderImpl: after set stopped state");
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ cpr.appInfo.packageName + ": " + e);
}
// Use existing process if already started
checkTime(startTime, "getContentProviderImpl: looking for process record");
//查询进程记录ProcessRecord
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) {
if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
"Installing in existing process " + proc);
if (!proc.pubProviders.containsKey(cpi.name)) {
checkTime(startTime, "getContentProviderImpl: scheduling install");
proc.pubProviders.put(cpi.name, cpr);
try {
//启动provider进程启动并发布provider
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
checkTime(startTime, "getContentProviderImpl: before start process");
// 启动进程
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
checkTime(startTime, "getContentProviderImpl: after start process");
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": process is bad");
return null;
}
}
cpr.launchingApp = proc;
//将cpr添加到mLaunchingProviders
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
checkTime(startTime, "getContentProviderImpl: updating data structures");
// Make sure the provider is published (the same provider class
// may be published under multiple names).
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
//增加引用计数
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
...
}
当ContentProvider所在进程没有存在时的功能:
(1) 根据authority,获取ProviderInfo对象 (2) 权限检查 (3) 当provider不是运行在system进程,且系统未准备好,则抛出IllegalArgumentException (4) 当拥有该provider的用户并没有运行,则直接返回 (5) 根据ComponentName,从AMS.mProviderMap中查询相应的ContentProviderRecord (6) 当首次调用,则创建对象ContentProviderRecord (7) 当允许运行在调用者进程且ProcessRecord不为空,则直接返回 (8) 当provider并没有处于mLaunchingProviders队列,则启动它 (9) 当ProcessRecord不为空,则加入到pubProviders,并开始安装provider (10) 当ProcessRecord为空,则启动进程 (11) 增加引用计数
2.5.3?等待目标provider发布
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
synchronized(this) {
...
// Wait for the provider to be published...
//循环等待provider发布完成
synchronized (cpr) {
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;
}
...
}
循环等待,直到provider发布完成才会退出循环。
一般地, 程序进行到此处, AT.acquireProvider方法应该已成功获取了Provider对象, 接下来便是安装Provider。通过调用installContentProviders()方法本地安装ContentProvider,这里可以简单理解所谓本地安装就是填充ActivityThread中保存ContentProvider接口的缓存,但是要注意当前的ActivityThread是表示定义ContentProvider的进程(App B),而不是使用ContentProvider的进程(App A)。
2.6?AT.installProvider
public final class ActivityThread extends ClientTransactionHandler {
...
/**
* Installs the provider.
*
* Providers that are local to the process or that come from the system server
* may be installed permanently which is indicated by setting noReleaseNeeded to true.
* Other remote providers are reference counted. The initial reference count
* for all reference counted providers is one. Providers that are not reference
* counted do not have a reference count (at all).
*
* This method detects when a provider has already been installed. When this happens,
* it increments the reference count of the existing provider (if appropriate)
* and returns the existing provider. This can happen due to concurrent
* attempts to acquire the same provider.
*/
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) {
...
} else {
provider = holder.provider;
}
ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, "
+ "using existing local provider");
}
provider = pr.mProvider;
} else {
holder = new ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
//根据jBinder,从mProviderRefCountMap中查询相应的ProviderRefCount
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, updating ref count");
}
// We need to transfer our new reference to the existing
// ref count, releasing the old one... but only if
// release is needed (that is, it is not running in the
// system process).
//只有当需要释放引用时则进入该分支
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;
}
...
private static final class ProviderRefCount {
public final ContentProviderHolder holder;
public final ProviderClientRecord client;
public int stableCount;
public int unstableCount;
...
}
}
获取ContentProviderHolder对象,该对象的成员变量provider记录着ContentProviderProxy对象。
2.6.1?AMS.removeContentProvider
public class ActivityManagerService extends IActivityManager.Stub implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
...
public void removeContentProvider(IBinder connection, boolean stable) {
enforceNotIsolatedCaller("removeContentProvider");
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)) {
updateOomAdjLocked();
}
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
boolean decProviderCountLocked(ContentProviderConnection conn,
ContentProviderRecord cpr, IBinder externalProcessToken, boolean stable) {
if (conn != null) {
cpr = conn.provider;
if (stable) {
conn.stableCount--;
} else {
conn.unstableCount--;
}
//当provider连接的 stable和unstable引用次数都为0时,则移除该连接对象信息
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;
}
...
}
2.7?CPP.query?
执行完acquireUnstableProvider()操作则成功获取了ContentProviderProxy
abstract public class ContentProviderNative extends Binder implements IContentProvider {
...
final class ContentProviderProxy implements IContentProvider {
...
}
...
}
abstract public class ContentProviderNative extends Binder implements IContentProvider {
...
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
switch (code) {
case QUERY_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
// String[] projection
int num = data.readInt();
String[] projection = null;
if (num > 0) {
projection = new String[num];
for (int i = 0; i < num; i++) {
projection[i] = data.readString();
}
}
Bundle queryArgs = data.readBundle();
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());
ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
Cursor cursor = query(callingPkg, url, projection, queryArgs, cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = null;
try {
adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
getProviderName());
cursor = null;
BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
adaptor = null;
reply.writeNoException();
reply.writeInt(1);
d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} finally {
// Close cursor if an exception was thrown while constructing the adaptor.
if (adaptor != null) {
adaptor.close();
}
if (cursor != null) {
cursor.close();
}
}
} else {
reply.writeNoException();
reply.writeInt(0);
}
return true;
}
...
}
}
}
final class ContentProviderProxy implements IContentProvider {
...
@Override
public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
int length = 0;
if (projection != null) {
length = projection.length;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(projection[i]);
}
data.writeBundle(queryArgs);
data.writeStrongBinder(adaptor.getObserver().asBinder());
data.writeStrongBinder(
cancellationSignal != null ? cancellationSignal.asBinder() : null);
//发送给Binder服务端
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
if (reply.readInt() != 0) {
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null);
adaptor.initialize(d);
} else {
adaptor.close();
adaptor = null;
}
return adaptor;
} catch (RemoteException ex) {
adaptor.close();
throw ex;
} catch (RuntimeException ex) {
adaptor.close();
throw ex;
} finally {
data.recycle();
reply.recycle();
}
}
...
}
...
}
到这里通过跨进程的方式,真正调用到了目标provider的query方法。
三、Provider 进程
3.1 两种场景
发布ContentProvider分两种情况:Provider进程尚未启动,Provider进程已启动但未发布。
场景一(Provider进程尚未启动):system_server进程调用startProcessLocked()创建provider进程且attach到system_server后,通过binder call到provider进程执行AT.bindApplication()方法 。
场景二(Provider进程已启动但未发布): provider进程已存在且attach到system_server,但所对应的provider还没有发布,通过binder call到provider进程执行AT.scheduleInstallProvider方法。
|