1.前言
ContentProvider (内容提供者)是 Android 的四大组件之一,是一种内容共享型组件,它提供了数据的统一访问格式,通过单一的 ContentResolver 接口把数据提供给其他应用。只有在多个应用之间分享数据时,ContentProvider 才是必须的。
由 ContentResolver 接口发起的insert(增加)、delete(删除)、update(更新)、query(查询)数据操作会发给 ContentProvider 对应的 insert(增加)、delete(删除)、update(更新)、query(查询)方法。
我们一般认为,内容提供者的数据来源是数据库,但实际上,内容提供者对底层的数据存储方式没有任何要求,可以使用数据库,也可以使用普通的文件,也可以使用内存中的一个对象,还可以使用网络数据。
换句话说,ContentProvider 提供了一种抽象,隔离了数据的使用方和数据的提供方,这样即便数据的提供方修改了数据存储实现,也不会影响到依赖数据访问的其他现有应用(即数据的使用方),具体而言,内容提供者使用数据库作为数据来源,当它把数据来源更改为 SharedPreferences 时,数据的使用方是不会受到影响的,数据的使用方是感知不到的。
在实际开发中,我们使用别人提供的内容提供者的时候比较多,比如使用 Android 系统中自带的电话簿(ContactsContract)获取联系人列表,使用 Android 系统中自带的 MediaStore(媒体库)获取媒体信息(如 MediaStore.Audio 音频数据,MediaStore.Video 视频数据,MediaStore.Files 文件数据,MediaStore.Images 图片数据)。Android 框架实现的部分内容提供程序位于 android.provider 包下。
而自己开发内容提供者给别人用比较少,一个应用是使用 ContentProvider 在 library 里直接获取上下文,不必再由主工程传递上下文给 library 了(不过,谷歌不推荐这样做)。
本文主要包括:
- 演示一个使用了
ContentProvider 的小例子,这也是我们本次要分析的场景; ContentProvider 的跨进程启动过程,这样我们就可以知道为什么 ContentProvider 的 onCreate() 方法要先于 Application 的 onCreate() 方法执行;ContentProvider 的数据操作方法调用过程,这里以 query(查询)方法为例来说明,这样可以知道由 ContentResolver 的 query 方法发起的查询操作如何最终交由 ContentProvider 的 query 方法来执行。
2.正文
2.1 小例子
例子部分请查看BookProvider。
本文不打算讲解这个例子了,因为本文已经很长了。
这里说明一下分析的场景:BookProvider 位于一个单独的进程里面;在客户端调用 ContentResolver 的 query 方法时,BookProvider 所处的进程还未启动,因此需要先开启目标进程。
2.2 代码分析
2.2.1 ContextWrapper.getContentResolver() 方法
@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}
这里的 ContextWrapper其实是装饰器设计模式的应用了,类结构图如下所示: 
调用装饰类 ContextWrapper 的 getContentResolver()方法,内部真正调用的是核心实现类 ContextImpl 的 getContentResolver()方法。所以 mBase 实际上是一个 ContextImpl 类型的对象。
2.2.2 ContextImpl.getContentResolver() 方法
class ContextImpl extends Context {
private final ApplicationContentResolver mContentResolver;
private ContextImpl(ContextImpl container, ActivityThread mainThread,
LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
Display display, Configuration overrideConfiguration) {
...
mContentResolver = new ApplicationContentResolver(this, mainThread, user);
}
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
private static final class ApplicationContentResolver extends ContentResolver {
private final ActivityThread mMainThread;
private final UserHandle mUser;
public ApplicationContentResolver(
Context context, ActivityThread mainThread, UserHandle user) {
super(context);
mMainThread = Preconditions.checkNotNull(mainThread);
mUser = Preconditions.checkNotNull(user);
}
@Override
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
...
}
}
可以看到,最终返回的是一个 mContentResolver 对象,它的类型是 ApplicationContentResolver,它是在 ContextImpl 的构造方法中被初始化的。
在初始化ApplicationContentResolver对象时,传入了 ActivityThread 对象,并且 ApplicationContentResolver 对象内部持有了 ActivityThread 对象。
ApplicationContentResolver是继承于 ContentResolver 抽象类的具体类,它是 ContextImpl 的私有嵌套内部类。
让我们用 UML 图来表示它们之间的关系:  可以看到,ApplicationContentResolver 实现了基类 ContentResolver 的一系列 acquireXXX 以及 releaseXXX 的方法,而方法内部的实现则是委托给 ActivityThread 对象的相应方法来完成。
2.2.3 ContentResolver.query() 方法
- Uri uri, Uri.parse(“content://com.wzc.chapter_9.bookprovider/books”)
- String[] projection, null
- String selection, null
- String[] selectionArgs, null
- String sortOrder, null
public final Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
调用重载的 query() 方法:
- Uri uri, Uri.parse(“content://com.wzc.chapter_9.bookprovider/books”)
- String[] projection, null
- String selection, null
- String[] selectionArgs, null
- String sortOrder, null
- CancellationSignal cancellationSignal, null
public final Cursor query(final Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
CancellationSignal cancellationSignal) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
Cursor qCursor = null;
try {
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
...
}
try {
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
}
if (qCursor == null) {
return null;
}
qCursor.getCount();
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, acquireProvider(uri));
qCursor = null;
return wrapper;
} catch (RemoteException e) {
return null;
} finally {
if (qCursor != null) {
qCursor.close();
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
}
}
}
2.2.4 ContentResolver.acquireUnstableProvider() 方法
- Uri uri, Uri.parse(“content://com.wzc.chapter_9.bookprovider/books”)
public static final String SCHEME_CONTENT = "content";
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;
}
调用重载的 acquireUnstableProvider() 方法:
protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
这是一个抽象方法,它的实现是在 ContextImpl.ApplicationContentResolver 里面。
这里出现了 IContentProvider 接口,这是一个用于跨进程通信的接口。与之相关的 binder 客户端与服务端类 UML 图如下:  比较疑惑的是,这里返回的 IContentProvider 对象到底是个什么对象,是 ContentProviderProxy 对象,还是 ContentProviderNative 对象呢?
我们现在还不得而知,但是我们可以通过Debug:
getContentResolver().acquireUnstableProvider(BookStore.Books.CONTENT_URI);
得到:  很明显,返回的是一个 ContentProviderProxy 对象,也就是说,是一个 binder 客户端对象。
那么,客户端进程就是通过这个 binder 客户端对象,经过 binder 驱动,发起远程调用,从 binder 服务端那里获取到数据的。
而由上面的类图可知,IContentProvider 接口对应的 binder 服务端对象是 ContentProvider 的内部类 Transport。
这样就构成了 binder 跨进程通信的客户端和服务端了。
2.2.5 ApplicationContentResolver.acquireUnstableProvider() 方法
- Context c, ContextImpl 对象
- String auth, “com.wzc.chapter_9.bookprovider”
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
本次的 auth 经过 ContentProvider.getAuthorityWithoutUserId(auth) 后,仍为 "com.wzc.chapter_9.bookprovider"。 resolveUserIdFromAuthority(auth) 的结果是 0。
2.2.6 ActivityThread.acquireProvider() 方法
- Context c, ContextImpl 对象
- String auth, “com.wzc.chapter_9.bookprovider”
- int userId, 0
- boolean stable, false
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContenProvider(
getApplicationThread(), auth, userId, stable)
} catch (RemoteException ex) {
}
if (holder == null) {
return null;
}
holder = installProvider(c, holder, holder.info,
true , holder.noReleaseNeeded, stable);
return holder.provider;
}
该方法的主要作用:
- 尝试获取已经存在的
IContentProvider 对象; - 如果 1 获取不到
IContentProvider 对象,再向 AMS 请求获取 ContentProviderHolder 对象; - 如果 2 获取的
ContentProviderHolder 对象不为 null,则调用安装 provider 的方法。
2.2.6.1 ActivityThread.acquireExistingProvider() 方法
- Context c, ContextImpl 对象
- String auth, “com.wzc.chapter_9.bookprovider”
- int userId, 0
- boolean stable, false
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
= new ArrayMap<ProviderKey, ProviderClientRecord>();
final ArrayMap<IBinder, ProviderRefCount> mProviderRefCountMap
= new ArrayMap<IBinder, ProviderRefCount>();
public final IContentProvider acquireExistingProvider(
Context c, String auth, int userId, boolean stable) {
synchronized (mProviderMap) {
final ProviderKey key = new ProviderKey(auth, userId);
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
return null;
}
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
if (!jBinder.isBinderAlive()) {
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
incProviderRefLocked(prc, stable);
}
return provider;
}
}
mProviderMap 是一个 ArrayMap 对象,是 ActivityThread 的一个成员变量,表示在该进程记录的 provider 信息。不过,目前它还是一个空的 ArrayMap 对象。
mProviderMap 是一个重要的集合,我们绘制下它的结构图如下:

2.2.6.2 ActivityManagerNative.getDefault() 方法
static public IActivityManager getDefault() {
return gDefault.get();
}
private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
protected IActivityManager create() {
IBinder b = ServiceManager.getService("activity");
IActivityManager am = asInterface(b);
return am;
}
};
static public IActivityManager asInterface(IBinder obj) {
if (obj == null) {
return null;
}
IActivityManager in =
(IActivityManager)obj.queryLocalInterface(descriptor);
if (in != null) {
return in;
}
return new ActivityManagerProxy(obj);
}
public abstract class Singleton<T> {
private T mInstance;
protected abstract T create();
public final T get() {
synchronized (this) {
if (mInstance == null) {
mInstance = create();
}
return mInstance;
}
}
}
这里采用的是局部单例技术,保证获取到的 IActivityManager 对象总是一个对象,实际上是 ActivityManagerProxy 对象。
2.2.7 ActivityManagerProxy.getContentProvider() 方法
-
IApplicationThread caller, ActivityThread 的 ApplicationThread 对象 mApplicationThread,是 binder 服务端对象 -
String name, “com.wzc.chapter_9.bookprovider” -
int userId, 0 -
boolean stable, false
class ActivityManagerProxy implements IActivityManager
{
public ContentProviderHolder getContentProvider(IApplicationThread caller,
String name, int userId, boolean stable) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeString(name);
data.writeInt(userId);
data.writeInt(stable ? 1 : 0);
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
ContentProviderHolder cph = null;
if (res != 0) {
cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
}
data.recycle();
reply.recycle();
return cph;
}
}
这个方法仍是在客户端进程调用的。
mRemote.transact() 是客户端进程发起 binder 通信的方法,经过 binder 驱动,最后会到 binder 服务端 ActivityManagerNative的 onTransact() 方法。
这里远程调用返回的 reply 值,最终会转为一个 ContentProviderHolder 对象,返回给客户端调用者。从 ContentProviderHolder 的名字来看,它是 ContentProvider 的持有者或者说 ContentProviderHolder 的容器。
ContentProviderHolder 类是 IActivityManager 接口的嵌套内部类。
public static class ContentProviderHolder implements Parcelable {
public final ProviderInfo info;
public IContentProvider provider;
public IBinder connection;
public boolean noReleaseNeeded;
public ContentProviderHolder(ProviderInfo _info) {
info = _info;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
info.writeToParcel(dest, 0);
if (provider != null) {
dest.writeStrongBinder(provider.asBinder());
} else {
dest.writeStrongBinder(null);
}
dest.writeStrongBinder(connection);
dest.writeInt(noReleaseNeeded ? 1:0);
}
public static final Parcelable.Creator<ContentProviderHolder> CREATOR
= new Parcelable.Creator<ContentProviderHolder>() {
@Override
public ContentProviderHolder createFromParcel(Parcel source) {
return new ContentProviderHolder(source);
}
@Override
public ContentProviderHolder[] newArray(int size) {
return new ContentProviderHolder[size];
}
};
private ContentProviderHolder(Parcel source) {
info = ProviderInfo.CREATOR.createFromParcel(source);
provider = ContentProviderNative.asInterface(
source.readStrongBinder());
connection = source.readStrongBinder();
noReleaseNeeded = source.readInt() != 0;
}
}
可以看到,ContentProviderHolder 是一个实现了 Parcelable 接口的类,所以它可以被序列化和反序列化。它封装了 provider 在清单中注册的信息,ContentProviderProxy 对象等。
2.2.8 ActivityManagerNative.onTransact() 方法
public abstract class ActivityManagerNative extends Binder implements IActivityManager
{
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
switch (code) {
case GET_CONTENT_PROVIDER_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
IBinder b = data.readStrongBinder();
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String name = data.readString();
int userId = data.readInt();
boolean stable = data.readInt() != 0;
ContentProviderHolder cph = getContentProvider(app, name, userId, stable);
reply.writeNoException();
if (cph != null) {
reply.writeInt(1);
cph.writeToParcel(reply, 0);
} else {
reply.writeInt(0);
}
return true;
}
}
}
}
这个方法是运行在服务端进程了,在这里是 system_server 进程。
ActivityManagerNative 是抽象类,getContentProvider() 是它的一个抽象方法。
ActivityManagerService 继承了 ActivityManagerNative,实现了 getContentProvider() 这个抽象方法。
2.2.9 ActivityManagerService.getContentProvider() 方法
- IApplicationThread caller, ApplicationThreadProxy 对象
- String name, “com.wzc.chapter_9.bookprovider”
- int userId, 0
- boolean stable, false
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
throw new SecurityException("");
}
return getContentProviderImpl(caller, name, null, stable, userId);
}
该方法的主要作用:检查 IApplicationThread caller 是不是为 null,通过检查后,调用 getContentProviderImpl() 方法。
2.2.10 ActivityManagerService.getContentProviderImpl() 方法
- IApplicationThread caller, ApplicationThreadProxy 对象
- String name, “com.wzc.chapter_9.bookprovider”
- IBinder token, null
- boolean stable, false
- int userId, 0
public final class ActivityManagerService extends ActivityManagerNative {
final ProviderMap mProviderMap;
final ArrayList<ContentProviderRecord> mLaunchingProviders
= new ArrayList<ContentProviderRecord>();
public ActivityManagerService(Context systemContext) {
mProviderMap = new ProviderMap(this);
}
private final 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.elapsedRealtime();
ProcessRecord r = null;
if (caller != null) {
r = getRecordForAppLocked(caller);
}
boolean checkCrossUser = true;
cpr = mProviderMap.getProviderByName(name, userId);
if (cpr == null && userId != UserHandle.USER_OWNER) {
...
}
boolean providerRunning = cpr != null;
if (providerRunning) {
...
}
boolean singleton;
if (!providerRunning) {
try {
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
} catch (RemoteException ex) {
}
if (cpi == null) {
return null;
}
singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_OWNER;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
String msg;
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
...
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
cpr = mProviderMap.getProviderByClass(comp, userId);
final boolean firstClass = cpr == null;
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
try {
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS, userId);
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);
} catch (RemoteException ex) {
} finally {
Binder.restoreCallingIdentity(ident);
}
}
if (r != null && cpr.canRunHere(r)) {
return cpr.newHolder(null);
}
final int N = mLaunchingProviders.size();
int i;
for (i=0; i<N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
try {
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
}
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null) {
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
} else {
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
if (proc == null) {
return null;
}
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
}
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;
}
}
该方法的主要作用:
- 尝试从 AMS 持有的数据结构
mProviderMap 中获取到 ContentProviderRecord 对象; - 如果 1 无法拿到
ContentProviderRecord 对象,说明 provider 还未发布,对发起方进程进行权限检查等操作后,创建一个 ContentProviderRecord 对象; - 检查 provider 是否可以运行在发起方进程里面,本次不可以;
- 判断
ContentProviderRecord 是否是客户端在等待发布的,不是,则进入 5,是,则进入 6; - 判断 provider 的目标进程是否存在,不存在,则需要去开启对应的目标进程;
- 把
ContentProviderRecord 存到 mProviderMap 数据结构中,增加 provider 引用计数; - 循环等待 provider 发布。
2.2.10.1 ProviderMap 类
public final class ProviderMap {
private static final String TAG = "ProviderMap";
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>>();
ProviderMap(ActivityManagerService am) {
mAm = am;
}
ContentProviderRecord getProviderByName(String name) {
return getProviderByName(name, -1);
}
ContentProviderRecord getProviderByName(String name, int userId) {
ContentProviderRecord record = mSingletonByName.get(name);
if (record != null) {
return record;
}
return getProvidersByName(userId).get(name);
}
ContentProviderRecord getProviderByClass(ComponentName name) {
return getProviderByClass(name, -1);
}
ContentProviderRecord getProviderByClass(ComponentName name, int userId) {
ContentProviderRecord record = mSingletonByClass.get(name);
if (record != null) {
return record;
}
return getProvidersByClass(userId).get(name);
}
void putProviderByName(String name, ContentProviderRecord record) {
if (record.singleton) {
mSingletonByName.put(name, record);
} else {
final int userId = UserHandle.getUserId(record.appInfo.uid);
getProvidersByName(userId).put(name, record);
}
}
void putProviderByClass(ComponentName name, ContentProviderRecord record) {
if (record.singleton) {
mSingletonByClass.put(name, record);
} else {
final int userId = UserHandle.getUserId(record.appInfo.uid);
getProvidersByClass(userId).put(name, record);
}
}
void removeProviderByName(String name, int userId) {
if (mSingletonByName.containsKey(name)) {
mSingletonByName.remove(name);
} else {
if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
HashMap<String, ContentProviderRecord> map = getProvidersByName(userId);
map.remove(name);
if (map.size() == 0) {
mProvidersByNamePerUser.remove(userId);
}
}
}
void removeProviderByClass(ComponentName name, int userId) {
if (mSingletonByClass.containsKey(name)) {
mSingletonByClass.remove(name);
} else {
if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
HashMap<ComponentName, ContentProviderRecord> map = getProvidersByClass(userId);
map.remove(name);
if (map.size() == 0) {
mProvidersByClassPerUser.remove(userId);
}
}
}
private HashMap<String, ContentProviderRecord> getProvidersByName(int userId) {
if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
final HashMap<String, ContentProviderRecord> map = mProvidersByNamePerUser.get(userId);
if (map == null) {
HashMap<String, ContentProviderRecord> newMap = new HashMap<String, ContentProviderRecord>();
mProvidersByNamePerUser.put(userId, newMap);
return newMap;
} else {
return map;
}
}
HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int userId) {
if (userId < 0) throw new IllegalArgumentException("Bad user " + userId);
final HashMap<ComponentName, ContentProviderRecord> map
= mProvidersByClassPerUser.get(userId);
if (map == null) {
HashMap<ComponentName, ContentProviderRecord> newMap
= new HashMap<ComponentName, ContentProviderRecord>();
mProvidersByClassPerUser.put(userId, newMap);
return newMap;
} else {
return map;
}
}
}
虽然这个类的名字叫 ProviderMap,但是它并不是一个 Map 的子类。这个类采用组合的方式,内部管理了 mSingletonByName ,mSingletonByClass,mProvidersByNamePerUser,mProvidersByClassPerUser四个集合对象,并定义了方法来实现元素的添加,获取,删除操作。
思考一下:为什么要使用组合的方式而不是继承的方式来实现 ProviderMap?
因为采用继承的方式,就要受限于父类的接口;而这里要实现对单实例集合和多实例集合的分别管理,采用组合可以达到这种目的。
这个类在后面用的比较多,所以这里重点说明了一下它的结构。
2.2.10.2 ContentProviderRecord.canRunHere() 方法
- ProcessRecord app, 调用方进程记录对象
final class ContentProviderRecord {
public final ProviderInfo info;
final int uid;
public boolean canRunHere(ProcessRecord app) {
return (info.multiprocess || info.processName.equals(app.processName))
&& uid == app.info.uid;
}
}
该方法的主要作用:判断 provider 是否可以运行在调用方进程。需要满足两个条件:
- 条件一:provider 在清单文件中设置了
android:multiprocess="true",或者 provider 的进程名字和调用方进程名字一致; - 条件二:provider 的 uid 和调用方进程的 uid 一致。
本次分析,不满足条件一:provider 在清单文件中没有设置 android:multiprocess="true",且provider 的进程名字("com.wzc.chapter_9.provider")和调用方进程名字("com.wzc.chapter_9")不一致,所以这个方法返回 false,即 provider 不可以运行在调用方进程。
2.2.11 ActivityManagerService.startProcessLocked() 方法
- String processName, “com.wzc.chapter_9.provider”
- ApplicationInfo info, 清单文件中的 application 节点信息
- boolean knownToBeDead, false
- int intentFlags, 为 0,
- String hostingType, “content provider”
- ComponentName hostingName, ContentProvider 的组件名对象,即包名 + 类名的组合
- boolean allowWhileBooting, false
- boolean isolated, false
- boolean keepIfLarge false
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType,
hostingName, allowWhileBooting, isolated, 0 , keepIfLarge,
null , null , null ,
null );
}
调用 startProcessLocked 的重载方法:
- String processName, “com.wzc.chapter_9.provider”
- ApplicationInfo info, 清单文件中的 application 节点信息
- boolean knownToBeDead, false
- int intentFlags, 为 0,
- String hostingType, “content provider”
- ComponentName hostingName, ContentProvider 的组件名对象,即包名 + 类名的组合
- boolean allowWhileBooting, false
- boolean isolated, false
- int isolatedUid, 0
- boolean keepIfLarge false
- String abiOverride, null
- String entryPoint, null
- String[] entryPointArgs, null
- Runnable crashHandler, null
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info,
boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName,
boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge,
String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) {
long startTime = SystemClock.elapsedRealtime();
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
} else {
...
}
if (app != null && app.pid > 0) {
...
}
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
if (!isolated) {
if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) {
...
} else {
mProcessCrashTimes.remove(info.processName, info.uid);
if (mBadProcesses.get(info.processName, info.uid) != null) {
mBadProcesses.remove(info.processName, info.uid);
if (app != null) {
app.bad = false;
}
}
}
}
if (app == null) {
app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
app.crashHandler = crashHandler;
if (app == null) {
return null;
}
mProcessNames.put(processName, app.uid, app);
...
} else {
...
}
if (!mProcessesReady
&& !isAllowedWhileBooting(info)
&& !allowWhileBooting) {
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app);
}
return app;
}
startProcessLocked(
app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
return (app.pid != 0) ? app : null;
}
2.2.11.1 ActivityManagerService.newProcessRecordLocked() 方法
- ApplicationInfo info, 清单文件中的 application 节点信息
- String customProcess, “com.wzc.chapter_9.provider”
- boolean isolated, false
- int isolatedUid, 0
final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
boolean isolated, int isolatedUid) {
String proc = customProcess != null ? customProcess : info.processName;
BatteryStatsImpl.Uid.Proc ps = null;
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
int uid = info.uid;
if (isolated) {
...
}
return new ProcessRecord(stats, info, proc, uid);
}
该方法的作用:创建了一个 ProcessRecord 对象而已。
2.2.12 ActivityManagerService.startProcessLocked() 方法
- ProcessRecord app, 新创建的 ProcessRecord 对象
- String hostingType, “service”
- String hostingNameStr, Service 的组件名对象转换成的字符串,即"com.wzc.chapter_9/.provider.BookProvider"
- String abiOverride, null
- String entryPoint, null
- String[] entryPointArgs, null
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
long startTime = SystemClock.elapsedRealtime();
if (app.pid > 0 && app.pid != MY_PID) {
...
}
mProcessesOnHold.remove(app);
updateCpuStats();
try {
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
...
}
...
boolean isActivityProcess = (entryPoint == null);
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
...
app.setPid(startResult.pid);
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
app.killed = false;
app.killedByAm = false;
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
if (isActivityProcess) {
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, startResult.usingWrapper
? PROC_START_TIMEOUT_WITH_WRAPPER : PROC_START_TIMEOUT);
}
}
} catch (RuntimeException e) {
...
}
}
2.2.13 Process.start() 方法
- final String processClass, “android.app.ActivityThread”
- final String niceName, “com.wzc.chapter_9.provider”
- int uid,
- int gid,
- int[] gids,
- int debugFlags,
- int mountExternal,
- int targetSdkVersion, 目标 sdk 版本
- String seInfo,
- String abi, 架构
- String instructionSet, 指令集
- String appDataDir,
- String[] zygoteArgs, null
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
system_server 进程里,调用 Process.start() 方法,通过 socket 向 zygote 进程发送创建新进程的请求;
在 zygote 进程里面,在执行ZygoteInit.main()后便进入runSelectLoop()循环体内,当有客户端连接时便会执行ZygoteConnection.runOnce()方法,再经过层层调用后 fork 出新的应用进程;
新的进程创建后,执行handleChildProc方法,最后调用ActivityThread.main()方法。
这部分详细请参考理解Android进程创建流程-袁辉辉。
本文会直接跳到 ActivityThread.main() 方法继续分析。
2.2.14 ActivityThread.main() 方法
public static void main(String[] args) {
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
2.2.15 ActivityThread.attach() 方法
- boolean system, false,表示不是系统进程,而是普通应用进程
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
...
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
}
...
} else {
...
}
...
}
2.2.16 ActivityManagerService.attachApplication() 方法
- IApplicationThread thread, ApplicationThreadProxy 对象
@Override
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
2.2.17 ActivityManagerService.attachApplicationLocked() 方法
- IApplicationThread thread, ApplicationThreadProxy 对象
- int pid, provider 进程的 pid
final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
ProcessRecord app;
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
if (app == null) {
...
}
if (app.thread != null) {
handleAppDiedLocked(app, true, true);
}
...
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
try {
...
ApplicationInfo appInfo = app.instrumentationInfo != null
? app.instrumentationInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
if (profileFd != null) {
profileFd = profileFd.dup();
}
ProfilerInfo profilerInfo = profileFile == null ? null
: new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
...
}
...
return true;
}
2.2.17.1 ActivityManagerService.generateApplicationProvidersLocked() 方法
private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) {
List<ProviderInfo> providers = null;
try {
providers = AppGlobals.getPackageManager().
queryContentProviders(app.processName, app.uid,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
} catch (RemoteException ex) {
}
int userId = app.userId;
if (providers != null) {
int N = providers.size();
app.pubProviders.ensureCapacity(N + app.pubProviders.size());
for (int i=0; i<N; i++) {
ProviderInfo cpi =
(ProviderInfo)providers.get(i);
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
if (cpr == null) {
cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
mProviderMap.putProviderByClass(comp, cpr);
}
app.pubProviders.put(cpi.name, cpr);
if (!cpi.multiprocess || !"android".equals(cpi.packageName)) {
app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
mProcessStats);
}
}
}
return providers;
}
2.2.18 ApplicationThreadProxy.bindApplication() 方法
public final void bindApplication(...) throws RemoteException {
...
mRemote.transact(BIND_APPLICATION_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
data.recycle();
}
这个方法仍是在 system_server 进程(是 binder 客户端进程)调用的。
mRemote.transact() 是 system_server 进程发起 binder 通信的方法,经过 binder 驱动,最后会到 provider 的目标进程(是 binder 服务端)ApplicationThreadNative的 onTransact() 方法。
2.2.19 ApplicationThreadNative.onTransact() 方法
public abstract class ApplicationThreadNative extends Binder
implements IApplicationThread {
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
case BIND_APPLICATION_TRANSACTION:
{
...
bindApplication(packageName, info, providers, testName, profilerInfo, testArgs,
testWatcher, uiAutomationConnection, testMode, openGlTrace,
restrictedBackupMode, persistent, config, compatInfo, services, coreSettings);
return true;
}
}
}
这个方法是运行在 provider 的目标进程里的。
ApplicationThreadNative 是一个抽象类,而 bindApplication()是它的一个抽象方法。
ApplicationThread 是继承于 ApplicationThreadNative 的具体类,它实现了 bindApplication() 方法。
ApplicationThread 类是 ActivityThread 的私有内部类。
2.2.20 ApplicationThread.bindApplication() 方法
public final void bindApplication(...) {
...
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
...
sendMessage(H.BIND_APPLICATION, data);
}
这个方法目前是运行在 provider 的目标进程的 binder 线程池里面的。
2.2.21 H.handleMessage() 方法
public final class ActivityThread {
final H mH = new H();
private class H extends Handler {
public void handleMessage(Message msg) {
case BIND_APPLICATION:
AppBindData data = (AppBindData)msg.obj;
handleBindApplication(data);
break;
}
}
}
这个方法目前是运行在 provider 的目标进程的主线程里面的。
2.2.22 ActivityThread.handleBindApplication() 方法
private void handleBindApplication(AppBindData data) {
...
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
if (data.instrumentationName != null) {
...
} else {
mInstrumentation = new Instrumentation();
}
try {
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
}
}
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {}
} finally {}
}
该方法的主要作用:
- 创建
Instrumentation 对象; - 创建
Application 对象; - 安装 content providers:创建 provider 对象,回调了 provider 的
onCreate() 方法,并存储了 provider 信息到对应的数据结构中; - 回调
Application 对象的 onCreate() 方法。
从这里可以知道,ContentProvider 的 onCreate() 方法在 Application 的 onCreate() 方法之前回调。
而ContentProvider 的 onCreate() 方法是在主线程调用的,那么如果在 ContentProvider 的 onCreate() 方法里执行了耗时操作,势必会推迟Application 的 onCreate() 方法的回调,也就是说,推迟了应用的初始化操作了,对于用户来说,就是应用启动缓慢了,这多么不好啊。
所以,一定不要在 ContentProvider 的 onCreate() 方法里面执行耗时操作。
2.2.23 ActivityThread.installContentProviders() 方法
- Context context, provider 进程的 Application 对象
- List providers, 清单文件中的 provider 信息列表
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false , true , true );
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
}
该方法的主要作用:
- 安装 provider;
- 发布安装结果:由 provider 目标进程向 system_server 进程的 AMS 发起远程请求。
2.2.24 ActivityThread.installProvider() 方法
- Context context, provider 进程的 Application 对象
- IActivityManager.ContentProviderHolder holder, null
- ProviderInfo info, 清单文件中的 provider 信息
- boolean noisy, false
- boolean noReleaseNeeded, true
- boolean stable, true
final ArrayMap<ProviderKey, ProviderClientRecord> mProviderMap
= new ArrayMap<ProviderKey, ProviderClientRecord>();
final ArrayMap<ComponentName, ProviderClientRecord> mLocalProvidersByName
= new ArrayMap<ComponentName, ProviderClientRecord>();
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
if (holder == null || holder.provider == null) {
...
try {
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {}
} else {
...
}
IActivityManager.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) {
provider = pr.mProvider;
} else {
holder = new IActivityManager.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 {
...
}
}
return retHolder;
}
该方法的主要作用:
- 通过反射创建
ContentProvider 对象; - 通过
ContentProvider.attachInfo() 方法把 Context 对象和 ContentProvider 相关联,并回调 BookProvider 对象的 onCreate() 方法; - 存储 provider 信息到相关的数据结构中。
2.2.24.1 ContentProvider.attachInfo() 方法
private void attachInfo(Context context, ProviderInfo info, boolean testing) {
if (mContext == null) {
mContext = context;
...
ContentProvider.this.onCreate();
}
}
该方法的主要作用:把 Context 对象和 ContentProvider 相关联,并回调 BookProvider 对象的 onCreate() 方法。
2.2.24.2 ActivityThread.installProviderAuthoritiesLocked() 方法
- IContentProvider provider, ContentProvider 的 Transport 对象
- ContentProvider localProvider, BookProvider 对象
- IActivityManager.ContentProviderHolder holder,
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
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;
}
2.2.25 ActivityManagerService.publishContentProviders() 方法
- IApplicationThread caller, provider 目标进程的 ApplicationThread 对象
- List providers, ContentProviderHolder 列表
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
final int N = providers.size();
for (int i=0; i<N; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
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);
}
...
synchronized (dst) {
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}
}
}
}
}
2.2.26 ActivityManagerService.getContentProviderImpl() 方法跳出循环等待 provider 发布
回到 2.2.10 的分析部分:
public final class ActivityManagerService extends ActivityManagerNative {
final ProviderMap mProviderMap;
final ArrayList<ContentProviderRecord> mLaunchingProviders
= new ArrayList<ContentProviderRecord>();
public ActivityManagerService(Context systemContext) {
mProviderMap = new ProviderMap(this);
}
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
...
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;
}
}
2.2.27 ActivityThread.acquireProvider() 方法
回到 2.2.6 的部分分析:
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
...
IActivityManager.ContentProviderHolder holder = null;
try {
holder = ActivityManagerNative.getDefault().getContenProvider(
getApplicationThread(), auth, userId, stable)
} catch (RemoteException ex) {
}
if (holder == null) {
return null;
}
holder = installProvider(c, holder, holder.info,
true , holder.noReleaseNeeded, stable);
return holder.provider;
}
这个方法执行完毕,就获得了 ContentProviderProxy 对象了。
2.2.27.1 ActivityThread.installProvider() 方法
虽然我们在 2.2.24 中也分析了这个方法,但是和这里是有区别的:
2.2.24 中的 installProvider方法是发生在 provider 目标进程的主线程;
这里的 installProvider 方法是发生在客户端进程的主线程。
- Context context, ContextImpl 对象
- IActivityManager.ContentProviderHolder holder, 不为 null
- ProviderInfo info, 清单文件中的 provider 信息
- boolean noisy, true
- boolean noReleaseNeeded, true
- boolean stable, false
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.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;
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
...
} else {
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
...
} else {
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
...
}
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}
该方法的作用:把 provider 信息存入 mProviderMap 集合和 mProviderRefCountMap 集合中。
2.2.27.2 ActivityThread.installProviderAuthoritiesLocked() 方法
private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider,
ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) {
final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority);
final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid);
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;
}
该方法的作用:把 provider 信息存入 mProviderMap 集合中。
2.2.28 ContentProviderProxy.query() 方法
final class ContentProviderProxy implements IContentProvider
{
public Cursor query(String callingPkg, Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
...
data.writeStrongBinder(adaptor.getObserver().asBinder());
data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
if (reply.readInt() != 0) {
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
adaptor.initialize(d);
} else {
adaptor.close();
adaptor = null;
}
return adaptor;
}
}
}
这个方法是运行在客户端进程的。
mRemote.transact() 是 客户端进程发起 binder 通信的方法,经过 binder 驱动,最后会到 provider 的目标进程(是 binder 服务端)ContentProviderNative的 onTransact() 方法。
2.2.29 ContentProviderNative.onTransact() 方法
@Override
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
case QUERY_TRANSACTION:
{
...
Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
sortOrder, 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 {}
} else {
reply.writeNoException();
reply.writeInt(0);
}
return true;
}
}
ContentProviderNative 是一个抽象类,query方法是它的一个抽象方法。
ContentProvider.Transport 是 ContentProviderNative 的具体实现类。
2.2.30 Transport.query() 方法
@Override
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri) != AppOpsManager.MODE_ALLOWED) {
return rejectQuery(uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
}
final String original = setCallingPackage(callingPkg);
try {
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
2.2.31 BookProvider.query() 方法
@Nullable
@Override
public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {
final int code = MATCHER.match(uri);
if (code == CODE_BOOK_DIR || code == CODE_BOOK_ITEM) {
Context context = getContext();
if (context == null) {
return null;
}
BookDao bookDao = AppDatabase.getInstance(context).bookDao();
final Cursor cursor;
if (code == CODE_BOOK_DIR) {
cursor = bookDao.queryAll();
} else {
cursor = bookDao.queryById(ContentUris.parseId(uri));
}
cursor.setNotificationUri(context.getContentResolver(), uri);
return cursor;
} else {
throw new IllegalArgumentException("Unknown URI: " + uri);
}
}
3.最后
本文到这里就结束了,希望能够帮助到大家。
关于本文需要讨论的地方,可以在评论区留言讨论。
4.参考
- 理解ContentProvider原理-袁辉辉
- ContentProvider引用计数-袁辉辉
- Android Cursor浅析
|