标题前言
我们熟知一般 Android 工程师都是在应用层上开发,不会涉及系统源码,但是如果你想往底层发展,或者深入插件化、Framework 系统层等开发工作,如果不了解 Android 源码可是不行的,那么接下来我基于自己的理解跟学习来记录跟 Android 开发息息相关的源码分析,大概从 Android 中的 SystemServer 启动、四大组件启动、AMS、PMS 等几个维度来介绍,下面是我的计划,当然在未来也有可能改变。
介绍
ContentProvider (内容提供者) 属于四大组件之一,可以说它是在四大组件中开发者使用率最少的一个,它的作用就是进程间进行数据交互,底层采用 Binder 机制进行进程间通信。使用方式我这里就不在具体说明了,想要了解使用的可以参考 [Android:关于ContentProvider的知识都在这里了!(https://blog.csdn.net/carson_ho/article/details/76101093) 下面我们就以分析 ContentProvider 工作流程为主来进行全面分析。
源码分析
query 到 AMS 调用过程
下面先来看一个代码示例,代码如下:
```
fun getContactsLists(): MutableList<String> {
var contactsLists: MutableList<String> = mutableListOf<String>()
lateinit var cursor: Cursor
try {
//使用 getContentResolver() 查询联系人列表
cursor = contentResolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null)
//对 cursor 进行遍历
if (cursor != null) {
while (cursor.moveToNext()) {
//获取姓名
val displayName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME))
//电话号码
val number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER))
contactsLists.add("姓名:$displayName 电话:$number")
}
}
cursor.close()
} catch (error: Exception) {
logger.error("error:$error")
}
return contactsLists
}
//测试
val contactsLists = getContactsLists()
contactsLists.forEach { it -> println("通过ContentResolver获取联系人: $contactsLists") }
```
上面代码就是通过内容提供者来获取手机中的通讯录列表,输出为:
I/System.out: 通过ContentResolver获取联系人: [姓名:Xiao 电话:110, 姓名:ming 电话:112, 姓名:华为客服 电话:4008308300]
那么这一流程内部是怎么运行的,这才是我们这篇文章主要分析内容,有没有发现上面代码示例是用 kotlin 代码写的例子。
老规矩,还是先看一下该小节分析流程,这里以时序图为主
通过上面代码示例想要 query 数据先要拿到 contentResolver 对象,通过父类 getContentResolver()方法获得,代码如下:
@Override
public ContentResolver getContentResolver() {
return mBase.getContentResolver();
}
这里的 mBase 是 Context 对象,根据前面几篇文章我们知道,它的实现类就是 ContextImpl 我们直接看它具体实现,代码如下:
//ContextImpl.java
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
这里的 getContentResolver 方法中返回了 ApplicationContentResolver 对象,它是 ContextImpl 的静态内部类,继承自 ContentResolver ,它在 ContextImpl 的构造方法中被创建,这说明当我们调用它的 query、insert、update 方法的时候,就会启动 ContentProvider,这里以上面我们示例 query 来进行分析,我们看它的具体实现,代码如下:
//ContentResolver.java
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
/**
* 1. 拿到 IContentProvider 对象,它是 ContentProvider 的本地代理
*/
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
try {
/**
* 2. 调用 IContentProvider 的 query 函数来进行 query
*/
qCursor = unstableProvider.query(mPackageName, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
//...
return wrapper;
} catch (RemoteException e) {
return null;
} finally {
...
}
}
在注释处通过 acquireUnstableProvider 方法拿到 ContentProvider 的本地代理对象,然后注释 2 调用本地代理对象的 query 方法返回一个 Cursor 对象,我们先来看下注释 1 的 acquireUnstableProvider 方法怎么拿到 ContentProvider 本地代理对象,代码如下:
//ContentResolver.java
public final IContentProvider acquireUnstableProvider(Uri uri) {
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
return null;
}
String auth = uri.getAuthority(