好了,終于到了最后一個啦,寫到這里,真的覺得不容意啊,以前看這些組件也就那樣了,現在還要記錄下來,重點是這東西都被分析爛了,我們這些后人屌絲還在寫,沒點突破的。真沒意思呢!就當寫作業咯。啦啦啦啦,不管如何,讓我們開始看下吧
起航 --- ContentResolver
API: 23
說真的,這個組件我還真的相對于Activity和Service用起來真的好少啊!
現在都不能記起來用他來干嘛了,雖然知道他能用來做跨進程通訊用,不過對于一般的app。
這玩意還真的用的次數少啊! 現在能想起來的一次使用這個就是要獲取圖片的時候。
以前開發的時候遇到的惡心的是,有些Rom把相冊給閹割了,搞了個別的來代替,導致調不了圖庫!
所以搞到需要自己開發一個,真的很無語!
ContentResolver mContentResolver = this.getContentResolver();
Cursor mCursor = mContentResolver.query(mImageUri, null,
MediaStore.Images.Media.MIME_TYPE + "=? or "
+ MediaStore.Images.Media.MIME_TYPE + "=? or " + MediaStore.Images.Media.MIME_TYPE + "=?" + " or " + MediaStore.Images.Media.MIME_TYPE + "=?",
new String[]{"image/jpeg", "image/png", "image/jpg", "image/jpe"},
MediaStore.Images.Media.DATA);
從這里我們開始看起吧
public final Cursor query(Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder) {
return query(uri, projection, selection, selectionArgs, sortOrder, null);
}
public final Cursor query(final Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
CancellationSignal cancellationSignal) {
IContentProvider unstableProvider = acquireUnstableProvider(uri);
if (unstableProvider == null) {
return null;
}
IContentProvider stableProvider = null;
Cursor qCursor = null;
try {
...
ICancellationSignal remoteCancellationSignal = null;
if (cancellationSignal != null) {
cancellationSignal.throwIfCanceled();
remoteCancellationSignal = unstableProvider.createCancellationSignal();
cancellationSignal.setRemote(remoteCancellationSignal);
}
try {
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
} catch (DeadObjectException e) {
unstableProviderDied(unstableProvider);
stableProvider = acquireProvider(uri);
if (stableProvider == null) {
return null;
}
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);
// Wrap the cursor object into CursorWrapperInner object.
CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
stableProvider != null ? stableProvider : acquireProvider(uri));
stableProvider = null;
qCursor = null;
return wrapper;
} catch (RemoteException e) {
return null;
} finally {
...
}
}
@Override
protected IContentProvider acquireUnstableProvider(Context c, String auth) {
return mMainThread.acquireProvider(c,
ContentProvider.getAuthorityWithoutUserId(auth),
resolveUserIdFromAuthority(auth), false);
}
開頭調用acquireUnstableProvider(uri)
,經過一輪跟蹤,發現他跑到了ActivityThread
里面的acquireProvider
,內容如下
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 {
holder = ActivityManagerNative.getDefault().getContentProvider(
getApplicationThread(), auth, userId, stable);
} catch (RemoteException ex) {
}
if (holder == null) {
return null;
}
// Install provider will increment the reference count for us, and break
// any ties in the race.
holder = installProvider(c, holder, holder.info,
true /*noisy*/, holder.noReleaseNeeded, stable);
return holder.provider;
}
我們看到他先查找本地有沒有,有就返回,沒有就去找了AMS要ContentProvider
,拿回來后就存本地,然后返回。
好了,讓我們去看下AMS里面的實現吧
@Override
public final ContentProviderHolder getContentProvider(
IApplicationThread caller, String name, int userId, boolean stable) {
enforceNotIsolatedCaller("getContentProvider");
if (caller == null) {
String msg = "null IApplicationThread when getting content provider "
+ name;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
return getContentProviderImpl(caller, name, null, stable, userId);
}
他跑去了他的實現函數getContentProviderImpl()
....真無語,同個類里面還搞抽象和實現啊,
像前面那樣寫成realGetContentProviderImpl()
不就好了嘛,哈哈,真 · 干活函數
不過這個實現還不小,三百多行,這在AMS里面都是這樣的,看著頭疼,一堆的判斷,截取關鍵的部分:
private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
String name, IBinder token, boolean stable, int userId) {
ContentProviderRecord cpr;
ContentProviderConnection conn = null;
ProviderInfo cpi = null;
...
proc = startProcessLocked(cpi.processName,
cpr.appInfo, false, 0, "content provider",
new ComponentName(cpi.applicationInfo.packageName,
cpi.name), false, false, false);
cpr.launchingApp = proc;
mLaunchingProviders.add(cpr);
mProviderMap.putProviderByName(name, cpr);
conn = incProviderCountLocked(r, cpr, token, stable);
return cpr != null ? cpr.newHolder(conn) : null;
}
這里需要補充的說明是,我們都知道那個ContentProvider的啟動是伴隨進程的啟動,啟動進程是有上面的startProcessLocked()來完成的。我們來看下他里面寫了什么。。。
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
checkTime(startTime, "startProcess: returned from zygote!");
...
}
這個函數也是一個巨無霸,我想那個AMS一定是靠幾個人寫完的,因為他的函數風格不在一樣,呵呵,雖然我也經常寫得不一樣。只截取重要的幾句..
這個函數最終通過調用Process的start方法來啟動。我們繼續深入看下
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
好,遇到了一個傳說級別的名字了Zygote
,不要問我這個名詞代表的故事,百度下吧。
感覺寫完這些組件后,可以開始寫更底層的部分了...哎。說真的,挺無聊的,看完又沒怎么樣,但出來混,他們老覺得高級開發就得看底層代碼,精通整個Android系統啊!這學習量真的不小,不過也就那點工資...
還不如學校門口一個擺攤的,好了,羅嗦了,繼續吧。
結論就是通過Zygote,最后我們到了ActivityThread的main方法,還記得這個玩意嘛?
我們在很久前解析那個Handler的時候有提到,程序的入口方法是ActivityThread的mian
方法!
是不是覺得很像以前學java時候!居然在安卓里面遇到人家!
public static void main(String[] args) {
SamplingProfilerIntegration.start();
...
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
整個的main方法就初始主線程的地方,同時開動主Looper, 然后attach這個方法會最終把消息傳遞AMS,然后AMS就完成了ContentProvider的創建!
private void attach(boolean system) {
...
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
...
}
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid) {
// Find the application record that is being attached... either via
// the pid if we are running in multiple processes, or just pull the
// next app record if we are emulating process with anonymous threads.
ProcessRecord app;
...
if (DEBUG_CONFIGURATION) Slog.v(TAG, "Binding proc "
+ processName + " with config " + mConfiguration);
ApplicationInfo appInfo = app.instrumentationInfo != null
? app.instrumentationInfo : app.info;
app.compat = compatibilityInfoForPackageLocked(appInfo);
if (profileFd != null) {
profileFd = profileFd.dup();
}
ProfilerInfo profilerInfo = profileFile == null ? null
: new ProfilerInfo(profileFile, profileFd, samplingInterval, profileAutoStop);
thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(mConfiguration), app.compat, getCommonServicesLocked(),
mCoreSettingsObserver.getCoreSettingsLocked());
updateLruProcessLocked(app, false, null);
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
...
}
每次到AMS里面的函數都是一大串!!!這里的thread就是那個ApplicationThread
,我們很熟悉。
走了一圈,又跑回來了
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
Bundle coreSettings) {
...
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableOpenGlTrace = enableOpenGlTrace;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfilerInfo = profilerInfo;
sendMessage(H.BIND_APPLICATION, data);
}
最終這個變成了同我們的H先生發送BIND_APPLICATION消息!
private void handleBindApplication(AppBindData data) {
...
// 1.創建Context
ContextImpl instrContext = ContextImpl.createAppContext(this, pi);
java.lang.ClassLoader cl = instrContext.getClassLoader();
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
data.instrumentationUiAutomationConnection);
...
// 2.創建app
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
...
// 3. 啟動ContentProvider,發送消息,調用onCreate函數
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
// For process that contains content providers, we want to
// ensure that the JIT is enabled "at some point".
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
...
//4. 啟動我們Application的onCreate方法。
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app);
StrictMode.setThreadPolicy(savedPolicy);
}
這個函數受AMS污染,也是賊長的一個函數。
在這個handleBindApplication函數里面,我截取保留了核心的信息,同時加了注釋。
具體就是創建context
和Application
,然后通過installContentProviders()來啟動當前進程的ContentProvider
,所以下次有人和你提問題,說你知道那個ContentProvider嘛?
你就反問,說你知道這個組件是在哪里初始化的嘛?
不知道你就說是在ActivityThread里面的H先生接受到了BindApplication消息,然后在處理消息對應的handleBindApplication()
方法里面的installContentProviders()
函數啦!
是不是很裝逼的樣子!!
為了徹底的裝逼,我們來看下這個installContentProviders()到底做了什么!
免得人家也看過代碼,慘遭裝逼失敗的下場。
private void installContentProviders(
Context context, List<ProviderInfo> providers) {
final ArrayList<IActivityManager.ContentProviderHolder> results =
new ArrayList<IActivityManager.ContentProviderHolder>();
for (ProviderInfo cpi : providers) {
IActivityManager.ContentProviderHolder cph = installProvider(context, null, cpi,
false /*noisy*/, true /*noReleaseNeeded*/, true /*stable*/);
if (cph != null) {
cph.noReleaseNeeded = true;
results.add(cph);
}
}
try {
ActivityManagerNative.getDefault().publishContentProviders(
getApplicationThread(), results);
} catch (RemoteException ex) {
}
}
這里面遍歷了providers
,然后installProvider
去啟動他們。最后找AMS把他們給注冊保存了。
而且是保存在一個叫mProviderMap
的map里面中,便于別的進程通過AMS來調用!
有代碼有真相,有木有,就在下面,沒騙人的啊!
public final void publishContentProviders(IApplicationThread caller,
List<ContentProviderHolder> providers) {
...
enforceNotIsolatedCaller("publishContentProviders");
synchronized (this) {
final ProcessRecord r = getRecordForAppLocked(caller);
final long origId = Binder.clearCallingIdentity();
final int N = providers.size();
for (int i=0; i<N; i++) {
ContentProviderHolder src = providers.get(i);
...
ContentProviderRecord dst = r.pubProviders.get(src.info.name);
if (dst != null) {
ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
mProviderMap.putProviderByClass(comp, dst);
String names[] = dst.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
mProviderMap.putProviderByName(names[j], dst);
}
...
updateOomAdjLocked(r);
}
}
Binder.restoreCallingIdentity(origId);
}
}
在徹底的裝逼,我們需要來看下這個installProvider
函數
private IActivityManager.ContentProviderHolder installProvider(Context context,
IActivityManager.ContentProviderHolder holder, ProviderInfo info,
boolean noisy, boolean noReleaseNeeded, boolean stable) {
ContentProvider localProvider = null;
IContentProvider provider;
...
try { //用ClassLoader去加載!
final java.lang.ClassLoader cl = c.getClassLoader();
localProvider = (ContentProvider)cl.
loadClass(info.name).newInstance();
provider = localProvider.getIContentProvider();
...
// XXX Need to create the correct context for this provider.
localProvider.attachInfo(c, info);
} catch (java.lang.Exception e) {
...
}
return null;
}
}
...
}
好了他的啟動過程基本到這里結束,我們回溯到前面的步驟,回到我們處理Application消息的第四點
//4. 啟動我們Application的onCreate方法。
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
mInstrumentation.onCreate(data.instrumentationArgs);
mInstrumentation.callApplicationOnCreate(app);
StrictMode.setThreadPolicy(savedPolicy);
好了,整個過程基本這樣了。
我們從一開始的acquireUnstableProvider(uri);
函數跑到這里,都快忘記原本是要干嘛了。
續航 ==== Query
讓我們繼續啟程,回到一開始query函數,在獲得了我們IContentProvider后,就調用了他的query方法。
qCursor = unstableProvider.query(mPackageName, uri, projection,
selection, selectionArgs, sortOrder, remoteCancellationSignal);
這個IContentProvider
是一個Binder
接口,具體的干活的人是誰呢?
IContentProvider
的具體實現是ContentProviderNative
,然后Transport
又繼承了它。
abstract public class ContentProviderNative extends Binder implements IContentProvider
class Transport extends ContentProviderNative
這個類是躲在ContentProvider的里面的即ContentProvider.Transport 。好了,寫了這么多,回主線
@Override
public Cursor query(String callingPkg, Uri uri, String[] projection,
String selection, String[] selectionArgs, String sortOrder,
ICancellationSignal cancellationSignal) {
validateIncomingUri(uri);
uri = getUriWithoutUserId(uri);
if (enforceReadPermission(callingPkg, uri, null) != AppOpsManager.MODE_ALLOWED) {
...
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 {
return ContentProvider.this.query(
uri, projection, selection, selectionArgs, sortOrder,
CancellationSignal.fromTransport(cancellationSignal));
} finally {
setCallingPackage(original);
}
}
到這里去調用了ContentProvider的query方法。這樣整個過程就結束了。其余的方法也在這個類里面,套路類似的,就不再寫了,這篇文章已經寫了很長了,而且現在有事,得去做點別了!
后記
今天寫得好晚,看到都有點累,不段的翻滾。。。寫到后面都沒精神和注意力了。。
先寫到這里,洗個澡睡覺,明天抽時間在繼續做補充。。
但無論如何把四大金剛的源碼都寫了一遍了。
====
更新:
重新補充了部分內容,把整個流程更細化了下。
不過還是有些具體的內容不是很清楚,
下一次在游覽別的時候,能有空再把這個過程寫得更清楚的話,就再來更新吧
對于Zygote這個下次得抽時間再寫一篇他的專輯。
谷歌起這個名字給它,這么有深度東西,很有故事。
下一篇就這么定是他了 ^_ ^