Framework 源碼解析知識梳理(6) ContentProvider 源碼解析

1、前言

Framework 源碼解析知識梳理(5) - startService 源碼分析 中,咱們分析了Service啓動的內部實現原理,今天,咱們趁熱打鐵,看一下Android中的四大組件中另外一個組件ContentProviderjava

2、源碼解析

在分析以前,先上一張整個的流程圖,你們在後面繞暈了之後,能夠參考這張圖進行對照: 緩存

2.1 ContentResolver 獲取過程

在使用ContentProvider來進行數據的增刪改查時,第一步就是要經過getContentResolver(),得到一個ContentResolver對象,該方法實際上調用了基類中的mBase變量,也就是ContextImpl中的getContentResolver()方法,並返回它其中的mContentResolver變量。bash

//ContextImpl.java

    @Override
    public ContentResolver getContentResolver() {
        return mContentResolver;
    }
複製代碼

而該mContentResolver是在ContextImpl的構造函數中初始化的,這其實和咱們以前在 插件化知識梳理(9) - 資源的動態加載示例及源碼分析 中所分析的getResources()方法返回一個Resources對象的過程相似。數據結構

private ContextImpl(ContextImpl container, ActivityThread mainThread,
            LoadedApk packageInfo, IBinder activityToken, UserHandle user, boolean restricted,
            Display display, Configuration overrideConfiguration, int createDisplayWithId) {
        //...
        mContentResolver = new ApplicationContentResolver(this, mainThread, user);
    }
複製代碼

這上面的ApplicationContentResolverContentResolver的子類: app

2.2 簡單的查詢過程

如今,咱們以ContentResolver所提供的query方法爲例,對ContentProvider的調用過程進行一次簡單的走讀:ide

public final @Nullable Cursor query(final @NonNull Uri uri, @Nullable String[] projection,
            @Nullable String selection, @Nullable String[] selectionArgs,
            @Nullable String sortOrder, @Nullable CancellationSignal cancellationSignal) {
        Preconditions.checkNotNull(uri, "uri");
        //1.獲取ContentProvider接口。
        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();
                //2.建立取消信號量。
                remoteCancellationSignal = unstableProvider.createCancellationSignal();
                cancellationSignal.setRemote(remoteCancellationSignal);
            }
            try {
                //3.調用IContentProvider的query方法。
                qCursor = unstableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            } catch (DeadObjectException e) {
                //若是發生了異常,那麼銷燬unstableProvider對象,從新獲取一個stableProvider對象。
                unstableProviderDied(unstableProvider);
                stableProvider = acquireProvider(uri);
                //若是stableProvider對象仍是爲空,那麼直接返回空。
                if (stableProvider == null) {
                    return null;
                }
                //調用stableProvider進行查詢。
                qCursor = stableProvider.query(mPackageName, uri, projection,
                        selection, selectionArgs, sortOrder, remoteCancellationSignal);
            }
            if (qCursor == null) {
                return null;
            }

            // Force query execution.  Might fail and throw a runtime exception here.
            qCursor.getCount();
            long durationMillis = SystemClock.uptimeMillis() - startTime;
            maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);

            //用CursorWrapperInner把qCursor包裹起來。
            CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
                    stableProvider != null ? stableProvider : acquireProvider(uri));
            stableProvider = null;
            qCursor = null;
            return wrapper;
        } catch (RemoteException e) {
            // Arbitrary and not worth documenting, as Activity
            // Manager will kill this process shortly anyway.
            return null;
        } finally {
            if (qCursor != null) {
                qCursor.close();
            }
            if (cancellationSignal != null) {
                cancellationSignal.setRemote(null);
            }
            if (unstableProvider != null) {
                releaseUnstableProvider(unstableProvider);
            }
            if (stableProvider != null) {
                releaseProvider(stableProvider);
            }
        }
    }
複製代碼

咱們對上面的流程進行一個簡單的梳理:函數

  • 經過acquireUnstableProvider獲取一個unstableProvider實例,按字面上的翻譯它是一個不穩定的ContentProvider
  • 經過第一步中獲取的unstableProvider實例進行查詢,若是查詢成功,那麼獲得qCursor對象;若是ContentProvider所對應的進程已經死亡,那麼將會釋放unstableProvider對象,再經過調用acquireProvider方法從新獲得一個stableProvider,它和unstableProvider相同,都是實現了IContentProvider接口,以後在經過它來查詢獲得qCursor
  • 把第二步中得到的qCursorCursorWrapperInner包裹起來,這裏須要注意的是第二個參數,若是是經過unstableProvider查詢獲得的qCursor,那麼將須要調用acquireProvider,並將返回值傳入。

那麼,咱們接下來就要分析經過acquireUnstableProvideracquireProvider獲取IContentProvider的過程。源碼分析

2.3 IContentProvider 獲取過程

首先,經過acquireUnstableProvider方法根據Uri中的authority字段,調用acquireUnstableProvider(Context c, String auth)方法: ui

該方法是由咱們前面看到的 ApplicationContentResolver所實現的:
能夠看到,這裏調用了 mMainThreadacquireProvider方法,它其實是一個 ActivityThread實例,其實現爲:

public final IContentProvider acquireProvider(
            Context c, String auth, int userId, boolean stable) {
        //首先從緩存中獲取,若是獲取到就直接返回。
        final IContentProvider provider = acquireExistingProvider(c, auth, userId, stable);
        if (provider != null) {
            return provider;
        }

        IActivityManager.ContentProviderHolder holder = null;
        try {
            //若是緩存當中沒有,那麼首先經過AMS進行獲取。
            holder = ActivityManagerNative.getDefault().getContentProvider(
                    getApplicationThread(), auth, userId, stable);
        } catch (RemoteException ex) {
        }
        if (holder == null) {
            Slog.e(TAG, "Failed to find provider info for " + auth);
            return null;
        }

        //根據返回的holder信息進行安裝。
        holder = installProvider(c, holder, holder.info,
                true /*noisy*/, holder.noReleaseNeeded, stable);
        return holder.provider;
    }
複製代碼

這裏,首先會去緩存中查找IContentProvider,若是沒有找到,那麼在調用AMS的方法去查找,獲取一個ContentProviderHolder對象。this

2.3.1 調用者進程不存在緩存的狀況

在這種狀況下面,會執行兩步操做:

  • 第一步:經過ActivityManagerService獲取ContentProviderHolder
  • 第二步:經過返回的ContentProviderHolder中的信息進行安裝

第一步,經過 ActivityManagerService 獲取 ContentProviderHolder

這裏咱們先假設沒有緩存的狀況,經過 Framework 源碼解析知識梳理(1) - 應用進程與 AMS 的通訊實現 中學到的知識,咱們知道它最終會調用到ActivityManagerService的下面這個方法:

接下來最終會調用到 getContentProviderImpl方法返回一個 ContentProviderHolder對象,這個方法比較長,就不貼代碼了,直接說結論,這裏會分爲如下幾種狀況:

(a) ContentProvider 所在進程已經啓動,而且已經該 ContentProvider 已經被安裝

這種狀況下,直接返回該ContentProviderHolder便可:

(b) ContentProvider 所在進程已經啓動,可是該 ContentProvider 沒有被安裝

此時,就須要經過ApplicationThread對象,再和ContentProvider所在的進程進行交互,以返回一個ContentProviderHolder實例:

通過 Binder通訊,那麼最終會調用到 ContentProvider所在進程的下面這個方法:
這裏面調用有調用了內部的 installContentProviders方法:
這裏的操做分爲兩步:

  • 安裝:根據傳過來的List<ProviderInfo>對象,經過installProvider方法進行安裝,並將結果存放在List<ContentProviderHolder>列表中。
  • 發佈:將安裝的結果,再經過一次消息傳遞,返回給ActivityManagerService

(b-1) 安裝過程

在這一步當中,傳入的第二個參數holdernull,所以會根據Provider的名字,動態地加載該類,並調用它的attachInfo方法:

咱們上面的有兩個 Provider

  • localProvider,類型爲ContentProvider
  • provider,類型爲Transport

provider是經過localProvidergetIContentProvider方法得到的,它是ContentProvider的一個內部類,它的做用就是做爲ContentProvider在遠程調用者中的一個代理對象,也就是說,ContentProvider的使用者是經過獲取ContentProvider所在進程的一個代理類Transport,再經過這個Transport對象調用到ContentProvider進行查詢的:

接下來,還會去調用 localProviderattachInfo方法,這裏面會初始化權限相關的信息,最終會執行 ContentProvideronCreate()方法:
假設上面咱們得到的 localProvider不爲空,那麼會執行下面的邏輯:
這裏面,咱們會生成一個 ProviderClientRecord對象,其內部包含了下面幾個變量:

  • mNamesContentProvider對象的authority
  • mProvider:遠程代理對象
  • mLocalProvider:本地對象
  • mHolder:返回給AMS的數據結構,AMS再會把它返回給ContentProvider的調用者,mHolder的類型爲IActivityManager.ContentProviderHolder,其內部包含的數據結構爲:

關於ContentProviderHolderProviderClientRecord,其繼承族譜以下圖所示:

(b-2) 發佈過程

發佈過程,其實就是調用了ActivityManagerServicepublishContentProviders方法,將在ContentProvider擁有者所建立的List<ContentProviderHolder>保存起來:

(c) ContentProvider 所在進程沒有啓動

在這種狀況下,就須要先經過startProcessLocked啓動ContentProvider所在進程,等待進程啓動完畢以後,再進行安裝。

第二步,利用返回的 ContentProviderHolder 中的信息,進行安裝

在第一步中,經過ActivityManagerService,咱們最終得到了ContentProviderHolder對象,接下來就是調用installProvider方法,這裏和咱們以前在第一步中的(b-1)中所看到的installProvider實際上是同一個方法,區別在於,以前咱們分析的installProvider傳入的holder參數爲空,下面,咱們就來看一下當holder參數不爲空時最終會走到下面的邏輯:

installProviderAuthoritiesLocked方法中,會將它緩存在 mProviderMap當中。

2.3.2 調用者進程存在緩存的狀況

當調用者進程存在緩存時,會調用acquireExistingProvider方法,這裏面就會經過咱們前面所看到的mProviderMap進行查找:

3、小結

這篇文章拖了一個星期,總算是完成了,源碼看的真的頭暈,其實最終看下來,發現整個調用過程,和咱們以前分析過的 Framework 源碼解析知識梳理(5) - startService 源碼分析 很相似,究其根本,就是調用者進程、全部者進程和ActivityManagerService進程的三方調用。


更多文章,歡迎訪問個人 Android 知識梳理系列:

相關文章
相關標籤/搜索