在 Framework 源碼解析知識梳理(5) - startService 源碼分析 中,咱們分析了Service
啓動的內部實現原理,今天,咱們趁熱打鐵,看一下Android
中的四大組件中另外一個組件ContentProvider
。java
在分析以前,先上一張整個的流程圖,你們在後面繞暈了之後,能夠參考這張圖進行對照: 緩存
在使用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);
}
複製代碼
這上面的ApplicationContentResolver
是ContentResolver
的子類: app
如今,咱們以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
。qCursor
用CursorWrapperInner
包裹起來,這裏須要注意的是第二個參數,若是是經過unstableProvider
查詢獲得的qCursor
,那麼將須要調用acquireProvider
,並將返回值傳入。那麼,咱們接下來就要分析經過acquireUnstableProvider
、acquireProvider
獲取IContentProvider
的過程。源碼分析
首先,經過acquireUnstableProvider
方法根據Uri
中的authority
字段,調用acquireUnstableProvider(Context c, String auth)
方法: ui
ApplicationContentResolver
所實現的:
mMainThread
的
acquireProvider
方法,它其實是一個
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
在這種狀況下面,會執行兩步操做:
ActivityManagerService
獲取ContentProviderHolder
ContentProviderHolder
中的信息進行安裝這裏咱們先假設沒有緩存的狀況,經過 Framework 源碼解析知識梳理(1) - 應用進程與 AMS 的通訊實現 中學到的知識,咱們知道它最終會調用到ActivityManagerService
的下面這個方法:
getContentProviderImpl
方法返回一個
ContentProviderHolder
對象,這個方法比較長,就不貼代碼了,直接說結論,這裏會分爲如下幾種狀況:
(a) ContentProvider 所在進程已經啓動,而且已經該 ContentProvider 已經被安裝
這種狀況下,直接返回該ContentProviderHolder
便可:
此時,就須要經過ApplicationThread
對象,再和ContentProvider
所在的進程進行交互,以返回一個ContentProviderHolder
實例:
Binder
通訊,那麼最終會調用到
ContentProvider
所在進程的下面這個方法:
installContentProviders
方法:
List<ProviderInfo>
對象,經過installProvider
方法進行安裝,並將結果存放在List<ContentProviderHolder>
列表中。ActivityManagerService
。(b-1) 安裝過程
在這一步當中,傳入的第二個參數holder
爲null
,所以會根據Provider
的名字,動態地加載該類,並調用它的attachInfo
方法:
Provider
:
localProvider
,類型爲ContentProvider
provider
,類型爲Transport
provider
是經過localProvider
的getIContentProvider
方法得到的,它是ContentProvider
的一個內部類,它的做用就是做爲ContentProvider
在遠程調用者中的一個代理對象,也就是說,ContentProvider
的使用者是經過獲取ContentProvider
所在進程的一個代理類Transport
,再經過這個Transport
對象調用到ContentProvider
進行查詢的:
localProvider
的
attachInfo
方法,這裏面會初始化權限相關的信息,最終會執行
ContentProvider
的
onCreate()
方法:
localProvider
不爲空,那麼會執行下面的邏輯:
ProviderClientRecord
對象,其內部包含了下面幾個變量:
mNames
:ContentProvider
對象的authority
mProvider
:遠程代理對象mLocalProvider
:本地對象mHolder
:返回給AMS
的數據結構,AMS
再會把它返回給ContentProvider
的調用者,mHolder
的類型爲IActivityManager.ContentProviderHolder
,其內部包含的數據結構爲:
關於ContentProviderHolder
和ProviderClientRecord
,其繼承族譜以下圖所示:
發佈過程,其實就是調用了ActivityManagerService
的publishContentProviders
方法,將在ContentProvider
擁有者所建立的List<ContentProviderHolder>
保存起來:
(c) ContentProvider 所在進程沒有啓動
在這種狀況下,就須要先經過startProcessLocked
啓動ContentProvider
所在進程,等待進程啓動完畢以後,再進行安裝。
在第一步中,經過ActivityManagerService
,咱們最終得到了ContentProviderHolder
對象,接下來就是調用installProvider
方法,這裏和咱們以前在第一步中的(b-1)
中所看到的installProvider
實際上是同一個方法,區別在於,以前咱們分析的installProvider
傳入的holder
參數爲空,下面,咱們就來看一下當holder
參數不爲空時最終會走到下面的邏輯:
installProviderAuthoritiesLocked
方法中,會將它緩存在
mProviderMap
當中。
當調用者進程存在緩存時,會調用acquireExistingProvider
方法,這裏面就會經過咱們前面所看到的mProviderMap
進行查找:
這篇文章拖了一個星期,總算是完成了,源碼看的真的頭暈,其實最終看下來,發現整個調用過程,和咱們以前分析過的 Framework 源碼解析知識梳理(5) - startService 源碼分析 很相似,究其根本,就是調用者進程、全部者進程和ActivityManagerService
進程的三方調用。