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浅析
|