目录
- 1.前言
- 2.正文
- 2.1 小例子
- 2.2 代码分析
- 2.2.1 ContextWrapper.getContentResolver() 方法
- 2.2.2 ContextImpl.getContentResolver() 方法
- 2.2.3 ContentResolver.query() 方法
- 2.2.4 ContentResolver.acquireUnstableProvider() 方法
- 2.2.5 ApplicationContentResolver.acquireUnstableProvider() 方法
- 2.2.6 ActivityThread.acquireProvider() 方法
- 2.2.7 ActivityManagerProxy.getContentProvider() 方法
- 2.2.8 ActivityManagerNative.onTransact() 方法
- 2.2.9 ActivityManagerService.getContentProvider() 方法
- 2.2.10 ActivityManagerService.getContentProviderImpl() 方法
- 2.2.11 ActivityManagerService.startProcessLocked() 方法
- 2.2.12 ActivityManagerService.startProcessLocked() 方法
- 2.2.13 Process.start() 方法
- 2.2.14 ActivityThread.main() 方法
- 2.2.15 ActivityThread.attach() 方法
- 2.2.16 ActivityManagerService.attachApplication() 方法
- 2.2.17 ActivityManagerService.attachApplicationLocked() 方法
- 2.2.18 ApplicationThreadProxy.bindApplication() 方法
- 2.2.19 ApplicationThreadNative.onTransact() 方法
- 2.2.20 ApplicationThread.bindApplication() 方法
- 2.2.21 H.handleMessage() 方法
- 2.2.22 ActivityThread.handleBindApplication() 方法
- 2.2.23 ActivityThread.installContentProviders() 方法
- 2.2.24 ActivityThread.installProvider() 方法
- 2.2.25 ActivityManagerService.publishContentProviders() 方法
- 2.2.26 ActivityManagerService.getContentProviderImpl() 方法跳出循环等待 provider 发布
- 2.2.27 ActivityThread.acquireProvider() 方法
- 2.2.28 ContentProviderProxy.query() 方法
- 2.2.29 ContentProviderNative.onTransact() 方法
- 2.2.30 Transport.query() 方法
- 2.2.31 BookProvider.query() 方法
- 3.最后
- 4.参考
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) {
...
// 初始化 ApplicationContentResolver 对象。
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 对象,见【2.2.4】。
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
Cursor qCursor = null;
try {
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) { // cancellationSignal 为 null,所以不会进入此分支
...
}
try {
// 获取 Cursor 对象,见【2.2.28】
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
// 省略异常的代码部分
}
if (qCursor == null) {
return null;
}
qCursor.getCount();
// 把 Cursor 对象包装成 CursorWrapperInner 对象返回.
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())) { // uri.getScheme() 是 "content",不会进入此分支
return null;
}
String auth = uri.getAuthority(); // auth 等于 "com.wzc.chapter_9.bookprovider"
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) {
// 获取已经存在的 IContentProvider 对象,见【2.2.6.1】
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) { // 本次分析 provider 为 null,所以不会进入此分支了。
// 如果可以获取到已经存在的 IContentProvider 对象,就直接返回了。
return provider;
}
IActivityManager.ContentProviderHolder holder = null;
try {
// 向 AMS 请求获取 ContentProviderHolder 对象
// ActivityManagerNative.getDefault() 的返回 ActivityManagerProxy 对象,分析见 【2.2.6.2】
// ActivityManagerProxy.getContentProvider() 分析,见【2.2.7】
holder = ActivityManagerNative.getDefault().getContenProvider(
getApplicationThread(), auth, userId, stable)
} catch (RemoteException ex) {
}
if (holder == null) {
// 如果 AMS 返回的 ContentProviderHolder 对象为 null,则直接返回 null。
return null;
}
// 安装 provider 将会增加引用计数,并且打破竞争中的任何联系。
holder = installProvider(c, holder, holder.info,
true /*noisy*/, 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
// mProviderMap 以 ProviderKey 为键,以 ProviderClientRecord 为值
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) {
// 把 auth 和 userId 封装为 ProviderKey 对象。
final ProviderKey key = new ProviderKey(auth, userId);
// 从 mProviderMap 查找对应 ProviderKey 的 ProviderClientRecord 对象
final ProviderClientRecord pr = mProviderMap.get(key);
if (pr == null) {
// 本次分析,获取的 pr 为 null,所以直接在这里返回了。
return null;
}
// ###下面的代码,本次分析不会走到了###。
IContentProvider provider = pr.mProvider;
IBinder jBinder = provider.asBinder();
if (!jBinder.isBinderAlive()) {
// provider 的宿主进程已经死亡,不能使用这个 binder 了。
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
// 如果我们有一个 ProviderRefCount 对象,就仅仅增加引用计数;
// 否则,说明这个 provider 没有被引用计数,也不需要被释放。
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() 方法
// ActivityManagerNative 类:
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;
}
};
// 因为这里客户端和服务端不处于同一个进程,所以这个方法返回的是 ActivityManagerProxy 对象。
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);
// 见[【2.2.8】
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);
// 这里拿到把 BinderProxy 对象,转换成了 ContentProviderProxy 对象。
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();
// 获取的是 ApplicationThreadProxy 对象
IApplicationThread app = ApplicationThreadNative.asInterface(b);
String name = data.readString();
int userId = data.readInt();
boolean stable = data.readInt() != 0;
// 调用到这里,进入 AMS,见【2.2.9】
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("");
}
// 见【2.2.10】
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 {
// ProviderMap 结构,见【2.2.10.1】
final ProviderMap mProviderMap;
// mLaunchingProviders 记录客户端正在等待publish的ContentProviderRecord对象
// 应用当前正在被启动,provider 在被发布后就会从这个列表里面移除掉。
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) { // call 不为 null,进入此分支
// 获取发起方的进程记录 ProcessRecord 对象
r = getRecordForAppLocked(caller);
}
boolean checkCrossUser = true;
// 首先,检查这个 provider 是否已经被发布了
// 本次分析,我们的 provider 还未发布,因此这里会返回 null,cpr 为 null。
cpr = mProviderMap.getProviderByName(name, userId);
// userId 是 0,UserHandle.USER_OWNER 也是 0,所以不会进入此分支
if (cpr == null && userId != UserHandle.USER_OWNER) {
...
}
boolean providerRunning = cpr != null; // false,表示目标 provider 不存在。
if (providerRunning) { // providerRunning 为 false,不会进入此分支
...// 省略掉很多代码,它们与本次分析无关。
}
boolean singleton;
if (!providerRunning) { // 进入此分支
try {
// 通过 PKMS 来解析清单文件中的 provider 信息,ProviderInfo 对象
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
} catch (RemoteException ex) {
}
if (cpi == null) {
return null;
}
// 本次我们分析的是单实例 provider,因此 singleton 为 true。
singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_OWNER;
}
// getAppInfoForUser 获取包含用户信息的 ApplicationInfo 对象。
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
String msg;
// 检查发起方进程是否有权限获取此 provider
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
...
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
// 根据 class,从 mProviderMap 里面获取 ContentProviderRecord
// 本次分析,provider 还未发布,所以返回 null,所以 cpr 为 null。
cpr = mProviderMap.getProviderByClass(comp, userId);
final boolean firstClass = cpr == null; // firstClass 为 true
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);
// 创建 ContentProviderRecord 对象
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} catch (RemoteException ex) {
} finally {
Binder.restoreCallingIdentity(ident);
}
}
// 到这里,ContentProviderRecord cpr 对象一定不会为 null 了。
// canRunHere 判断 ContentProvider 是否能运行在发起方所在进程
// 本次分析,canRunHere() 返回 false,见【2.2.10.2】分析
if (r != null && cpr.canRunHere(r)) { // 不会进入此分支
return cpr.newHolder(null);
}
// 遍历 mLaunchingProviders,如果有元素等于 cpr,就跳出循环。
final int N = mLaunchingProviders.size();
int i;
for (i=0; i<N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
if (i >= N) { // i >= N,说明上面的循环走完了,没有中途跳出,也就是说,没有发现有元素等于 cpr。
final long origId = Binder.clearCallingIdentity();
try {
try {
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
}
// 获取 provider 所在进程(进程名字:"com.wzc.chapter_9.provider")的进程记录对象
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
// 进程记录存在且其 IApplicationThread 成员存在,则计划安装此provider。
// 本次分析,目标进程还没有启动,所以不会进入此分支
if (proc != null && proc.thread != null) {
proc.pubProviders.put(cpi.name, cpr);
try {
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
} else {
// 否则,开启对应的进程,见【2.2.11】
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 成员变量
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;
}
}
}
// 循环等待 provider 发布
// 本次分析,cpr.provider 为 null,因此会进入 while 循环。
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;
// 全局集合:存放的是单实例的 provider 记录
// 以 authority 为 key,以 CPR 为 value
private final HashMap<String, ContentProviderRecord> mSingletonByName
= new HashMap<String, ContentProviderRecord>();
// 以 class 为 key,以 CPR 为 value
private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
= new HashMap<ComponentName, ContentProviderRecord>();
// 按用户的userId,来管理对应的集合:存放的是多实例的 provider 记录。
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 /* isolatedUid */, keepIfLarge,
null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */,
null /* crashHandler */);
}
调用 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) { // isolated 为 false,进入此分支
// 获取进程名为 "com.wzc.chapter_9.provider" 的进程记录对象,这里还没有,所以返回 null。
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
} else {
...
}
if (app != null && app.pid > 0) { // app 为 null,不会进入此分支
...
}
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null;
if (!isolated) { // 进入此分支
if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0) { // intentFlags 为 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) { // 进入此分支
// 创建新的 ProcessRecord 对象,见【2.2.11.1】。
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;
}
// 启动新进程,见【2.2.12】
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) { // isolated 为 false,所以不会进入此分支
...
}
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) { // app.pid 为 0,不会进入此分支
...
}
mProcessesOnHold.remove(app);
updateCpuStats();
try {
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) { // isolated 为 false,会进入此分支
...
}
...
boolean isActivityProcess = (entryPoint == null); // true
// entryPoint 是 null,所以 entryPoint 会被赋值为 "android.app.ActivityThread"
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
// 开启进程:请求 zygote 去开启进程,见[2.2.13]
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);
...
// 设置 ProcessRecord app 的成员变量
app.setPid(startResult.pid);
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
app.killed = false;
app.killedByAm = false;
synchronized (mPidsSelfLocked) {
// 存储新进程的 pid 和 ProcessRecord 对象键值对到 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 {
// 通过 zygote 开启进程
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 对象
Looper.prepareMainLooper();
// 创建 ActivityThread 对象
ActivityThread thread = new ActivityThread();
// 调用 ActivityThread 对象的 attach 方法
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) { // system 为 false,进入此分支
...
RuntimeInit.setApplicationObject(mAppThread.asBinder());
// mgr 实际上是 ActivityManagerProxy 对象
final IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
...
} 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
// 存储了所有运行的进程,以pid为键,以ProcessRecord为值
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) {
// 根据 pid,获取到之前存储的 ProcessRecord 对象,不为 null。
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
if (app == null) { // 不会进入此分支
...
}
if (app.thread != null) { // app.thread 目前为 null,不会进入此分支
handleAppDiedLocked(app, true, true);
}
...
// mProcessesReady 为 true,所以这里 normalMode 为 true
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
// 获取清单文件中注册的 provider 信息
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 是 ApplicationThreadProxy 对象,见【2.2.18】
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 {
// 获取清单文件中注册的 provider 信息列表
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);
}
// 把 provider 信息添加到 ProcessRecord 的 pubProviders ArrayMap 里面。
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:
{
...
// 调用到这里,见【2.2.20】
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 里,通过 handler 发送到主线程。
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) {
...
// 获取 LoadedApk 对象,赋值给 data.info
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
// 来自 ProcessRecord 的 instrumentationClass,这个值只有在 AMS 的 startInstrumentation() 方法里赋值了
// 所以,本次分析 data.instrumentationName 为 null,不会进入 if 分支
if (data.instrumentationName != null) {
...
} else {
// 创建 Instrumentation 对象
mInstrumentation = new Instrumentation();
}
try {
// 创建 Application 对象
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) { // 非限制模式,进入 if 分支
// 获取清单中注册的 provider 信息列表
List<ProviderInfo> providers = data.providers;
if (providers != null) {
// 安装 content providers,见【2.2.23】
installContentProviders(app, providers);
}
}
try {
// 内部会调用 app.onCreate() 方法
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>();
// 遍历清单文件中的 provider 信息列表
for (ProviderInfo cpi : providers) {
// 安装每一个 provider,本次分析我们只有一个 provider 待安装,见【2.2.24】
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
// 见【2.2.25】
// ActivityManagerNative.getDefault() 是一个 ActivityManagerProxy 对象,通过它,经过 binder 驱动,向 binder 服务端的 AMS 发起远程调用。
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
// 在 2.2.6.2 中,我们绘制了这个集合的结构图
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) { // 进入此 if 分支
...
try {
final java.lang.ClassLoader cl = c.getClassLoader();
// 反射创建 ContentProvider 对象,本次分析创建的是 BookProvider 对象。
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
// 这里获取的是 Transport 对象,是 IContentProvider 接口的 binder 服务端对象。
provider = localProvider.getIContentProvider();
// 把 Context 对象和 ContentProvider 相关联,并回调 BookProvider 对象的 onCreate() 方法,见【2.2.24.1】
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {}
} else {
...
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) { // 进入此 if 分支
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
provider = pr.mProvider;
} else { // 进入 else 分支
holder = new IActivityManager.ContentProviderHolder(info);
holder.provider = provider;
holder.noReleaseNeeded = true;
// 把 provider 存储在 mProviderMap 里面,见【2.2.24.2】
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) {
// 保证 mContext 对象只被设置一次,这样 onCreate() 方法也是只会调用一次了。
if (mContext == null) {
mContext = context;
...
// 回调 BookProvider 的 onCreate() 方法
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);
// 把 holder 封装在 ProviderClientRecord 对象里面。
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 {
// 把对应的 ProviderKey 和 ProviderClientRecord 存储在 mProviderMap 集合里面。
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) {
// 获取 provider 目标进程的进程记录对象,已存在,所以 r 不为 null。
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;
}
// r.pubProviders 是
// final ArrayMap<String, ContentProviderRecord> pubProviders
// = new ArrayMap<String, ContentProviderRecord>();
// src.info.name 是 provider 的类名称
// 此处 dst 不为 null,因为在 2.2.17.1 中已经添加了 provider 信息到这个集合里面了。
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) {
// 这行代码非常关键,把 ContentProviderHolder src 的 provider 对象赋值给
// ContentProviderRecord dst 的 provider 变量。
dst.provider = src.provider;
// 把 provider 的目标进程记录对象赋值给 ContentProviderRecord dst 的 proc 变量。
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;
...
// 循环等待 provider 发布
// 到这里,cpr.provider 不为 null,因此会结束 while 循环。
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;
}
}
}
}
// 把 cpr 封装成 ContentProviderHolder 对象返回
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 {
// 这个方法会获取到结果 ContentProviderHolder 对象
holder = ActivityManagerNative.getDefault().getContenProvider(
getApplicationThread(), auth, userId, stable)
} catch (RemoteException ex) {
}
if (holder == null) { // 不会进入此分支
// 如果 AMS 返回的 ContentProviderHolder 对象为 null,则直接返回 null。
return null;
}
// 安装 provider 将会增加引用计数,并且打破竞争中的任何联系。见【2.2.27.1】
holder = installProvider(c, holder, holder.info,
true /*noisy*/, 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) { // 不会进入 if 分支
...
} else { // 命中 else 分支
provider = holder.provider;
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
if (localProvider != null) { // localProvider 为 null,不会进入 if 分支
...
} else { // 进入 else 分支
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) { // prc 为 null,不会进入 if 分支
...
} else { // 进入 else 分支
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) { // 进入 if 分支
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 对象
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 {
// 这里调用的就是 BookProvider 的 query 方法了。
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.最后
本文到这里就结束了,希望能够帮助到大家。
关于本文需要讨论的地方,可以在评论区留言讨论。