Android ContentProvider
本文基于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
- 应用使用该类访问ContentProvider
- ContentProviderProxy
- ContentProvider代理对象
- ContentProviderNative
- ContentProvider本地对象
- Transport
- 实现了ContentProviderNative
- ContentProvider
- 用于应用间共享数据
通过ContentResolver获取ContentProviderProxy对象
下面从ContextImpl
的getContentResolver()
开始分析
public ContentResolver getContentResolver() {
return mContentResolver;
}
这里mContentResolver
是一个ApplicationContentResolver
类型的引用,它是在ContextImpl
构造函数中创建的,下面看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){
// 调用ActivityThread的acquireProvider
// ContentProvider.getAuthorityWithoutUserId(auth)通常返回auth
// resolveUserIdFromAuthority(auth)通常返回0
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
- unstableProvider
- 当ContentProvider宿主进程死亡时,系统会通知ContentProvider客户端进程
- stableProvider
- 当ContentProvider宿主进程死亡时
- ContentProviderConnection存在时,系统会杀死非persistent的ContentProvider客户端进程
- ContentProviderConnection移除时,系统不会杀ContentProvider客户端进程
下面看ActivityThread
的acquireProvider()
的实现
- 当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.
// 系统进程(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()
的实现
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引用计数
incProviderRefLocked(prc, stable);
}
return provider;
}
}
- ProviderKey
- 保存authorith以及userId
- ProviderClientRecord
- 保存Provider信息(在ContentProvider宿主进程及客户端均使用)
这里假定acquireExistingProvider()
返回null,下面看getContentProvider()
的实现
// 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) {
// 创建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) {
// 根据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...
// 检查目标ContentProvider是否已经发布,cpr不为null也并不意味着ContentProvider已经发布
cpr = mProviderMap.getProviderByName(name, userId);
......
boolean providerRunning = cpr != null && cpr.proc != null && !cpr.proc.killed;
if (providerRunning) {
// ContentProvider已经发布
cpi = cpr.info;
String msg;
......
if (r != null && cpr.canRunHere(r)) {
// ContentProvider能够运行在调用者进程,例如:
// 1) 多进程ContentProvider同时调用者与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,调用者自己实例化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引用计数
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,调整
// ContentProvider宿主进程及关联进程在LRU链表中的位置
updateLruProcessLocked(cpr.proc, false, null);
checkTime(startTime, "getContentProviderImpl: after updateLruProcess");
}
}
checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
final int verifiedAdj = cpr.proc.verifiedAdj;
// 更新ContentProvider宿主进程状态及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);
// 减少引用计数,如果计数为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");
// 检查客户端是否有权限访问ContentProvider
if ((msg = checkContentProviderPermissionLocked(cpi, r, userId, !singleton))
!= null) {
throw new SecurityException(msg);
}
checkTime(startTime, "getContentProviderImpl: after checkContentProviderPermission");
// system准备好之前不能运行非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");
// 根据组件名及userId获取ContentProviderRecord
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
final boolean firstClass = cpr == null;
if (firstClass) {
// 需要创建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);
// 创建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能够运行在调用者进程,例如:
// 1) 调用者是ContentProvider宿主自身
// 2) 多进程ContentProvider同时调用者与ContentProvider宿主进程uid相同
// 这里无需设置holder.provider为null,ContentProviderRecord创建后成员provider默认为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");
// 设置ContentProvider包的状态
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宿主进程已经运行
if (DEBUG_PROVIDER) Slog.d(TAG_PROVIDER,
"Installing in existing process " + proc);
if (!proc.pubProviders.containsKey(cpi.name)) {
// ContentProvider没有发布
checkTime(startTime, "getContentProviderImpl: scheduling install");
// ContentProviderRecord放入pubProviders
proc.pubProviders.put(cpi.name, cpr);
try {
// 通过Binder IPC请求宿主进程安装发布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发布后从该列表中删除相应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);
// 增加引用计数,返回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宿主进程发布
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驱动发送的Binder传输完成协议后立即返回
mRemote.transact(SCHEDULE_INSTALL_PROVIDER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
假定ContentProvider
宿主进程已经启动,ContentProvider
尚未安装发布。下面看ContentProvider
宿主进程安装发布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为应用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 {
// 发布ContentProvider
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
下面看安装ContentProvider
的过程。由于ContentProvider
宿主进程及客户端进程都需要调用installProvider()
,这里只关注ContentProvider
宿主进程的执行过程。
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();
// 创建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.
// 设置Provider信息(权限等),调用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) {
// 根据组件名查询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创建ProviderClientRecord
pr = installProviderAuthoritiesLocked(provider, localProvider, holder);
// 添加到mLocalProviders及mLocalProvidersByName
mLocalProviders.put(jBinder, pr);
mLocalProvidersByName.put(cname, pr);
}
retHolder = pr.mHolder;
} else {
......
}
}
return retHolder;
}
下面看ContentProvider
的发布过程。
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, 等待回复
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对应同一个ContentProviderRecord
mProviderMap.putProviderByName(names[j], dst);
}
// ContentProvider发布,从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发布的等待着
dst.provider = src.provider;
dst.proc = r;
dst.notifyAll();
}
......
}
}
Binder.restoreCallingIdentity(origId);
}
}
ContentProvider
的发布等待者(通常是system_server的Binder线程)被唤醒后,将发送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
客户端收到回复后安装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,系统进程(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 {
// 创建ProviderClientRecord添加到mProviderMap
ProviderClientRecord client = installProviderAuthoritiesLocked(
provider, localProvider, holder);
if (noReleaseNeeded) {
prc = new ProviderRefCount(holder, client, 1000, 1000);
} else {
// 创建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;
}
现在ContentProvider
客户端进程已经得到了ContentProviderProxy
对象,下面看使用ContentProviderProxy
对象访问ContentProvider
的过程。
使用ContentProviderProxy对象访问ContentProvider的过程
使用ContentProviderProxy
对象访问ContentProvider
的过程中涉及的类比较繁杂,首先看下类图:
- ContentObserver
- 观察者模式,接收Content改变的回调
- ContentObserver.Transport
- 继承自IContentObserver.Stub, 接收Content的改变
- SelfContentObserver
- BulkCursorToCursorAdapter
- 适配器模式,转换IBulkCursor接口到Cursor
- BulkCursorDescriptor
- 记录CursorToBulkCursorAdapter中Cursor的属性,用于在客户端初始化BulkCursorToCursorAdapter
- BulkCursorNative
- 用于实现进程间通信
- CursorToBulkCursorAdapter
- 适配器模式,转换Cursor接口到IBulkCursor,继承自BulkCursorNative,支持进程间通信
- CursorWindow
- 包含数据库多行内容的buffer,用于进程间(ContentProvider客户端与ContentProvider宿主)共享数据
下面从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查询数据库信息
// 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引用计数
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
// 创建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引用计数
releaseUnstableProvider(unstableProvider);
}
if (stableProvider != null) {
releaseProvider(stableProvider);
}
}
}
下面看ContentProviderProxy
的query()
的实现
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,需要等待回复
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
if (reply.readInt() != 0) {
// 从Parcel中创建BulkCursorDescriptor对象
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
// 调用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());
// 调用ContentProvider.Transport的query
Cursor cursor = query(callingPkg, url, projection, selection, selectionArgs,
sortOrder, cancellationSignal);
if (cursor != null) {
CursorToBulkCursorAdaptor adaptor = null;
try {
// 创建CursorToBulkCursorAdaptor
adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
getProviderName());
cursor = null;
// 工厂方法,创建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);
// 检查客户端是否有权限读取Content
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
// 客户端没有权限,返回空的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 {
// 调用ContentProvider的query,这里假定返回MatrixCursor对象
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
ContentProvider
客户端通过ContentProviderProxy
的query()
方法获取了ContentProvider
的一些信息(Count/ColumnNames等),但是没有得到真正的数据内容,下面分析获取ContentProvider
真正数据的过程。
ContentProvider客户端使用Cursor获取ContentProvider数据的过程
从前面的分析可知,调用getContentResolver().query()
返回CursorWrapperInner
类型的对象。
- CursorWrapperInner
- 使用完后,要关闭
- GC回收CursorWrapperInner时,会关闭Cursor
- CursorWrapper
- Cursor的封装,用于实现仅需要重写Cursor部分接口的子类
- CrossProcessCursorWrapper
- 可用于适配原始的Cursor到CrossProcessCursor,适配器模式
获取CursorWrapperInner
对象后,通过MoveToFirst()
建立ContentProvider共享数据,然后使用getXxx()
访问共享数据。
- 可用于适配原始的Cursor到CrossProcessCursor,适配器模式
MoveToFirst处理过程
public boolean moveToFirst() {
// mCursor为BulkCursorToCursorAdapter对象
return mCursor.moveToFirst();
}
// BulkCursorToCursorAdapter继承自AbstractCursor
public final boolean moveToFirst() {
// 调用moveToPosition,设置位置为0
return moveToPosition(0);
}
public final boolean moveToPosition(int position) {
// Make sure position isn't past the end of the cursor
// position可以理解为数据库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
// 当前位置等于目标位置,直接返回
if (position == mPos) {
return true;
}
// 当前位置移动得到目标位置
boolean result = onMove(mPos, position);
if (result == false) {
mPos = -1;
} else {
// 修改当前位置
mPos = position;
}
return result;
}
BulkCursorToCursorAdapter
重写了onMove()
,下面分析它的实现。
public boolean onMove(int oldPosition, int newPosition) {
// 如果Cursor已经关闭抛出异常
throwIfCursorIsClosed();
try {
// Make sure we have the proper window
// 这里mWindow为null
if (mWindow == null
|| newPosition < mWindow.getStartPosition()
|| newPosition >= mWindow.getStartPosition() + mWindow.getNumRows()) {
// mBulkCursor为BulkCursorProxy对象
// 获取、设置CursorWindow
setWindow(mBulkCursor.getWindow(newPosition));
} else if (mWantsAllOnMoveCalls) {
// mWantsAllOnMoveCalls默认为false,如果为true,onMove为跨进程调用
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);
// 传递目标位置
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
宿主进程(服务端)创建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);
// 目标位置
int startPos = data.readInt();
// 调用CursorToBulkCursorAdaptor的getWindow
CursorWindow window = getWindow(startPos);
reply.writeNoException();
if (window == null) {
reply.writeInt(0);
} else {
// CursorWindow创建成功
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的当前位置
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) {
// 创建CursorWindow
mFilledWindow = new CursorWindow(mProviderName);
window = mFilledWindow;
} else if (position < window.getStartPosition()
|| position >= window.getStartPosition() + window.getNumRows()) {
window.clear();
}
// Cursor中的数据拷贝至CursorWindow(匿名共享内存)
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
的创建过程,然后分析数据拷贝至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大小默认2MB
sCursorWindowSize = Resources.getSystem().getInteger(
com.android.internal.R.integer.config_cursorWindowSize) * 1024;
}
// 创建Native层CursorWindow及匿名共享内存
mWindowPtr = nativeCreate(mName, sCursorWindowSize);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
(sCursorWindowSize / 1024) + " kb failed. " + printStats());
}
// CloseGuard用于确保在CursorWindow被回收之前释放匿名共享内存
mCloseGuard.open("close");
// mWindowPtr添加到sWindowToPidMap中
recordNewWindow(Binder.getCallingPid(), mWindowPtr);
}
下面看nativeCreate()
的实现
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;
// 创建匿名共享内存及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) {
// 匿名共享内存区域以CursorWindow:开头,see内存映射信息
String8 ashmemName("CursorWindow: ");
ashmemName.append(name);
status_t result;
// 创建匿名共享内存区域
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) {
// 映射虚拟内存区域用于读写匿名共享内存
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) {
// 创建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
的创建过程分析完了,下面看Cursor
中的数据拷贝至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();
// 设置CursorWindow的起始位置为position
window.setStartPosition(position);
// 设置CursorWindow的列数
window.setNumColumns(numColumns);
// cursor移动到目标位置
if (cursor.moveToPosition(position)) {
rowloop: do {
// CursorWindow分配一行空间
if (!window.allocRow()) {
break;
}
// 遍历列,将当前行的每个列数据拷贝至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恢复原来的位置
cursor.moveToPosition(oldPos);
}
下面只分析FIELD_TYPE_STRING类型数据的拷贝过程,也就是CursorWindow
的putString
的实现。在分析之前先了解Native层CursorWindow
的内存布局。
- CursorWindow的Header
- freeOffset: CursorWindow空闲区域的偏移
- firstChunkOffset: 第一个RowSlot的偏移
- numRows: 行数
- numColumns: 列数
- RowSlotChunk
- slots: 预分配的RowSlot,默认100个
- nextChunkOffset: 如果预分配的RowSlot不够用,表示下一个RowSlotChunk在CursorWindow中的偏移
- RowSlot
- offset: 记录一行数据在CursorWindow中的偏移
- FieldSlot(记录一个列数据)
- type: 列数据类型
- 列类型为double/long
- data.d/data.l: 值
- 列类型为String/Blob
- data.buffer.offset: String/Blob内容在CursorWindow中的偏移
- data.buffer.size: String/Blob内容大小
- 列类型为Null
- data.buffer.offset: 0
- data.buffer.size: 0
下面看putString()
的实现。
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;
}
// 调用CursorWindow的putString,这里sizeIncludingNull包含字符串结束符
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(字节数组)或String, 单独分配存储空间
uint32_t offset = alloc(size);
if (!offset) {
return NO_MEMORY;
}
// String内容拷贝至分配的空间中
memcpy(offsetToPtr(offset), value, size);
// 记录String数据信息
fieldSlot->type = type;
fieldSlot->data.buffer.offset = offset;
fieldSlot->data.buffer.size = size;
return OK;
}
至此,ContentProvider
宿主进程的getWindow()
分析完成,下面看ContentProvider
客户端收到回复后建立匿名共享内存的过程。
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建立匿名共享内存
mWindowPtr = nativeCreateFromParcel(source);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window could not be "
+ "created from binder.");
}
mName = nativeGetName(mWindowPtr);
mCloseGuard.open("close");
}
下面看nativeCreateFromParcel()
的实现
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;
// 匿名共享内存文件描述符
int ashmemFd = parcel->readFileDescriptor();
if (ashmemFd == int(BAD_TYPE)) {
result = BAD_TYPE;
} else {
// 获取匿名共享内存区域大小
ssize_t size = ashmem_get_size_region(ashmemFd);
if (size < 0) {
result = UNKNOWN_ERROR;
} else {
// 创建文件描述符ashmemFd的拷贝
int dupAshmemFd = ::dup(ashmemFd);
if (dupAshmemFd < 0) {
result = -errno;
} else {
// 映射虚拟地址空间用以读取匿名共享内存
void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
if (data == MAP_FAILED) {
result = -errno;
} else {
// 创建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
宿主进程之间就建立起了匿名共享内存,此后ContentProvider
客户端只需访问匿名共享内存就能获取Content数据。
getXxx(以getString为例分析)处理过程
下面从CursorWrapperInner
的getString()
开始分析
public String getString(int columnIndex) {
// mCursor为BulkCursorToCursorAdapter类型的对象
return mCursor.getString(columnIndex);
}
public String getString(int columnIndex) {
// 检查当前的位置(Row)是否合法
checkPosition();
// 调用CursorWindow的getString
return mWindow.getString(mPos, columnIndex);
}
public String getString(int row, int column) {
acquireReference();
try {
// 从CursorWindow(匿名共享内存)中读取String
return nativeGetString(mWindowPtr, row - mStartPos, column);
} finally {
releaseReference();
}
}
下面看nativeGetString()
的实现
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);
// 根据行、列号找到对应的FieldSlot
CursorWindow::FieldSlot* fieldSlot = window->getFieldSlot(row, column);
if (!fieldSlot) {
throwExceptionWithRowCol(env, row, column);
return NULL;
}
// 读取列数据类型
int32_t type = window->getFieldSlotType(fieldSlot);
if (type == CursorWindow::FIELD_TYPE_STRING) {
size_t sizeIncludingNull;
// 字符串内容地址
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;
}
}
小结
参考
https://developer.android.com/guide/topics/providers/content-provider-basics?hl=zh-cn