android源码分析目录
一 概述
ContentProvider 作为 Android 的四大组件之一,是出场最少的一个了,所以今天在咱们介绍 ContentProvider 之前,先来回忆一下 ContentProvider 的运用办法。
二 运用办法
ContentProvider 作为内容供给者,一般涉及到两个进程,ContentProvider 的供给者地点的进程和运用者地点的进程(当然它也能够在一个进程内运用)。
2.1 供给者
作为供给者的一方,咱们需求承继 ContentProvider,并完成它的笼统办法。下面便是 Google 供给的一个简略的 Demo
2.2 FileProvider
[development/samples/ApiDemos/src/com/example/android/apis/content/FileProvider.java]
public class FileProvider extends ContentProvider
implements PipeDataWriter<InputStream> {
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
String sortOrder) {
// content providers that support open and openAssetFile should support queries for all
// android.provider.OpenableColumns.
int displayNameIndex = -1;
int sizeIndex = -1;
// If projection is null, return all columns.
if (projection == null) {
projection = new String[] {
OpenableColumns.DISPLAY_NAME,
OpenableColumns.SIZE};
}
for (int i = 0; i < projection.length; i++) {
if (OpenableColumns.DISPLAY_NAME.equals(projection[i])) {
displayNameIndex = i;
}
if (OpenableColumns.SIZE.equals(projection[i])) {
sizeIndex = i;
}
}
MatrixCursor cursor = new MatrixCursor(projection);
Object[] result = new Object[projection.length];
for (int i = 0; i < result.length; i++) {
if (i == displayNameIndex) {
result[i] = uri.getPath();
}
if (i == sizeIndex) {
result[i] = null; // Size is unknown, so null, if it was known, it would go here.
}
}
cursor.addRow(result);
return cursor;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
// Don't support inserts.
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// Don't support deletes.
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
// Don't support updates.
return 0;
}
@Override
public String getType(Uri uri) {
// For this sample, assume all files are .apks.
return "application/vnd.android.package-archive";
}
...
}
作为内容供给者,需求完成以下五个函数
- onCreate :回来值表示当时内容供给者地点的进程是否加载完成
- query : 回来一个 Cursor 用来查询数据,运用完需求关闭
- insert :增
- delete : 删
- update :改
2.3 AndroidManifest.xml
<provider android:name=".content.FileProvider"
android:authorities="com.example.android.apis.content.FileProvider"
android:grantUriPermissions="true"
android:exported="false"
android:enabled="@bool/atLeastHoneycombMR2" />
在 AndroidManifest 中装备对应的 provider 节点,并装备以下特点
- android:name : 文件途径
- android:authorities :URI ,授权方用于标识 Content Provider 供给的数据
- android:enabled :体系是否能够实例化 Content Provider。假如能够,则设为“true”;假如不能,则设为“false”。默认值为“true”。
接下来,便是运用方的示例。
2.4 运用者
ContentResolver cr = getContentResolver();
Uri uri = Uri.parse("uri ...");
//履行查询
Cursor c = cr.query(uri, null, null, null, null);
运用者的逻辑就相对比较简略了
- 首要是获取 ContentResolver
- 然后经过 Uri.parse 解析对应的 uri
- 最终经过 ContentResolver 和 Uri 进行增修改查
ContentResolver 它是一个笼统类,它完成了 ContentInterface 接口。而 ContentInterface 中,界说了一切的增修改查,即咱们需求运用的相关 api。
接下来,咱们就从运用者开始,看看 ContentResolver 具体的调用流程和原理。
三 Context
首要仍是从 Context 动身,经过 getContentResolver 获取 ContentResolver。调用流程如下
- Context.getContentResolver
- ContextWrapper.getContentResolver
- ContextImpl.getContentResolver
3.1 getContentResolver
[frameworks/base/core/java/android/app/ContextImpl.java]
@Override
public ContentResolver getContentResolver() {
return mContentResolver;
}
和其他的四大组件不同,ContentResolver 在 ContextImpl 中直接就有一个成员目标 mContentResolver。
3.2 ContextImpl
[frameworks/base/core/java/android/app/ContextImpl.java]
@UnsupportedAppUsage
private final ApplicationContentResolver mContentResolver;
这个成员目标的类型是 ApplicationContentResolver。
[frameworks/base/core/java/android/app/ContextImpl.java]
private ContextImpl (...)
mContentResolver = new ApplicationContentResolver(this, mainThread);
}
而且这个目标仍是在结构函数中初始化的。
3.3 ApplicationContentResolver
[frameworks/base/core/java/android/app/ContextImpl.java]
private static final class ApplicationContentResolver extends ContentResolver {
@UnsupportedAppUsage
private final ActivityThread mMainThread;
...
protected IContentProvider acquireProvider(Context context, String auth) {
return mMainThread.acquireProvider(context,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), true);
}
......
}
ApplicationContentResolver 是 ContextImpl 的静态内部类,它承继自 ContentResolver,在 ApplicationContentResolver 中保存了一个 ActivityThread 的目标,外部调用它时,其实都会调用到 ActivityThread。
接下来,咱们看看 ApplicationContentResolver 的增修改查都是怎么完成的。
四 ContentResolver
4.1 query
接下来咱们经过跟踪 query 的调用,来看一下 ContentProvider 的运用者和供给者是怎么交互的。
[frameworks/base/core/java/android/content/ContentResolver.java]
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
Objects.requireNonNull(uri, "uri");
... // 省掉代码
// 经过 uri 获取 ContentProvider 的 BInder 目标
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
long startTime = SystemClock.uptimeMillis();
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
remoteCancellationSignal = unstableProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
qCursor = unstableProvider.query(mContext.getAttributionSource(), uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
// The remote process has died... but we only hold an unstable
// reference though, so we might recover!!! Let's try!!!!
// This is exciting!!1!!1!!!!1
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
qCursor = stableProvider.query(mContext.getAttributionSource(), uri, projection,
queryArgs, remoteCancellationSignal);
}
if (qCursor == null) {
return null;
}
// Force query execution. Might fail and throw a runtime exception here.
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
// Wrap the cursor object into CursorWrapperInner object.
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
// Arbitrary and not worth documenting, as Activity
// Manager will kill this process shortly anyway.
return null;
} finally {
if (qCursor != null) {
qCursor.close();
}
if (cancellationSignal != null) {
cancellationSignal.setRemote(null);
}
if (unstableProvider != null) {
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}
首要,在 query 函数中,首要会 经过 acquireUnstableProvider 拿到一个 IContentProvider 目标。
4.2 IContentProvider
public interface IContentProvider extends IInterface {
这个 IContentProvider 目标是一个笼统类,它完成了 IInterface 接口,这个接口便是用于跨进程通讯的。
public interface IInterface
{
public IBinder asBinder();
}
所以 IContentProvider 这个目标,便是用于跨进程通讯的。
4.3 acquireUnstableProvider
在 query 中,首要就会经过 acquireUnstableProvider 获取到一个 IContentProvider,而这个 acquireUnstableProvider 在之前咱们现已说了,它界说在 ApplicationContentResolver 中,可是实际上调用的却是 ActivityThread 中的函数。
[frameworks/base/core/java/android/app/ActivityThread.java]
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;
}
4.3 ApplicationContentResolver.acquireUnstableProvider
[frameworks/base/core/java/android/app/ContextImpl.java]
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
最终会调用 mMainThread 中的 acquireProvider 函数。
五 ActivityThread
5.1 acquireProvider
[frameworks/base/core/java/android/app/ActivityThread.java]
@UnsupportedAppUsage
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;
}
// 假如不存在,就预备创建一个,可是为了避免多个线程一起获取
// 这儿会有一个锁
ContentProviderHolder holder = null;
final ProviderKey key = getGetProviderKey(auth, userId);
try {
synchronized (key) {
// 经过 AMS 获取 IContentProvider
holder = ActivityManager.getService().getContentProvider(
getApplicationThread(), c.getOpPackageName(), auth, userId, stable);
// 假如 holder 不为空,可是 provider 为空,那么久要等候
// 供给者的进程发布 provider,这儿的超时时刻是 10 秒(不是ANR)
if (holder != null && holder.provider == null && !holder.mLocal) {
synchronized (key.mLock) {
key.mLock.wait(ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS);
holder = key.mHolder;
}
if (holder != null && holder.provider == null) {
// probably timed out
holder = null;
}
}
}
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
} catch (InterruptedException e) {
holder = null;
} finally {
synchronized (key.mLock) {
key.mHolder = null;
}
}
// 假如 holder 也没有,那么就会装置一个 IContentProvider
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
在 acquireProvider 中,主要就做了三件事
- 假如有能够复用的缓存,就直接运用 -> 调用 acquireExistingProvider [5.2]
- 假如没有能够复用的缓存,就新建一个 -> 调用 AMS.getContentProvider [6.1]
- 假如是新建的,就调用履行装置逻辑 -> 调用 installProvider [6.8]
5.2 acquireExistingProvider
acquireExistingProvider 便是从 ActivityThread 的成员变量 mProviderMap 中,取出对应的 IContentProvider。
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()) {
// Binder 地点的进程死亡,就不运用缓存
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
//
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
// 增加引用计数
incProviderRefLocked(prc, stable);
}
return provider;
}
}
缓存的逻辑很简略,便是从 mProviderRefCountMap 中取出。
5.3 小结
到此咱们能够简略小结一下,目前有两个要害点,一个经过 AMS.getContentProvider 获取 IContentProvider,另一个是 ActivityThread 的 installProvider。
六 AMS
首要咱们来看看 AMS 获取 IContentProvider 的逻辑。
6.1 getContentProvider
[frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java]
final ContentProviderHelper mCpHelper;
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String callingPackage, String name, int userId,
boolean stable) {
try {
return mCpHelper.getContentProvider(caller, callingPackage, name, userId, stable);
} finally {
}
}
在 AMS 中,存在一个 ContentProviderHelper 类型的目标 mCpHelper,经过调用 mCpHelper.getContentProvider 获得了 ContentProviderHolder。
6.2 ContentProviderHelper.getContentProvider
ContentProviderHolder getContentProvider(IApplicationThread caller, String callingPackage,
String name, int userId, boolean stable) {
... // 省掉代码
return getContentProviderImpl(caller, name, null, callingUid, callingPackage,
null, stable, userId);
}
6.3 getContentProviderImpl 中的数据结构
getContentProviderImpl 这个函数很长,所以这儿咱们分几个部分进行分析。
- 获取缓存的 ContentProviderRecord,并获取 ContentProvider 对应地点的进程
- ContentProvider 地点进程存活的情况
- ContentProvider 地点进程死亡的情况
为了方便了解,咱们先看一下 ContentProviderRecord 这个目标的界说
6.3.1 ContentProviderRecord
final class ContentProviderRecord implements ComponentName.WithComponentName {
//
static final int MAX_RETRY_COUNT = 3;
// AMS
final ActivityManagerService service;
// 持有者的信息?
public final ProviderInfo info;
final int uid;
// 进程信息
final ApplicationInfo appInfo;
// 包名
final ComponentName name;
final boolean singleton;
// 它的 Binder 目标
public IContentProvider provider;
public boolean noReleaseNeeded;
// 一切衔接的客户端
final ArrayList<ContentProviderConnection> connections
= new ArrayList<ContentProviderConnection>();
//final HashSet<ProcessRecord> clients = new HashSet<ProcessRecord>();
// Handles for non-framework processes supported by this provider
ArrayMap<IBinder, ExternalProcessHandle> externalProcessTokenToHandle;
// Count for external process for which we have no handles.
int externalProcessNoHandleCount;
int mRestartCount; // number of times we tried before bringing up it successfully.
ProcessRecord proc; // if non-null, hosting process.
ProcessRecord launchingApp; // if non-null, waiting for this app to be launched.
String stringName;
String shortStringName;
ContentProviderRecord 是 AMS 用来记载 ContentProvider 的结构,它里边记载了有关 ContentProvider 的相关信息
- ProviderInfo:此 ContentProvider 在 AndroidManifest.xml 中的信息
- ComponentName:ContentProvider 的名称
- singleton:此 ContentProvider 是否是单例
- provider:此 ContentProvider 对应的 Binder 目标
- connections:当时 ContentProvider 一切的衔接信息
- proc:此 proc 地点的进程信息
- launchingApp:等候 ContentProvider 发动的进程
6.3.2 ContentProviderConnection
public final class ContentProviderConnection extends Binder {
public final ContentProviderRecord provider;
// 恳求运用 ContentProvider 的客户端
public final ProcessRecord client;
// 客户端包名
public final String clientPackage;
...
ContentProviderConnection 是 ContentProvider 和对应客户端的衔接目标,它里边保存了恳求 ContentProvider 的客户端信息,和对应的记载 ContentProviderRecord。
6.4 getContentProviderImpl
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, int callingUid, String callingPackage, String callingTag,
boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
boolean providerRunning = false;
final int expectedUserId = userId;
synchronized (mService) {
long startTime = SystemClock.uptimeMillis();
// 先查看调用者地点进程
ProcessRecord r = null;
if (caller != null) {
// 假如调用者地点的进程不存在(异常情况,直接抛出)
r = mService.getRecordForAppLOSP(caller);
if (r == null) {
throw new SecurityException("Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid() + ") when getting content provider "
+ name);
}
}
boolean checkCrossUser = true;
// 查看 ContentProviderRecord 缓存是否存在(内容供给者是否现已发布)
cpr = mProviderMap.getProviderByName(name, userId);
// 假如没发布,而且当时用户不是体系用户
if (cpr == null && userId != UserHandle.USER_SYSTEM) {
// 那么就从体系用户中获取
cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
if (cpr != null) {
cpi = cpr.info;
if (mService.isSingleton(
cpi.processName, cpi.applicationInfo, cpi.name, cpi.flags)
&& mService.isValidSingletonCall(
r == null ? callingUid : r.uid, cpi.applicationInfo.uid)) {
userId = UserHandle.USER_SYSTEM;
checkCrossUser = false;
} else {
cpr = null;
cpi = null;
}
}
}
ProcessRecord dyingProc = null;
if (cpr != null && cpr.proc != null) {
// ContentProvider 地点的进程是否存活,保存到 providerRunning 中
providerRunning = !cpr.proc.isKilled();
// 假如 ContentProviderRecord 地点的进程现已被杀了,
// 可是 appDiedLocked 还没用被调用,那么就保存到 dyingProc
// 后续需求对 dyingProc 做清理工作
if (cpr.proc.isKilled() && cpr.proc.isKilledByAm()) {
dyingProc = cpr.proc;
}
}
// 假如 ContentProviderRecord 的进程在运转
if (providerRunning) {
...
}
// 假如 ContentProvider 进程没用运转
if (!providerRunning) {
...
}
// 由于需求等候供给者发布,所以这儿有一个死循环
synchronized (cpr) {
while (cpr.provider == null) {
...
}
}
}
第一部分的逻辑比较简略,便是先判断有没有缓存的 ContentProvider。
- 假如有,就看这个 ContentProvider 的进程是否存活,假如是则 providerRunning 为 true,否则为 false。
- 假如没有,providerRunning 就为 false
接下来,就会根据 providerRuning 的值为 true 或许 false 履行不同的逻辑。
6.5 进程存活
// 假如 ContentProviderRecord 的进程在运转
if (providerRunning) {
cpi = cpr.info;
// 假如调用者进程已发动
// 而且 ContentProviderRecord 能够在调用者进程中运转
// 假如 multiprocess 的设置为 true,那么这儿 canRunHere 就为 true
// 那么就会【直接回来】ContentProviderHolder
if (r != null && cpr.canRunHere(r)) {
checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
cpr.name.flattenToShortString(), startTime);
ContentProviderHolder holder = cpr.newHolder(null, true);
// 【直接回来】不要给调用者供给目标
holder.provider = null;
return holder;
}
// 免装置运用不供给 ContentProvider
try {
if (AppGlobals.getPackageManager()
.resolveContentProvider(name, /*flags=*/ 0, userId) == null) {
return null;
}
} catch (RemoteException e) {
}
checkAssociationAndPermissionLocked(r, cpi, callingUid, userId, checkCrossUser,
cpr.name.flattenToShortString(), startTime);
final long origId = Binder.clearCallingIdentity();
try {
checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
// Return the provider instance right away since it already exists.
conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage,
callingTag, stable, true, startTime, mService.mProcessList,
expectedUserId);
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
final int verifiedAdj = cpr.proc.mState.getVerifiedAdj();
boolean success = mService.updateOomAdjLocked(cpr.proc,
OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
// XXX things have changed so updateOomAdjLocked doesn't actually tell us
// if the process has been successfully adjusted. So to reduce races with
// it, we will check whether the process still exists. Note that this doesn't
// completely get rid of races with LMK killing the process, but should make
// them much smaller.
if (success && verifiedAdj != cpr.proc.mState.getSetAdj()
&& !isProcessAliveLocked(cpr.proc)) {
success = false;
}
maybeUpdateProviderUsageStatsLocked(r, cpr.info.packageName, name);
checkTime(startTime, "getContentProviderImpl: after updateOomAdj");
if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
Slog.i(TAG, "Adjust success: " + success);
}
// NOTE: there is still a race here where a signal could be
// pending on the process even though we managed to update its
// adj level. Not sure what to do about this, but at least
// the race is now smaller.
if (!success) {
// Uh oh... it looks like the provider's process
// has been killed on us. We need to wait for a new
// process to be started, and make sure its death
// doesn't kill our process.
Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable,
false, false);
if (!lastRef) {
// This wasn't the last ref our process had on
// the provider... we will be killed during cleaning up, bail.
return null;
}
// We'll just start a new process to host the content provider
providerRunning = false;
conn = null;
dyingProc = cpr.proc;
} else {
cpr.proc.mState.setVerifiedAdj(cpr.proc.mState.getSetAdj());
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
假如 ContentProvider 地点的进程存活,那么履行 providerRunning 为 true 的逻辑。
- 注意,假如调用者的进程不为空,而且 ContentProvider 能够运转在调用者地点的进程中(即 AndroidManifest.xml 中的 multiprocess 为 true)。那么就会直接经过 ContentProviderRecord 创建出一个 ContentProviderHolder 目标,而且这个 holder 目标里的 provider 为空。直接回来此 holder。
- 这儿 provider 为空是为了在调用者的进程中创建出对应的 ContentProvider,而不是供给者地点的进程。由于假如你在一个 App 中运用支付宝的付款功用,成果付款成功之后,进入了支付宝运用的界面,而不是你地点运用 App 的付款成果页,必然会导致你运用上的误解,所以这儿需求在运用者进程中创建 ContentProvider,而不是供给者进程。
6.6 进程死亡
// 假如 ContentProvider 进程没用运转
if (!providerRunning) {
... // 省掉代码
// 获取 ContentProvider 的进程,假如存在就直接运用
ProcessRecord proc = mService.getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid);
IApplicationThread thread;
if (proc != null && (thread = proc.getThread()) != null
&& !proc.isKilled()) {
if (ActivityManagerDebugConfig.DEBUG_PROVIDER) {
Slog.d(TAG, "Installing in existing process " + proc);
}
final ProcessProviderRecord pr = proc.mProviders;
if (!pr.hasProvider(cpi.name)) {
checkTime(startTime, "getContentProviderImpl: scheduling install");
pr.installProvider(cpi.name, cpr);
try {
thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
// 假如不存在,就走发动进程的逻辑
proc = mService.startProcessLocked(
cpi.processName, cpr.appInfo, false, 0,
new HostingRecord("content provider",
new ComponentName(
cpi.applicationInfo.packageName, cpi.name)),
Process.ZYGOTE_POLICY_FLAG_EMPTY, false, false);
if (proc == null) {
// 假如发动失利,就回来空
return null;
}
}
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
... // 省掉代码
}
假如 ContextProvider 的进程没有运转,那么就会走发动进程的逻辑。
6.7 等候发布
final long timeout =
SystemClock.uptimeMillis() + ContentResolver.CONTENT_PROVIDER_READY_TIMEOUT_MILLIS;
boolean timedOut = false;
synchronized (cpr) {
// 这儿是个死循环
while (cpr.provider == null) {
// 处理异常情况,假如发动的进程失利就直接回来
if (cpr.launchingApp == null) {
return null;
}
try {
final long wait = Math.max(0L, timeout - SystemClock.uptimeMillis());
if (conn != null) {
conn.waiting = true;
}
// 调用 ContentProviderRecord 的 wait 进入等候
cpr.wait(wait);
if (cpr.provider == null) {
timedOut = true;
break;
}
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
if (timedOut) {
// 假如超时,就回来为 null
String callerName = "unknown";
if (caller != null) {
synchronized (mService.mProcLock) {
final ProcessRecord record =
mService.mProcessList.getLRURecordForAppLOSP(caller);
if (record != null) {
callerName = record.processName;
}
}
}
return null;
}
// 正常回来,经过 ContentProviderConnection 创建一个 Holder 目标
return cpr.newHolder(conn, false);
最终,假如 ContentProviderRecord 里的 provider 为空,即没有发布,就会在一个死循环里等候发布。发布流程能够看 [7.3]。
咱们再回到 [5.1],在经历了 AMS 的 getContentProvider 之后,会调用 installProvider 函数。
6.8 installProvider
[frameworks/base/core/java/android/app/ActivityThread.java]
@UnsupportedAppUsage
private ContentProviderHolder installProvider(Context context,
ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
// localProvider 是一个 ContentProvider 目标,
// 而不是 IContentProvider 这个 Binder 目标
// 说明运用 localProvider 时是同一个进程间通讯
ContentProvider localProvider = null;
IContentProvider provider;
... // 省掉代码
if (holder == null || holder.provider == null) {
// 假如 holder 为空或许 holder.provider 为空,
// 就走同进程通讯
try {
final java.lang.ClassLoader cl = c.getClassLoader();
LoadedApk packageInfo = peekPackageInfo(ai.packageName, true);
if (packageInfo == null) {
// System startup case.
packageInfo = getSystemContext().mPackageInfo;
}
localProvider = packageInfo.getAppFactory()
.instantiateProvider(cl, info.name);
provider = localProvider.getIContentProvider();
if (provider == null) {
return null;
}
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
if (!mInstrumentation.onException(null, e)) {
throw new RuntimeException(
"Unable to get provider " + info.name
+ ": " + e.toString(), e);
}
return null;
}
} else {
// 否则,就从 ContentProviderHolder 中取出 IContentProvider
provider = holder.provider;
}
ContentProviderHolder retHolder;
synchronized (mProviderMap) {
IBinder jBinder = provider.asBinder();
// localProvider 是否为空,即当时的 ContextProvider 和调用者是否是同一个进程
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 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 {
// 跨进程通讯,增加引用计数,
// 而且将 Binder 目标缓存到 mProviderRefCountMap 中
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
try {
ActivityManager.getService().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}
installProvider 函数,看它名字久知道它的目的是装置 ContextProvider。在这个函数中,会根据调用者来源的不同来区别处理。
- 假如调用者和 ContextProvider 的供给者是同一个进程,那么就直接回来。
- 假如调用者和 ContextProvider 的供给者是不同进程,那么就需求增加计数器
七 ActivityThread
说完了 ContextProvider 的获取,再来说说 ContextProvider 的发布。之前在 [6.7] 咱们看到了 ContextProvider 发布了就能够直接获取,而 ContextProvider 没有发布的时分,会有一个死循环。
7.1 handleBindApplication
接下来,咱们就来看看 ContextProvider 是怎么发布的。首要是进程的发动流程,在运用发动完毕后,会调用 handleBindApplication 创建 Application 并绑定上下午。
private void handleBindApplication(AppBindData data) {
if (!data.restrictedBackupMode) {
// 假如 App 的 providers 不为空,就先装置 providers
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.providers);
}
}
// 调用 Application 的 OnCreate 函数
try {
mInstrumentation.callApplicationOnCreate(app);
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
}
在 handleBindApplication 中,咱们竟然发现 ContentProvider 的发布竟然是在调用 Application 的 OnCreate 函数之前。所以之前有一些运用或许三方库会在 ContentProvider 进行初始化。
当然,现在建议不要这样做,由于 ContentProvider 从发布和创建也是需求消耗性能的,谷歌现在在 Jetpack 中现已供给了用于初始化的 App Startup。不要再用 ContentProvider 初始化了。
7.2 installContentProviders
@UnsupportedAppUsage
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<ContentProviderHolder> results = new ArrayList<>();
for (ProviderInfo cpi : providers) {
// 线调用 installProvider 装置 ContentProvider
ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
// 然后再调用 AMS 的 publishContentProviders
ActivityManager.getService().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
在 ActivityThread 的 installContentProviders 中,会先调用 installProvider 装置 ContentProvider。然后再调用 AMS 的 来发布 publishContentProviders。
装置的逻辑在 [6.8] 中现已说了,咱们接下来看看发布的逻辑。
7.3 ContentProviderHelper.publishContentProviders
AMS 的发布逻辑,其实也是调用它的 mCpHelper 目标的 publishContentProviders 函数,和之前的 [6.1] 相同。
void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}
synchronized (mService) {
final ProcessRecord r = mService.getRecordForAppLOSP(caller);
if (r == null) {
throw new SecurityException("Unable to find app for caller " + caller
+ " (pid=" + Binder.getCallingPid()
+ ") when publishing content providers");
}
final long origId = Binder.clearCallingIdentity();
boolean providersPublished = false;
for (int i = 0, size = providers.size(); i < size; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
ContentProviderRecord dst = r.mProviders.getProvider(src.info.name);
if (dst == null) {
continue;
}
providersPublished = true;
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);
}
boolean wasInLaunchingProviders = false;
for (int j = 0, numLaunching = mLaunchingProviders.size(); j < numLaunching; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
numLaunching--;
}
}
// 移除超时音讯
if (wasInLaunchingProviders) {
mService.mHandler.removeMessages(
ActivityManagerService.WAIT_FOR_CONTENT_PROVIDER_TIMEOUT_MSG, dst);
mService.mHandler.removeMessages(
ActivityManagerService.CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
r.addPackage(dst.info.applicationInfo.packageName,
dst.info.applicationInfo.longVersionCode, mService.mProcessStats);
synchronized (dst) {
// 注意,这儿给 ContentProviderRecord 的 provider 赋值
// 还记得 [6.7] 里的死循环吗
dst.provider = src.provider;
dst.setProcess(r);
// dst 是一个 ContentProviderRecord 目标,这儿调用 notifyAll 告诉之前 cpr.wait 的目标。
dst.notifyAll();
dst.onProviderPublishStatusLocked(true);
}
dst.mRestartCount = 0;
}
// update the app's oom adj value and each provider's usage stats
if (providersPublished) {
mService.updateOomAdjLocked(r, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
for (int i = 0, size = providers.size(); i < size; i++) {
ContentProviderHolder src = providers.get(i);
if (src == null || src.info == null || src.provider == null) {
continue;
}
maybeUpdateProviderUsageStatsLocked(r,
src.info.packageName, src.info.authority);
}
}
Binder.restoreCallingIdentity(origId);
}
}
总结
最终仍是来做一个简略的总结,先用一幅图来展示整个流程
- ContentProvider 的运用首要需求获取 ContentResolver,它完成了 ContentInterface 接口,这个接口里界说一切咱们需求运用到的增修改查的 api。
- 在 ContentResolver 中,实际上调用的是 IContentProvider 目标,它承继自 IInterface,用于跨进程通讯。
- getContentResolver.query 实际真正调用的是支撑 binder 通讯的署理目标 IContentProvider
- 在获取 IContentProvider 的过程中,会触发供给者进程的发动(假如需求的话)
- ContentProvider 发动支撑在当时进程发动,也支撑新建一个进程发动
- ContentProvider 发动过程的 OnCreate 办法调用会先于 Application 办法的 OnCreate 办法调用