ActivityManagerService之ContentProvider原理篇2數據傳輸流程

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);
            }
        }
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章