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 中,主要就做了三件事

  1. 假如有能够复用的缓存,就直接运用 -> 调用 acquireExistingProvider [5.2]
  2. 假如没有能够复用的缓存,就新建一个 -> 调用 AMS.getContentProvider [6.1]
  3. 假如是新建的,就调用履行装置逻辑 -> 调用 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 这个函数很长,所以这儿咱们分几个部分进行分析。

  1. 获取缓存的 ContentProviderRecord,并获取 ContentProvider 对应地点的进程
  2. ContentProvider 地点进程存活的情况
  3. 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源码解析(Android12)

  • ContentProvider 的运用首要需求获取 ContentResolver,它完成了 ContentInterface 接口,这个接口里界说一切咱们需求运用到的增修改查的 api。
  • 在 ContentResolver 中,实际上调用的是 IContentProvider 目标,它承继自 IInterface,用于跨进程通讯。
  • getContentResolver.query 实际真正调用的是支撑 binder 通讯的署理目标 IContentProvider
  • 在获取 IContentProvider 的过程中,会触发供给者进程的发动(假如需求的话)
  • ContentProvider 发动支撑在当时进程发动,也支撑新建一个进程发动
  • ContentProvider 发动过程的 OnCreate 办法调用会先于 Application 办法的 OnCreate 办法调用