本文基于Android 7.0,涉及的主要源碼:
aosp/frameworks/base/core/java/android/app/ContextImpl.java
aosp/frameworks/base/core/java/android/app/ActivityThread.java
aosp/frameworks/base/core/java/android/app/ActivityManagerNative.java
aosp/frameworks/base/core/java/android/app/ApplicationThreadNative.javaaosp/frameworks/base/core/java/android/content/ContentResolver.java
aosp/frameworks/base/core/java/android/content/ContentProvider.java
aosp/frameworks/base/core/java/android/content/ContentProviderNative.javaaosp/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
aosp/frameworks/base/core/java/android/database/AbstractCursor.java
aosp/frameworks/base/core/java/android/database/MatrixCursor.java
aosp/frameworks/base/core/java/android/database/CursorWindow.java
aosp/frameworks/base/core/java/android/database/BulkCursorNative.java
aosp/frameworks/base/core/java/android/database/CursorToBulkCursorAdaptor.java
aosp/frameworks/base/core/java/android/database/BulkCursorDescriptor.java
aosp/frameworks/base/core/java/android/database/BulkCursorToCursorAdaptor.java
aosp/frameworks/base/core/java/android/database/DatabaseUtils.java
aosp/frameworks/base/core/jni/android_database_CursorWindow.cpp
aosp/frameworks/base/libs/androidfw/CursorWindow.cpp
類圖

- ContentResolver
- 應(yīng)用使用該類訪問ContentProvider
- ContentProviderProxy
- ContentProvider代理對象
- ContentProviderNative
- ContentProvider本地對象
- Transport
- 實現(xiàn)了ContentProviderNative
- ContentProvider
- 用于應(yīng)用間共享數(shù)據(jù)
通過ContentResolver獲取ContentProviderProxy對象

下面從ContextImpl的getContentResolver()開始分析
public ContentResolver getContentResolver() {
return mContentResolver;
}
這里mContentResolver是一個ApplicationContentResolver類型的引用,它是在ContextImpl構(gòu)造函數(shù)中創(chuàng)建的,下面看ApplicationContentResolver的query()。
public final @Nullable Cursor query(@RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNullUri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
// 獲取unstableProvider代理,unstableProvider為ContentProviderProxy對象
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 {
// 通過Binder IPC向ContentProvider查詢信息
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
......
}
......
}
......
}
protected IContentProvider acquireUnstableProvider(Context c, String auth){
// 調(diào)用ActivityThread的acquireProvider
// ContentProvider.getAuthorityWithoutUserId(auth)通常返回auth
// resolveUserIdFromAuthority(auth)通常返回0
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
- unstableProvider
- 當(dāng)ContentProvider宿主進程死亡時,系統(tǒng)會通知ContentProvider客戶端進程
- stableProvider
- 當(dāng)ContentProvider宿主進程死亡時
- ContentProviderConnection存在時,系統(tǒng)會殺死非persistent的ContentProvider客戶端進程
- ContentProviderConnection移除時,系統(tǒng)不會殺ContentProvider客戶端進程
下面看ActivityThread的acquireProvider()的實現(xiàn)
- 當(dāng)ContentProvider宿主進程死亡時
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
// 查詢緩存的Provider代理
final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
if (provider != null) {
return provider;
}
// There is a possible race here. Another thread may try to acquire
// the same provider at the same time. When this happens, we want to ensure
// that the first one wins.
// Note that we cannot hold the lock while acquiring and installing the
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
IActivityManager.ContentProviderHolder holder = null;
try {
// 非system_server進程ActivityManagerNative.getDefault()返回ActivityManagerProxy對象
// 向ActivityManagerService查詢ContentProvider
// getApplicationThread()返回ApplicationThread對象
// userId為auth所屬用戶userId,通常為0
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
// Install provider will increment the reference count for us, and break
// any ties in the race.
// 系統(tǒng)進程(uid == 0 || uid == SYSTEM_UID)中holder.noReleaseNeeded為true
// 普通客戶端進程holder.noReleaseNeeded為false
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
下面首先看acquireExistingProvider()的實現(xiàn)
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;
// jBinder為BinderProxy或者Binder對象
IBinder jBinder = provider.asBinder();
// 查詢ContentProvider宿主進程是否活著
if (!jBinder.isBinderAlive()) {
// The hosting process of the provider has died; we can't
// use this one.
Log.i(TAG, "Acquiring provider " + auth + " for user " + userId
+ ": existing object's process dead");
// 處理ContentProvider宿主進程死亡的情況
handleUnstableProviderDiedLocked(jBinder, true);
return null;
}
// Only increment the ref count if we have one. If we don't then the
// provider is not reference counted and never needs to be released.
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
// 非ContentProvider宿主進程,增加ContentProvider引用計數(shù)
incProviderRefLocked(prc, stable);
}
return provider;
}
}
- ProviderKey
- 保存authorith以及userId
- ProviderClientRecord
- 保存Provider信息(在ContentProvider宿主進程及客戶端均使用)
這里假定acquireExistingProvider()返回null,下面看getContentProvider()的實現(xiàn)
// caller為ApplicationThread對象繼承自ApplicationThreadNative
// name為authority, 這里stable為false
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);
// 向ActivityManagerService查詢ContentProvider,這里等待reply
mRemote.transact(GET_CONTENT_PROVIDER_TRANSACTION, data, reply, 0);
reply.readException();
int res = reply.readInt();
ContentProviderHolder cph = null;
if (res != 0) {
// 創(chuàng)建ContentProviderHolder
cph = ContentProviderHolder.CREATOR.createFromParcel(reply);
}
data.recycle();
reply.recycle();
return cph;
}
getContentProvider()是個Binder IPC,下面直接看ActivityManagerService處理請求
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();
// app為ApplicationThreadProxy對象
IApplicationThread app = ApplicationThreadNative.asInterface(b);
// name為authorith字符串
String name = data.readString();
// userId為ContentProvider所屬用戶id,通常為0
int userId = data.readInt();
// stable這里為false
boolean stable = data.readInt() != 0;
ContentProviderHolder cph = getContentProvider(app, name, userId, stable);
reply.writeNoException();
if (cph != null) {
reply.writeInt(1);
cph.writeToParcel(reply, 0);
} else {
reply.writeInt(0);
}
return true;
}
......
}
......
}
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
// Isolated進程不允許獲取ContentProvider
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
// The incoming user check is now handled in checkContentProviderPermissionLocked() to deal
// with cross-user grant.
return getContentProviderImpl(caller, name, null, stable, userId);
}
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
// token為null
ContentProviderRecord cpr;
// 代表ContentProvider與客戶端之間的連接
ContentProviderConnection conn = null;
// 持有特定ContentProvider信息
ProviderInfo cpi = null;
synchronized(this) {
long startTime = SystemClock.uptimeMillis();
ProcessRecord r = null;
if (caller != null) {
// 根據(jù)ApplicationThreadProxy查找ProcessRecord
r = getRecordForAppLocked(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;
checkTime(startTime, "getContentProviderImpl: getProviderByName");
// First check if this content provider has been published...
// 檢查目標(biāo)ContentProvider是否已經(jīng)發(fā)布,cpr不為null也并不意味著ContentProvider已經(jīng)發(fā)布
cpr = mProviderMap.getProviderByName(name, userId);
......
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
if (providerRunning) {
// ContentProvider已經(jīng)發(fā)布
cpi = cpr.info;
String msg;
......
if (r != null && cpr.canRunHere(r)) {
// ContentProvider能夠運行在調(diào)用者進程,例如:
// 1) 多進程ContentProvider同時調(diào)用者與ContentProvider宿主進程uid相同
// This provider has been published or is in the process
// of being published... but it is also allowed to run
// in the caller's process, so don't make a connection
// and just let the caller instantiate its own instance.
ContentProviderHolder holder = cpr.newHolder(null);
// don't give caller the provider object, it needs
// to make its own.
// holder.provider為null,調(diào)用者自己實例化ContentProvider
holder.provider = null;
return holder;
}
final long origId = Binder.clearCallingIdentity();
checkTime(startTime, "getContentProviderImpl: incProviderCountLocked");
// In this case the provider instance already exists, so we can
// return it right away.
// 增加ContentProvider引用計數(shù)
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
// If this is a perceptible app accessing the provider,
// make sure to count it as being accessed and thus
// back up on the LRU list. This is good because
// content providers are often expensive to start.
checkTime(startTime, "getContentProviderImpl: before updateLruProcess");
// ContentProvider客戶端為percetible app,調(diào)整
// ContentProvider宿主進程及關(guān)聯(lián)進程在LRU鏈表中的位置
updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
}
}
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
final int verifiedAdj = cpr.proc.verifiedAdj;
// 更新ContentProvider宿主進程狀態(tài)及oomadj值
boolean success = updateOomAdjLocked(cpr.proc);
......
if (!success) {
// ContentProvider宿主進程死亡
// 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.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
// 減少引用計數(shù),如果計數(shù)為0,斷開連接避免客戶進程被殺
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
checkTime(startTime, "getContentProviderImpl: before appDied");
appDiedLocked(cpr.proc);
checkTime(startTime, "getContentProviderImpl: after appDied");
if (!lastRef) {
// This wasn't the last ref our process had on
// the provider... we have now been killed, bail.
return null;
}
providerRunning = false;
conn = null;
} else {
cpr.proc.verifiedAdj = cpr.proc.setAdj;
}
Binder.restoreCallingIdentity(origId);
}
if (!providerRunning) {
// ContentProvider沒有運行
try {
checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
// 向PackageManagerService查詢ProviderInfo
cpi = AppGlobals.getPackageManager().
resolveContentProvider(name,
STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId);
checkTime(startTime, "getContentProviderImpl: after resolveContentProvider");
} catch (RemoteException ex) {
}
if (cpi == null) {
return null;
}
// If the provider is a singleton AND
// (it's a call within the same user || the provider is a
// privileged app)
// Then allow connecting to the singleton provider
// 檢查ContentProvider是否為單例(多用戶共享)
boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
cpi.name, cpi.flags)
&& isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
if (singleton) {
userId = UserHandle.USER_SYSTEM;
}
cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
checkTime(startTime, "getContentProviderImpl: got app info for user");
String msg;
checkTime(startTime, "getContentProviderImpl: before checkContentProviderPermission");
// 檢查客戶端是否有權(quán)限訪問ContentProvider
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
// system準(zhǔn)備好之前不能運行非system進程ContentProvider
if (!mProcessesReady
&& !cpi.processName.equals("system")) {
// If this content provider does not run in the system
// process, and the system is not yet ready to run other
// processes, then fail fast instead of hanging.
throw new IllegalArgumentException(
"Attempt to launch content provider before system ready");
}
// Make sure that the user who owns this provider is running. If not,
// we don't want to allow it to run.
if (!mUserController.isUserRunningLocked(userId, 0)) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": user " + userId + " is stopped");
return null;
}
ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
// 根據(jù)組件名及userId獲取ContentProviderRecord
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
final boolean firstClass = cpr == null;
if (firstClass) {
// 需要創(chuàng)建ContentProviderRecord
final long ident = Binder.clearCallingIdentity();
// If permissions need a review before any of the app components can run,
// we return no provider and launch a review activity if the calling app
// is in the foreground.
if (Build.PERMISSIONS_REVIEW_REQUIRED) {
if (!requestTargetProviderPermissionsReviewIfNeededLocked(cpi, r, userId)) {
return null;
}
}
try {
checkTime(startTime, "getContentProviderImpl: before getApplicationInfo");
// 從PackageManagerService獲取ApplicationInfo
ApplicationInfo ai =
AppGlobals.getPackageManager().
getApplicationInfo(
cpi.applicationInfo.packageName,
STOCK_PM_FLAGS, userId);
checkTime(startTime, "getContentProviderImpl: after getApplicationInfo");
if (ai == null) {
Slog.w(TAG, "No package info for content provider "
+ cpi.name);
return null;
}
ai = getAppInfoForUser(ai, userId);
// 創(chuàng)建ContentProviderRecord
cpr = new ContentProviderRecord(this, cpi, ai, comp, singleton);
} catch (RemoteException ex) {
// pm is in same process, this will never happen.
} finally {
Binder.restoreCallingIdentity(ident);
}
}
checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
if (r != null && cpr.canRunHere(r)) {
// ContentProvider能夠運行在調(diào)用者進程,例如:
// 1) 調(diào)用者是ContentProvider宿主自身
// 2) 多進程ContentProvider同時調(diào)用者與ContentProvider宿主進程uid相同
// 這里無需設(shè)置holder.provider為null,ContentProviderRecord創(chuàng)建后成員provider默認(rèn)為null
return cpr.newHolder(null);
}
if (DEBUG_PROVIDER) Slog.w(TAG_PROVIDER, "LAUNCHING REMOTE PROVIDER (myuid "
+ (r != null ? r.uid : null) + " pruid " + cpr.appInfo.uid + "): "
+ cpr.info.name + " callers=" + Debug.getCallers(6));
// This is single process, and our app is now connecting to it.
// See if we are already in the process of launching this
// provider.
final int N = mLaunchingProviders.size();
int i;
for (i = 0; i < N; i++) {
if (mLaunchingProviders.get(i) == cpr) {
break;
}
}
// If the provider is not already being launched, then get it
// started.
if (i >= N) {
final long origId = Binder.clearCallingIdentity();
try {
// Content provider is now in use, its package can't be stopped.
try {
checkTime(startTime, "getContentProviderImpl: before set stopped state");
// 設(shè)置ContentProvider包的狀態(tài)
AppGlobals.getPackageManager().setPackageStoppedState(
cpr.appInfo.packageName, false, userId);
checkTime(startTime, "getContentProviderImpl: after set stopped state");
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ cpr.appInfo.packageName + ": " + e);
}
// Use existing process if already started
checkTime(startTime, "getContentProviderImpl: looking for process record");
// 獲取ContentProvider宿主進程
ProcessRecord proc = getProcessRecordLocked(
cpi.processName, cpr.appInfo.uid, false);
if (proc != null && proc.thread != null && !proc.killed) {
// ContentProvider宿主進程已經(jīng)運行
if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
"Installing in existing process " + proc);
if (!proc.pubProviders.containsKey(cpi.name)) {
// ContentProvider沒有發(fā)布
checkTime(startTime, "getContentProviderImpl: scheduling install");
// ContentProviderRecord放入pubProviders
proc.pubProviders.put(cpi.name, cpr);
try {
// 通過Binder IPC請求宿主進程安裝發(fā)布ContentProvider
proc.thread.scheduleInstallProvider(cpi);
} catch (RemoteException e) {
}
}
} else {
// ContentProvider宿主進程還沒有運行
checkTime(startTime, "getContentProviderImpl: before start process");
// 啟動宿主進程
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
checkTime(startTime, "getContentProviderImpl: after start process");
if (proc == null) {
Slog.w(TAG, "Unable to launch app "
+ cpi.applicationInfo.packageName + "/"
+ cpi.applicationInfo.uid + " for provider "
+ name + ": process is bad");
return null;
}
}
// 記錄正在啟動ContentProvider的宿主進程
cpr.launchingApp = proc;
// mLaunchingProviders記錄正在啟動的ContentProvider,ContentProvider發(fā)布后從該列表中刪除相應(yīng)ContentProviderRecord
mLaunchingProviders.add(cpr);
} finally {
Binder.restoreCallingIdentity(origId);
}
}
checkTime(startTime, "getContentProviderImpl: updating data structures");
// Make sure the provider is published (the same provider class
// may be published under multiple names).
// ContentProviderRecord添加到mProviderMap
if (firstClass) {
mProviderMap.putProviderByClass(comp, cpr);
}
// 不同的name可能映射到向相同的cpr
mProviderMap.putProviderByName(name, cpr);
// 增加引用計數(shù),返回ContentProviderConnection
conn = incProviderCountLocked(r, cpr, token, stable);
if (conn != null) {
conn.waiting = true;
}
}
checkTime(startTime, "getContentProviderImpl: done!");
}
// Wait for the provider to be published...
synchronized (cpr) {
while (cpr.provider == null) {
......
try {
if (DEBUG_MU) Slog.v(TAG_MU,
"Waiting to start provider " + cpr
+ " launchingApp=" + cpr.launchingApp);
if (conn != null) {
conn.waiting = true;
}
// 等待ContentProvider宿主進程發(fā)布
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
return cpr != null ? cpr.newHolder(conn) : null;
}
public void scheduleInstallProvider(ProviderInfo provider) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
provider.writeToParcel(data, 0);
// FLAG_ONEWAY表示收到Binder驅(qū)動發(fā)送的Binder傳輸完成協(xié)議后立即返回
mRemote.transact(SCHEDULE_INSTALL_PROVIDER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
假定ContentProvider宿主進程已經(jīng)啟動,ContentProvider尚未安裝發(fā)布。下面看ContentProvider宿主進程安裝發(fā)布ContentProvider的過程,從scheduleInstallProvider()開始分析。
public void scheduleInstallProvider(ProviderInfo provider) {
// 請求UI線程安裝ContentProvider
sendMessage(H.INSTALL_PROVIDER, provider);
}
public void handleInstallProvider(ProviderInfo info) {
final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites();
try {
// mInitialApplication為應(yīng)用Application對象
installContentProviders(mInitialApplication, Lists.newArrayList(info));
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
}
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
......
// 安裝ContentProvider
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
// 發(fā)布ContentProvider
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
下面看安裝ContentProvider的過程。由于ContentProvider宿主進程及客戶端進程都需要調(diào)用installProvider(),這里只關(guān)注ContentProvider宿主進程的執(zhí)行過程。
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) {
// 需要實例化ContentProvider
......
Context c = null;
ApplicationInfo ai = info.applicationInfo;
if (context.getPackageName().equals(ai.packageName)) {
c = context;
} else if (mInitialApplication != null &&
mInitialApplication.getPackageName().equals(ai.packageName)) {
c = mInitialApplication;
} else {
try {
c = context.createPackageContext(ai.packageName,
Context.CONTEXT_INCLUDE_CODE);
} catch (PackageManager.NameNotFoundException e) {
// Ignore
}
}
......
try {
final java.lang.ClassLoader cl = c.getClassLoader();
// 創(chuàng)建ContentProvider
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
// provider為Transport對象
provider = localProvider.getIContentProvider();
if (provider == null) {
Slog.e(TAG, "Failed to instantiate class " +
info.name + " from sourceDir " +
info.applicationInfo.sourceDir);
return null;
}
if (DEBUG_PROVIDER) Slog.v(
TAG, "Instantiating local provider " + info.name);
// XXX Need to create the correct context for this provider.
// 設(shè)置Provider信息(權(quán)限等),調(diào)用onCreate方法
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 {
......
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
+ " / " + info.name);
// jBinder是Binder對象
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
// 根據(jù)組件名查詢ProviderClientRecord
ComponentName cname = new ComponentName(info.packageName, info.name);
ProviderClientRecord pr = mLocalProvidersByName.get(cname);
if (pr != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, "
+ "using existing local provider");
}
provider = pr.mProvider;
} else {
holder = new IActivityManager.ContentProviderHolder(info);
// provider為Transport對象
holder.provider = provider;
holder.noReleaseNeeded = true;
// 為ContentProvider創(chuàng)建ProviderClientRecord
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
// 添加到mLocalProviders及mLocalProvidersByName
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
......
}
}
return retHolder;
}
下面看ContentProvider的發(fā)布過程。
public void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(caller != null ? caller.asBinder() : null);
data.writeTypedList(providers);
// 非FLAG_ONEWAY, 等待回復(fù)
mRemote.transact(PUBLISH_CONTENT_PROVIDERS_TRANSACTION, data, reply, 0);
reply.readException();
data.recycle();
reply.recycle();
}
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
if (providers == null) {
return;
}
enforceNotIsolatedCaller("publishContentProviders");
synchronized (this) {
// caller通常為ApplicationThreadProxy對象
// 查找ContentProvider宿主進程
final ProcessRecord r = getRecordForAppLocked(caller);
if (DEBUG_MU) Slog.v(TAG_MU, "ProcessRecord uid = " + r.uid);
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();
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;
}
// 從pubProviders中查到ContentProviderRecord
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (DEBUG_MU) Slog.v(TAG_MU, "ContentProviderRecord uid = " + dst.uid);
if (dst != null) {
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
// ContentProviderRecord添加到mProviderMap
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
// 多個authority對應(yīng)同一個ContentProviderRecord
mProviderMap.putProviderByName(names[j], dst);
}
// ContentProvider發(fā)布,從mLaunchingProviders移除
int launchingCount = mLaunchingProviders.size();
int j;
boolean wasInLaunchingProviders = false;
for (j = 0; j < launchingCount; j++) {
if (mLaunchingProviders.get(j) == dst) {
mLaunchingProviders.remove(j);
wasInLaunchingProviders = true;
j--;
launchingCount--;
}
}
if (wasInLaunchingProviders) {
// 移除ContentProvider超時消息
mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
}
synchronized (dst) {
// provider通常為ContentProviderProxy對象
// 喚醒ContentProvider發(fā)布的等待著
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}
......
}
}
Binder.restoreCallingIdentity(origId);
}
}
ContentProvider的發(fā)布等待者(通常是system_server的Binder線程)被喚醒后,將發(fā)送ContentProviderHolder對象給ContentProvider客戶端。
private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
......
synchronized (cpr) {
while (cpr.provider == null) {
......
try {
if (DEBUG_MU) Slog.v(TAG_MU,
"Waiting to start provider " + cpr
+ " launchingApp=" + cpr.launchingApp);
if (conn != null) {
conn.waiting = true;
}
// 從此被喚醒,此時cpr.provider不為null
cpr.wait();
} catch (InterruptedException ex) {
} finally {
if (conn != null) {
conn.waiting = false;
}
}
}
}
// 返回ContentProviderHolder對象
return cpr != null ? cpr.newHolder(conn) : null;
}
下面看ContentProvider客戶端收到回復(fù)后安裝ContentProvider的過程。
public final IContentProvider acquireProvider(
Context c, String auth, int userId, boolean stable) {
......
// There is a possible race here. Another thread may try to acquire
// the same provider at the same time. When this happens, we want to ensure
// that the first one wins.
// Note that we cannot hold the lock while acquiring and installing the
// provider since it might take a long time to run and it could also potentially
// be re-entrant in the case where the provider is in the same process.
IActivityManager.ContentProviderHolder holder = null;
try {
// 返回ContentProviderHolder
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
if (holder == null) {
Slog.e(TAG, "Failed to find provider info for " + auth);
return null;
}
// Install provider will increment the reference count for us, and break
// any ties in the race.
// 安裝provider,系統(tǒng)進程(uid == 0 || uid == SYSTEM_UID)中,holder.noReleaseNeeded為true
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
// 非可運行ContentProvider客戶端進程返回ContentProviderProxy對象
return holder.provider;
}
需要注意,如果ContentProvider客戶端進程可運行ContentProvider,那么holder.provider為null,下面以普通客戶端進程為例說明安裝過程。
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) {
// 可運行ContentProvider客戶端進程
......
} else {
// provider為ContentProviderProxy對象
provider = holder.provider;
if (DEBUG_PROVIDER) Slog.v(TAG, "Installing external provider " + info.authority + ": "
+ info.name);
}
IActivityManager.ContentProviderHolder retHolder;
synchronized (mProviderMap) {
if (DEBUG_PROVIDER) Slog.v(TAG, "Checking to add " + provider
+ " / " + info.name);
// jBinder為BinderProxy對象
IBinder jBinder = provider.asBinder();
if (localProvider != null) {
......
} else {
//
ProviderRefCount prc = mProviderRefCountMap.get(jBinder);
if (prc != null) {
if (DEBUG_PROVIDER) {
Slog.v(TAG, "installProvider: lost the race, updating ref count");
}
// We need to transfer our new reference to the existing
// ref count, releasing the old one... but only if
// release is needed (that is, it is not running in the
// system process).
if (!noReleaseNeeded) {
incProviderRefLocked(prc, stable);
try {
ActivityManagerNative.getDefault().removeContentProvider(
holder.connection, stable);
} catch (RemoteException e) {
//do nothing content provider object is dead any way
}
}
} else {
// 創(chuàng)建ProviderClientRecord添加到mProviderMap
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
// 創(chuàng)建ProviderRefCount
prc = stable
? new ProviderRefCount(holder, client, 1, 0)
: new ProviderRefCount(holder, client, 0, 1);
}
// ProviderRefCount添加到mProviderRefCountMap
mProviderRefCountMap.put(jBinder, prc);
}
retHolder = prc.holder;
}
}
return retHolder;
}
現(xiàn)在ContentProvider客戶端進程已經(jīng)得到了ContentProviderProxy對象,下面看使用ContentProviderProxy對象訪問ContentProvider的過程。
使用ContentProviderProxy對象訪問ContentProvider的過程
使用ContentProviderProxy對象訪問ContentProvider的過程中涉及的類比較繁雜,首先看下類圖:

- ContentObserver
- 觀察者模式,接收Content改變的回調(diào)
- ContentObserver.Transport
- 繼承自IContentObserver.Stub, 接收Content的改變
- SelfContentObserver
- BulkCursorToCursorAdapter
- 適配器模式,轉(zhuǎn)換IBulkCursor接口到Cursor
- BulkCursorDescriptor
- 記錄CursorToBulkCursorAdapter中Cursor的屬性,用于在客戶端初始化BulkCursorToCursorAdapter
- BulkCursorNative
- 用于實現(xiàn)進程間通信
- CursorToBulkCursorAdapter
- 適配器模式,轉(zhuǎn)換Cursor接口到IBulkCursor,繼承自BulkCursorNative,支持進程間通信
- CursorWindow
- 包含數(shù)據(jù)庫多行內(nèi)容的buffer,用于進程間(ContentProvider客戶端與ContentProvider宿主)共享數(shù)據(jù)

下面從ContentResolver的query()開始分析。
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable String selection,
@Nullable String[] selectionArgs, @Nullable String sortOrder,
@Nullable CancellationSignal cancellationSignal) {
Preconditions.checkNotNull(uri, "uri");
// 這里unstableProvider為ContentProviderProxy對象
IContentProvider unstableProvider = acquireUnstableProvider(uri);
......
try {
long startTime = SystemClock.uptimeMillis();
......
try {
// 通過Binder IPC向ContentProvider查詢數(shù)據(jù)庫信息
// qCursor為BulkCursorToCursorAdapter對象
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, 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
// 處理ContentProvider宿主進程死亡的情況
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
qCursor = stableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
}
......
// 增加stableProvider引用計數(shù)
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
// 創(chuàng)建CursorWrapperInner對象
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
// 返回CursorWrapperInner
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) {
// 減少unstableProvider引用計數(shù)
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}
下面看ContentProviderProxy的query()的實現(xiàn)
public Cursor query(String callingPkg, Uri url, String[] projection, String selection,
String[] selectionArgs, String sortOrder, ICancellationSignal cancellationSignal)
throws RemoteException {
BulkCursorToCursorAdaptor adaptor = new BulkCursorToCursorAdaptor();
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IContentProvider.descriptor);
data.writeString(callingPkg);
url.writeToParcel(data, 0);
int length = 0;
if (projection != null) {
length = projection.length;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(projection[i]);
}
data.writeString(selection);
if (selectionArgs != null) {
length = selectionArgs.length;
} else {
length = 0;
}
data.writeInt(length);
for (int i = 0; i < length; i++) {
data.writeString(selectionArgs[i]);
}
data.writeString(sortOrder);
// adaptor.getObserver()返回ContentObserver.Transport對象
data.writeStrongBinder(adaptor.getObserver().asBinder());
data.writeStrongBinder(cancellationSignal != null ? cancellationSignal.asBinder() : null);
// Binder IPC,需要等待回復(fù)
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
if (reply.readInt() != 0) {
// 從Parcel中創(chuàng)建BulkCursorDescriptor對象
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
// 調(diào)用BulkCursorToCursorAdaptor的初始化方法
adaptor.initialize(d);
} else {
adaptor.close();
adaptor = null;
}
// 返回BulkCursorToCursorAdaptor
return adaptor;
}
......
}
下面看ContentProvider宿主進程處理QUERY_TRANSACTION請求。
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
switch (code) {
case QUERY_TRANSACTION:
{
data.enforceInterface(IContentProvider.descriptor);
String callingPkg = data.readString();
Uri url = Uri.CREATOR.createFromParcel(data);
// String[] projection
int num = data.readInt();
String[] projection = null;
if (num > 0) {
projection = new String[num];
for (int i = 0; i < num; i++) {
projection[i] = data.readString();
}
}
// String selection, String[] selectionArgs...
String selection = data.readString();
num = data.readInt();
String[] selectionArgs = null;
if (num > 0) {
selectionArgs = new String[num];
for (int i = 0; i < num; i++) {
selectionArgs[i] = data.readString();
}
}
String sortOrder = data.readString();
// 通常observer為IContentObserver.Stub.Proxy對象
IContentObserver observer = IContentObserver.Stub.asInterface(
data.readStrongBinder());
ICancellationSignal cancellationSignal = ICancellationSignal.Stub.asInterface(
data.readStrongBinder());
// 調(diào)用ContentProvider.Transport的query
Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
sortOrder, cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = null;
try {
// 創(chuàng)建CursorToBulkCursorAdaptor
adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
getProviderName());
cursor = null;
// 工廠方法,創(chuàng)建BulkCursorDescriptor記錄adaptor中Cursor的屬性
BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
adaptor = null;
reply.writeNoException();
reply.writeInt(1);
d.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
} finally {
// Close cursor if an exception was thrown while constructing the adaptor.
if (adaptor != null) {
adaptor.close();
}
if (cursor != null) {
cursor.close();
}
}
} else {
reply.writeNoException();
reply.writeInt(0);
}
return true;
}
......
}
......
}
......
}
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
// 檢查客戶端是否有權(quán)限讀取Content
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
// 客戶端沒有權(quán)限,返回空的MatrixCursor對象
// The caller has no access to the data, so return an empty cursor with
// the columns in the requested order. The caller may ask for an invalid
// column and we would not catch that but this is not a problem in practice.
// We do not call ContentProvider#query with a modified where clause since
// the implementation is not guaranteed to be backed by a SQL database, hence
// it may not handle properly the tautology where clause we would have created.
if (projection != null) {
return new MatrixCursor(projection, 0);
}
// Null projection means all columns but we have no idea which they are.
// However, the caller may be expecting to access them my index. Hence,
// we have to execute the query as if allowed to get a cursor with the
// columns. We then use the column names to return an empty cursor.
Cursor cursor = ContentProvider.this.query(uri, projection, selection,
selectionArgs, sortOrder, CancellationSignal.fromTransport(
cancellationSignal));
if (cursor == null) {
return null;
}
// Return an empty cursor for all columns.
return new MatrixCursor(cursor.getColumnNames(), 0);
}
final String original = setCallingPackage(callingPkg);
try {
// 調(diào)用ContentProvider的query,這里假定返回MatrixCursor對象
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
ContentProvider客戶端通過ContentProviderProxy的query()方法獲取了ContentProvider的一些信息(Count/ColumnNames等),但是沒有得到真正的數(shù)據(jù)內(nèi)容,下面分析獲取ContentProvider真正數(shù)據(jù)的過程。
ContentProvider客戶端使用Cursor獲取ContentProvider數(shù)據(jù)的過程
從前面的分析可知,調(diào)用getContentResolver().query()返回CursorWrapperInner類型的對象。

- CursorWrapperInner
- 使用完后,要關(guān)閉
- GC回收CursorWrapperInner時,會關(guān)閉Cursor
- CursorWrapper
- Cursor的封裝,用于實現(xiàn)僅需要重寫Cursor部分接口的子類
- CrossProcessCursorWrapper
- 可用于適配原始的Cursor到CrossProcessCursor,適配器模式
獲取CursorWrapperInner對象后,通過MoveToFirst()建立ContentProvider共享數(shù)據(jù),然后使用getXxx()訪問共享數(shù)據(jù)。
- 可用于適配原始的Cursor到CrossProcessCursor,適配器模式
MoveToFirst處理過程

public boolean moveToFirst() {
// mCursor為BulkCursorToCursorAdapter對象
return mCursor.moveToFirst();
}
// BulkCursorToCursorAdapter繼承自AbstractCursor
public final boolean moveToFirst() {
// 調(diào)用moveToPosition,設(shè)置位置為0
return moveToPosition(0);
}
public final boolean moveToPosition(int position) {
// Make sure position isn't past the end of the cursor
// position可以理解為數(shù)據(jù)庫Row id
final int count = getCount();
if (position >= count) {
mPos = count;
return false;
}
// Make sure position isn't before the beginning of the cursor
if (position < 0) {
mPos = -1;
return false;
}
// Check for no-op moves, and skip the rest of the work for them
// 當(dāng)前位置等于目標(biāo)位置,直接返回
if (position == mPos) {
return true;
}
// 當(dāng)前位置移動得到目標(biāo)位置
boolean result = onMove(mPos, position);
if (result == false) {
mPos = -1;
} else {
// 修改當(dāng)前位置
mPos = position;
}
return result;
}
BulkCursorToCursorAdapter重寫了onMove(),下面分析它的實現(xiàn)。
public boolean onMove(int oldPosition, int newPosition) {
// 如果Cursor已經(jīng)關(guān)閉拋出異常
throwIfCursorIsClosed();
try {
// Make sure we have the proper window
// 這里mWindow為null
if (mWindow == null
|| newPosition < mWindow.getStartPosition()
|| newPosition >= mWindow.getStartPosition() + mWindow.getNumRows()) {
// mBulkCursor為BulkCursorProxy對象
// 獲取、設(shè)置CursorWindow
setWindow(mBulkCursor.getWindow(newPosition));
} else if (mWantsAllOnMoveCalls) {
// mWantsAllOnMoveCalls默認(rèn)為false,如果為true,onMove為跨進程調(diào)用
mBulkCursor.onMove(newPosition);
}
} catch (RemoteException ex) {
// We tried to get a window and failed
Log.e(TAG, "Unable to get window because the remote process is dead");
return false;
}
// Couldn't obtain a window, something is wrong
if (mWindow == null) {
return false;
}
return true;
}
public CursorWindow getWindow(int position) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
data.writeInterfaceToken(IBulkCursor.descriptor);
// 傳遞目標(biāo)位置
data.writeInt(position);
// 同步Binder通信,獲取CursorWindow
mRemote.transact(GET_CURSOR_WINDOW_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
CursorWindow window = null;
if (reply.readInt() == 1) {
// 從Parcel中重建CursorWindow
window = CursorWindow.newFromParcel(reply);
}
return window;
} finally {
data.recycle();
reply.recycle();
}
}
下面看ContentProvider宿主進程(服務(wù)端)創(chuàng)建CursorWindow的過程。
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
switch (code) {
case GET_CURSOR_WINDOW_TRANSACTION: {
data.enforceInterface(IBulkCursor.descriptor);
// 目標(biāo)位置
int startPos = data.readInt();
// 調(diào)用CursorToBulkCursorAdaptor的getWindow
CursorWindow window = getWindow(startPos);
reply.writeNoException();
if (window == null) {
reply.writeInt(0);
} else {
// CursorWindow創(chuàng)建成功
reply.writeInt(1);
// 寫入Parcel,主要涉及Binder跨進程傳遞文件描述符
window.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
}
return true;
}
......
}
......
}
......
}
public CursorWindow getWindow(int position) {
synchronized (mLock) {
throwIfCursorIsClosed();
// mCursor為MatrixCursor對象,修改Cursor的當(dāng)前位置
if (!mCursor.moveToPosition(position)) {
closeFilledWindowLocked();
return null;
}
// getWindow返回null
CursorWindow window = mCursor.getWindow();
if (window != null) {
closeFilledWindowLocked();
} else {
// mFilledWindow為null
window = mFilledWindow;
if (window == null) {
// 創(chuàng)建CursorWindow
mFilledWindow = new CursorWindow(mProviderName);
window = mFilledWindow;
} else if (position < window.getStartPosition()
|| position >= window.getStartPosition() + window.getNumRows()) {
window.clear();
}
// Cursor中的數(shù)據(jù)拷貝至CursorWindow(匿名共享內(nèi)存)
mCursor.fillWindow(position, window);
}
if (window != null) {
// Acquire a reference to the window because its reference count will be
// decremented when it is returned as part of the binder call reply parcel.
window.acquireReference();
}
return window;
}
}
下面首先看CursorWindow的創(chuàng)建過程,然后分析數(shù)據(jù)拷貝至CursorWindow的過程。
public CursorWindow(String name) {
mStartPos = 0;
mName = name != null && name.length() != 0 ? name : "<unnamed>";
if (sCursorWindowSize < 0) {
/** The cursor window size. resource xml file specifies the value in kB.
* convert it to bytes here by multiplying with 1024.
*/
// CursorWindow大小默認(rèn)2MB
sCursorWindowSize = Resources.getSystem().getInteger(
com.android.internal.R.integer.config_cursorWindowSize) * 1024;
}
// 創(chuàng)建Native層CursorWindow及匿名共享內(nèi)存
mWindowPtr = nativeCreate(mName, sCursorWindowSize);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
(sCursorWindowSize / 1024) + " kb failed. " + printStats());
}
// CloseGuard用于確保在CursorWindow被回收之前釋放匿名共享內(nèi)存
mCloseGuard.open("close");
// mWindowPtr添加到sWindowToPidMap中
recordNewWindow(Binder.getCallingPid(), mWindowPtr);
}
下面看nativeCreate()的實現(xiàn)
static jlong nativeCreate(JNIEnv* env, jclass clazz, jstring nameObj, jint cursorWindowSize) {
String8 name;
const char* nameStr = env->GetStringUTFChars(nameObj, NULL);
name.setTo(nameStr);
env->ReleaseStringUTFChars(nameObj, nameStr);
CursorWindow* window;
// 創(chuàng)建匿名共享內(nèi)存及Native層的CursorWindow
status_t status = CursorWindow::create(name, cursorWindowSize, &window);
if (status || !window) {
ALOGE("Could not allocate CursorWindow '%s' of size %d due to error %d.",
name.string(), cursorWindowSize, status);
return 0;
}
LOG_WINDOW("nativeInitializeEmpty: window = %p", window);
return reinterpret_cast<jlong>(window);
}
status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
// 匿名共享內(nèi)存區(qū)域以CursorWindow:開頭,see內(nèi)存映射信息
String8 ashmemName("CursorWindow: ");
ashmemName.append(name);
status_t result;
// 創(chuàng)建匿名共享內(nèi)存區(qū)域
int ashmemFd = ashmem_create_region(ashmemName.string(), size);
if (ashmemFd < 0) {
result = -errno;
} else {
result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
if (result >= 0) {
// 映射虛擬內(nèi)存區(qū)域用于讀寫匿名共享內(nèi)存
void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);
if (data == MAP_FAILED) {
result = -errno;
} else {
result = ashmem_set_prot_region(ashmemFd, PROT_READ);
if (result >= 0) {
// 創(chuàng)建CursorWindow
CursorWindow* window = new CursorWindow(name, ashmemFd,
data, size, false /*readOnly*/);
// 初始化CursorWindow
result = window->clear();
if (!result) {
LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
"numRows=%d, numColumns=%d, mSize=%d, mData=%p",
window->mHeader->freeOffset,
window->mHeader->numRows,
window->mHeader->numColumns,
window->mSize, window->mData);
// 返回CursorWindow地址
*outCursorWindow = window;
return OK;
}
delete window;
}
}
::munmap(data, size);
}
::close(ashmemFd);
}
*outCursorWindow = NULL;
return result;
}
至此,CursorWindow的創(chuàng)建過程分析完了,下面看Cursor中的數(shù)據(jù)拷貝至CursorWindow的過程。
public void fillWindow(int position, CursorWindow window) {
DatabaseUtils.cursorFillWindow(this, position, window);
}
public static void cursorFillWindow(final Cursor cursor,
int position, final CursorWindow window) {
if (position < 0 || position >= cursor.getCount()) {
return;
}
// 保存原來的位置
final int oldPos = cursor.getPosition();
final int numColumns = cursor.getColumnCount();
// 初始化CursorWindow
window.clear();
// 設(shè)置CursorWindow的起始位置為position
window.setStartPosition(position);
// 設(shè)置CursorWindow的列數(shù)
window.setNumColumns(numColumns);
// cursor移動到目標(biāo)位置
if (cursor.moveToPosition(position)) {
rowloop: do {
// CursorWindow分配一行空間
if (!window.allocRow()) {
break;
}
// 遍歷列,將當(dāng)前行的每個列數(shù)據(jù)拷貝至CursorWindow
for (int i = 0; i < numColumns; i++) {
// 列類型
final int type = cursor.getType(i);
final boolean success;
switch (type) {
case Cursor.FIELD_TYPE_NULL:
success = window.putNull(position, i);
break;
case Cursor.FIELD_TYPE_INTEGER:
success = window.putLong(cursor.getLong(i), position, i);
break;
case Cursor.FIELD_TYPE_FLOAT:
success = window.putDouble(cursor.getDouble(i), position, i);
break;
case Cursor.FIELD_TYPE_BLOB: {
final byte[] value = cursor.getBlob(i);
success = value != null ? window.putBlob(value, position, i)
: window.putNull(position, i);
break;
}
default: // assume value is convertible to String
case Cursor.FIELD_TYPE_STRING: {
final String value = cursor.getString(i);
success = value != null ? window.putString(value, position, i)
: window.putNull(position, i);
break;
}
}
if (!success) {
window.freeLastRow();
break rowloop;
}
}
position += 1;
// cursor移動到下一行
} while (cursor.moveToNext());
}
// cursor恢復(fù)原來的位置
cursor.moveToPosition(oldPos);
}
下面只分析FIELD_TYPE_STRING類型數(shù)據(jù)的拷貝過程,也就是CursorWindow的putString的實現(xiàn)。在分析之前先了解Native層CursorWindow的內(nèi)存布局。

- CursorWindow的Header
- freeOffset: CursorWindow空閑區(qū)域的偏移
- firstChunkOffset: 第一個RowSlot的偏移
- numRows: 行數(shù)
- numColumns: 列數(shù)
- RowSlotChunk
- slots: 預(yù)分配的RowSlot,默認(rèn)100個
- nextChunkOffset: 如果預(yù)分配的RowSlot不夠用,表示下一個RowSlotChunk在CursorWindow中的偏移
- RowSlot
- offset: 記錄一行數(shù)據(jù)在CursorWindow中的偏移
- FieldSlot(記錄一個列數(shù)據(jù))
- type: 列數(shù)據(jù)類型
- 列類型為double/long
- data.d/data.l: 值
- 列類型為String/Blob
- data.buffer.offset: String/Blob內(nèi)容在CursorWindow中的偏移
- data.buffer.size: String/Blob內(nèi)容大小
- 列類型為Null
- data.buffer.offset: 0
- data.buffer.size: 0
下面看putString()的實現(xiàn)。
public boolean putString(String value, int row, int column) {
acquireReference();
try {
return nativePutString(mWindowPtr, value, row - mStartPos, column);
} finally {
releaseReference();
}
}
static jboolean nativePutString(JNIEnv* env, jclass clazz, jlong windowPtr,
jstring valueObj, jint row, jint column) {
// Native層的CursorWindow
CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
size_t sizeIncludingNull = env->GetStringUTFLength(valueObj) + 1;
const char* valueStr = env->GetStringUTFChars(valueObj, NULL);
if (!valueStr) {
LOG_WINDOW("value can't be transferred to UTFChars");
return false;
}
// 調(diào)用CursorWindow的putString,這里sizeIncludingNull包含字符串結(jié)束符
status_t status = window->putString(row, column, valueStr, sizeIncludingNull);
env->ReleaseStringUTFChars(valueObj, valueStr);
......
return true;
}
status_t CursorWindow::putString(uint32_t row, uint32_t column, const char* value,
size_t sizeIncludingNull) {
return putBlobOrString(row, column, value, sizeIncludingNull, FIELD_TYPE_STRING);
}
status_t CursorWindow::putBlobOrString(uint32_t row, uint32_t column,
const void* value, size_t size, int32_t type) {
if (mReadOnly) {
return INVALID_OPERATION;
}
// 查找所屬FieldSlot
FieldSlot* fieldSlot = getFieldSlot(row, column);
if (!fieldSlot) {
return BAD_VALUE;
}
// 對于Blob(字節(jié)數(shù)組)或String, 單獨分配存儲空間
uint32_t offset = alloc(size);
if (!offset) {
return NO_MEMORY;
}
// String內(nèi)容拷貝至分配的空間中
memcpy(offsetToPtr(offset), value, size);
// 記錄String數(shù)據(jù)信息
fieldSlot->type = type;
fieldSlot->data.buffer.offset = offset;
fieldSlot->data.buffer.size = size;
return OK;
}
至此,ContentProvider宿主進程的getWindow()分析完成,下面看ContentProvider客戶端收到回復(fù)后建立匿名共享內(nèi)存的過程。
public CursorWindow getWindow(int position) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
try {
......
if (reply.readInt() == 1) {
// 從Parcel中重建CursorWindow
window = CursorWindow.newFromParcel(reply);
}
return window;
} finally {
data.recycle();
reply.recycle();
}
}
public static final Parcelable.Creator<CursorWindow> CREATOR
= new Parcelable.Creator<CursorWindow>() {
public CursorWindow createFromParcel(Parcel source) {
return new CursorWindow(source);
}
......
};
public static CursorWindow newFromParcel(Parcel p) {
return CREATOR.createFromParcel(p);
}
private CursorWindow(Parcel source) {
// 起始位置
mStartPos = source.readInt();
// 從Parcel建立匿名共享內(nèi)存
mWindowPtr = nativeCreateFromParcel(source);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window could not be "
+ "created from binder.");
}
mName = nativeGetName(mWindowPtr);
mCloseGuard.open("close");
}
下面看nativeCreateFromParcel()的實現(xiàn)
static jlong nativeCreateFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
Parcel* parcel = parcelForJavaObject(env, parcelObj);
CursorWindow* window;
status_t status = CursorWindow::createFromParcel(parcel, &window);
......
return reinterpret_cast<jlong>(window);
}
status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
String8 name = parcel->readString8();
status_t result;
// 匿名共享內(nèi)存文件描述符
int ashmemFd = parcel->readFileDescriptor();
if (ashmemFd == int(BAD_TYPE)) {
result = BAD_TYPE;
} else {
// 獲取匿名共享內(nèi)存區(qū)域大小
ssize_t size = ashmem_get_size_region(ashmemFd);
if (size < 0) {
result = UNKNOWN_ERROR;
} else {
// 創(chuàng)建文件描述符ashmemFd的拷貝
int dupAshmemFd = ::dup(ashmemFd);
if (dupAshmemFd < 0) {
result = -errno;
} else {
// 映射虛擬地址空間用以讀取匿名共享內(nèi)存
void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
if (data == MAP_FAILED) {
result = -errno;
} else {
// 創(chuàng)建CursorWindow
CursorWindow* window = new CursorWindow(name, dupAshmemFd,
data, size, true /*readOnly*/);
LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "
"numRows=%d, numColumns=%d, mSize=%d, mData=%p",
window->mHeader->freeOffset,
window->mHeader->numRows,
window->mHeader->numColumns,
window->mSize, window->mData);
*outCursorWindow = window;
return OK;
}
::close(dupAshmemFd);
}
}
}
*outCursorWindow = NULL;
return result;
}
這樣,ContentProvider客戶端與ContentProvider宿主進程之間就建立起了匿名共享內(nèi)存,此后ContentProvider客戶端只需訪問匿名共享內(nèi)存就能獲取Content數(shù)據(jù)。
getXxx(以getString為例分析)處理過程

下面從CursorWrapperInner的getString()開始分析
public String getString(int columnIndex) {
// mCursor為BulkCursorToCursorAdapter類型的對象
return mCursor.getString(columnIndex);
}
public String getString(int columnIndex) {
// 檢查當(dāng)前的位置(Row)是否合法
checkPosition();
// 調(diào)用CursorWindow的getString
return mWindow.getString(mPos, columnIndex);
}
public String getString(int row, int column) {
acquireReference();
try {
// 從CursorWindow(匿名共享內(nèi)存)中讀取String
return nativeGetString(mWindowPtr, row - mStartPos, column);
} finally {
releaseReference();
}
}
下面看nativeGetString()的實現(xiàn)
static jstring nativeGetString(JNIEnv* env, jclass clazz, jlong windowPtr,
jint row, jint column) {
// 獲取Native層的CursorWindow
CursorWindow* window = reinterpret_cast<CursorWindow*>(windowPtr);
LOG_WINDOW("Getting string for %d,%d from %p", row, column, window);
// 根據(jù)行、列號找到對應(yīng)的FieldSlot
CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
if (!fieldSlot) {
throwExceptionWithRowCol(env, row, column);
return NULL;
}
// 讀取列數(shù)據(jù)類型
int32_t type = window->getFieldSlotType(fieldSlot);
if (type == CursorWindow::FIELD_TYPE_STRING) {
size_t sizeIncludingNull;
// 字符串內(nèi)容地址
const char* value = window->getFieldSlotValueString(fieldSlot, &sizeIncludingNull);
if (sizeIncludingNull <= 1) {
return gEmptyString;
}
// Convert to UTF-16 here instead of calling NewStringUTF. NewStringUTF
// doesn't like UTF-8 strings with high codepoints. It actually expects
// Modified UTF-8 with encoded surrogate pairs.
String16 utf16(value, sizeIncludingNull - 1);
// 返回字符串
return env->NewString(reinterpret_cast<const jchar*>(utf16.string()), utf16.size());
} else if (type == CursorWindow::FIELD_TYPE_INTEGER) {
int64_t value = window->getFieldSlotValueLong(fieldSlot);
char buf[32];
snprintf(buf, sizeof(buf), "%" PRId64, value);
return env->NewStringUTF(buf);
} else if (type == CursorWindow::FIELD_TYPE_FLOAT) {
double value = window->getFieldSlotValueDouble(fieldSlot);
char buf[32];
snprintf(buf, sizeof(buf), "%g", value);
return env->NewStringUTF(buf);
} else if (type == CursorWindow::FIELD_TYPE_NULL) {
return NULL;
} else if (type == CursorWindow::FIELD_TYPE_BLOB) {
throw_sqlite3_exception(env, "Unable to convert BLOB to string");
return NULL;
} else {
throwUnknownTypeException(env, type);
return NULL;
}
}
小結(jié)

參考
https://developer.android.com/guide/topics/providers/content-provider-basics?hl=zh-cn