ContentProvider通過Binder進程間通信機制來突破應用程序邊界的權限控制(IBulkCursor和IContentProvider),同時以共享內存作爲數據載體(CursorWindow),ContentProviderProxy所對應的進程通過IBulkCursor和CursorWindow來操作數據集合
ContentProvider數據傳輸流程的時序圖如下:
類的簡單說明
BulkCursorToCursorAdaptor
將BulkCursor代理對象轉成Cursor的適配器類
BulkCursorNative
IBulkCursor Binder本地對象
BulkCursorProxy
IBulkCursor Binder代理對象
ContentProviderNative
IContentProvider Binder本地對象
ContentProviderProxy
IContentProvider Binder代理對象
CursorToBulkCursorAdaptor
將ContentPrivade中查詢得到的Cursor對象適配成IBulkCursor對象
BulkCursorDescriptor
Binder進程間通信傳遞IBulkCursor和CursorWindow對象
CursorWindow
匿名共享內存的封裝類
Cursor
數據操作的抽象接口
ContentProvider數據傳輸流程的簡單類圖如下:
ContentResolver.java (d:\source\android\android8.0\android-8.0.0_r1\frameworks\base\core\java\android\content)
unstableProvider是通過AMS獲取得到的IContentProvider Binder代理對象,IContentProvider Binder代理對象對應的類爲ContentProviderProxy,接下來分析ContentProviderProxy的query函數
public final @Nullable Cursor query(final @RequiresPermission.Read @NonNull Uri uri,
@Nullable String[] projection, @Nullable Bundle queryArgs,
@Nullable CancellationSignal cancellationSignal) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
try {
// unstableProvider爲IContentProvider代理對象,對應ContentProviderProxy的query函數
qCursor = unstableProvider.query(mPackageName, uri, projection,
queryArgs, remoteCancellationSignal);
} catch (DeadObjectException e) {
}
qCursor.getCount();
long durationMillis = SystemClock.uptimeMillis() - startTime;
maybeLogQueryToEventLog(durationMillis, uri, projection, queryArgs);
// Wrap the cursor object into CursorWrapperInner object.
final IContentProvider provider = (stableProvider != null) ? stableProvider
: acquireProvider(uri);
final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
stableProvider = null;
qCursor = null;
// 將CursorWrapperInner返回給調用者
return wrapper;
} catch (RemoteException e) {
return null;
} finally {
}
}
ContentProviderNative.java (d:\source\android\android8.0\android-8.0.0_r1\frameworks\base\core\java\android\content)
ContentProviderProxy的query函數首先創建一個BulkCursorToCursorAdaptor對象,BulkCursorToCursorAdaptor對象從名字上來看是將IBulkCursor對象適配成Cursor操作的接口類,封裝IBulkCursor的細節.接下來將數據查詢的信息寫入Pracel,然後將數據通過Binder驅動發送給IContentProvider的Binder本地對象ContentProviderNative,Binder通信返回後,如果有數據,從Binder對象中讀取對應的BulkCursorDescriptor信息,BulkCursorDescriptor中有兩個重要的信息,IBulkCursor和CursorWindow代理對象,將BulkCursorDescriptor保存在BulkCursorToCursorAdaptor中,以提供給對應的客服端程序對具體的數據操作
ContentProviderProxy
public Cursor query(String callingPkg, Uri url, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal)
throws RemoteException {
// 創建BulkCursorToCursorAdaptor對象,將BulkCursorDescriptor注入,方便調用放通過Cursor層的接口既可獲取對應的數據
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.writeBundle(queryArgs);
data.writeStrongBinder(adaptor.getObserver().asBinder());
data.writeStrongBinder(
cancellationSignal != null ? cancellationSignal.asBinder() : null);
// 向Binder發送QUERY_TRANSACTION命令
mRemote.transact(IContentProvider.QUERY_TRANSACTION, data, reply, 0);
DatabaseUtils.readExceptionFromParcel(reply);
if (reply.readInt() != 0) {
// 通過Binder驅動將IBulkCursor和CursorWindow代理對象讀取出來
BulkCursorDescriptor d = BulkCursorDescriptor.CREATOR.createFromParcel(reply);
Binder.copyAllowBlocking(mRemote, (d.cursor != null) ? d.cursor.asBinder() : null);
// 把BulkCursorDescriptor保存在BulkCursorToCursorAdaptor中
adaptor.initialize(d);
} else {
adaptor.close();
adaptor = null;
}
return adaptor;
} catch (RemoteException ex) {
adaptor.close();
throw ex;
} catch (RuntimeException ex) {
adaptor.close();
throw ex;
} finally {
data.recycle();
reply.recycle();
}
}
接下來分析IContentProvider的Binder本地對象,IContentProvider代理對象最終會調用到ContentProviderNative的nTransact函數,query函數對應的cmd爲QUERY_TRANSACTION,首先調用query函數,ContentProviderNative沒有實現query函數。 ContentProvider有個成員變量mTransport類型爲Transport,Transport爲ContentProvider的內部類。繼承ContentProviderNative,ContentProvider在向AMS提交時,會把mTransport的Binder對象傳遞給AMS。query函數最終調用的是Transport的query函數,query查詢得到的Cursor對象將其封裝成可以跨Binder進程的BulkCursorDescriptor對象,將BulkCursorDescriptor對象返回給ContentProviderProxy代理端。CursorToBulkCursorAdaptor對象作爲適配器類,方便Cursor轉成BulkCursorDescriptor對象
ContentProviderNative
public boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
try {
switch (code) {
case QUERY_TRANSACTION:
{
// query函數最終調用的是ContentProvider的query函數
Cursor cursor = query(callingPkg, url, projection, queryArgs, cancellationSignal);
if (cursor != null) {
// 將ContentProvider中查詢到的信息封裝成CursorToBulkCursorAdaptor
CursorToBulkCursorAdaptor adaptor = null;
try {
adaptor = new CursorToBulkCursorAdaptor(cursor, observer,
getProviderName());
cursor = null;
BulkCursorDescriptor d = adaptor.getBulkCursorDescriptor();
adaptor = null;
reply.writeNoException();
reply.writeInt(1);
// 通過Binder驅動把BulkCursorDescriptor對象傳遞給調用的APP進程
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;
}
}
ContentProvider.java (d:\source\android\android8.0\android-8.0.0_r1\frameworks\base\core\java\android\content)
Transport的query函數,最終調用的是子類的query函數的具體實現,將查詢得到的Cursor對象返回
class Transport extends ContentProviderNative {
@Override
public Cursor query(String callingPkg, Uri uri, @Nullable String[] projection,
@Nullable Bundle queryArgs, @Nullable ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
try {
// 調用子類的query函數
return ContentProvider.this.query(
uri, projection, queryArgs,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
}