1.前言
- 最近一直在看 《Android進(jìn)階解密》 的一本書,這本書編寫邏輯、流程都非常好拳亿,而且很容易看懂,非常推薦大家去看看(沒有收廣告費愿伴,單純覺得作者寫的很好)肺魁。
- 上一篇簡單的介紹了Android進(jìn)階(二): 應(yīng)用進(jìn)程啟動過程,最終知道了ActivityThread就是代表應(yīng)用進(jìn)程隔节。
- 今天就介紹ActivityThread啟動之后鹅经,是如何啟動
Application
(基于Android 8.0 系統(tǒng))。 - 文章中實例 linhaojian的Github
2.Application啟動過程的時序圖
Application啟動流程.png
3.源碼分析
3.1 ActivityThread初始化:
public static void main(String[] args) {
//...
//創(chuàng)建ActivityThread對象 & 調(diào)用attach()
ActivityThread thread = new ActivityThread();
thread.attach(false, startSeq);
//創(chuàng)建主線程的Handler
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
//創(chuàng)建主線程的Looper
Looper.loop();
}
- 主要做了2件事怎诫,實例化ActivityThread & 創(chuàng)建主線程Handler與Looper接收信息瘾晃;
3.2 ActivityThread的attach函數(shù):
private void attach(boolean system, long startSeq) {
//...
RuntimeInit.setApplicationObject(mAppThread.asBinder());
// 獲取ActivityManagerService的代理對象
final IActivityManager mgr = ActivityManager.getService();// 1
try {
//通知AMS進(jìn)行application的初始化
mgr.attachApplication(mAppThread, startSeq);// 2
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
}
- 注釋1:獲取ActivityManagerService的代理對象;
- 注釋2:通過代理對象調(diào)用attachApplication()幻妓,獲取啟動application所需信息(應(yīng)用進(jìn)程相關(guān)數(shù)據(jù))蹦误;
3.3 ActivityManagerService的attachApplication函數(shù):
public final void attachApplication(IApplicationThread thread, long startSeq) {
synchronized (this) {
int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid, callingUid, startSeq);// 1
Binder.restoreCallingIdentity(origId);
}
}
- 注釋1:調(diào)用attachApplicationLocked();
3.4 ActivityManagerService的attachApplicationLocked函數(shù):
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// 根據(jù)pid獲取存儲在AMS中肉津,對應(yīng)進(jìn)程的相關(guān)信息
ProcessRecord app;
long startTime = SystemClock.uptimeMillis();
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);// 1
}
} else {
app = null;
}
// ...
thread.bindApplication(processName, appInfo, providers, null, profilerInfo, // 2
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
// ...
}
- 注釋1:根據(jù)pid獲取存儲在AMS中强胰,對應(yīng)應(yīng)用進(jìn)程的相關(guān)信息;
- 注釋2:通知ActivityThread啟動application(IApplicationThread是ActivityThread的內(nèi)部類阀圾,負(fù)責(zé)與ActivityManagerService通訊)哪廓;
3.5 ActivityThread的handleBindApplication函數(shù):
- AMS中調(diào)用了ActivityThread的bindApplication函數(shù)狗唉,其內(nèi)部其實是完成了Handler切換到主線程初烘,并且最后活調(diào)用handleBindApplication(),下面我們看看其內(nèi)部源碼;
private void handleBindApplication(AppBindData data) {
// 將UI線程注冊為運行時的虛擬機(jī).
VMRuntime.registerSensitiveThread();
if (data.trackAllocation) {
DdmVmInternal.enableRecentAllocations(true);
}
// ...
// 創(chuàng)建上下文對象
final ContextImpl appContext = ContextImpl.createAppContext(this, data.info);
updateLocaleListFromAppContext(appContext,
mResourcesManager.getConfiguration().getLocales());
if (!Process.isIsolated()) {
final int oldMask = StrictMode.allowThreadDiskWritesMask();
try {
setupGraphicsSupport(appContext);
} finally {
StrictMode.setThreadPolicyMask(oldMask);
}
} else {
ThreadedRenderer.setIsolatedProcess(true);
}
// Continue loading instrumentation.
if (ii != null) {
// ...
} else {
mInstrumentation = new Instrumentation();// 1
mInstrumentation.basicInit(this);
}
Application app;
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
final StrictMode.ThreadPolicy writesAllowedPolicy = StrictMode.getThreadPolicy();
try {
// If the app is being launched for full backup or restore, bring it up in
// a restricted environment with the base application class.
// 初始化Applcation類
app = data.info.makeApplication(data.restrictedBackupMode, null); // 2
// Propagate autofill compat state
app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
mInitialApplication = app;
// don't bring up providers in restricted mode; they may depend on the
// app's custom Application class
if (!data.restrictedBackupMode) {
if (!ArrayUtils.isEmpty(data.providers)) {
installContentProviders(app, data.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);
}
}
// Do this after providers, since instrumentation tests generally start their
// test thread at this point, and we don't want that racing.
try {
mInstrumentation.onCreate(data.instrumentationArgs); // 3
}
catch (Exception e) {
throw new RuntimeException(
"Exception thrown in onCreate() of "
+ data.instrumentationName + ": " + e.toString(), e);
}
try {
//調(diào)用Applcation的OnCreate函數(shù)
mInstrumentation.callApplicationOnCreate(app); // 4
} catch (Exception e) {
if (!mInstrumentation.onException(app, e)) {
throw new RuntimeException(
"Unable to create application " + app.getClass().getName()
+ ": " + e.toString(), e);
}
}
} finally {
// If the app targets < O-MR1, or doesn't change the thread policy
// during startup, clobber the policy to maintain behavior of b/36951662
if (data.appInfo.targetSdkVersion < Build.VERSION_CODES.O_MR1
|| StrictMode.getThreadPolicy().equals(writesAllowedPolicy)) {
StrictMode.setThreadPolicy(savedPolicy);
}
}
// Preload fonts resources
FontsContract.setApplicationContextForResources(appContext);
if (!Process.isIsolated()) {
try {
final ApplicationInfo info =
getPackageManager().getApplicationInfo(
data.appInfo.packageName,
PackageManager.GET_META_DATA /*flags*/,
UserHandle.myUserId());
if (info.metaData != null) {
final int preloadedFontsResource = info.metaData.getInt(
ApplicationInfo.METADATA_PRELOADED_FONTS, 0);
if (preloadedFontsResource != 0) {
data.info.getResources().preloadFonts(preloadedFontsResource);
}
}
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
- 注釋1:創(chuàng)建Instrumentation,負(fù)責(zé)跟蹤Application還在Activity的生命周期分俯;
- 注釋2:創(chuàng)建Application對象 & 調(diào)用其attach()肾筐;
- 注釋3:調(diào)用Instrumentation的onCreate(),內(nèi)部是空實現(xiàn)缸剪;
- 注釋4:調(diào)用Instrumentation的callApplicationOnCreate()吗铐,內(nèi)部是調(diào)用application的onCreate,如下代碼杏节;
public class Instrumentation {
public void callApplicationOnCreate(Application app) {
app.onCreate();
}
}
4.類關(guān)系
Application啟動類結(jié)構(gòu).png
- ActivityThread :通過IActivityManager類唬渗,通知AMS準(zhǔn)備application啟動所需進(jìn)程數(shù)據(jù) ;
- ActivityManagerService :獲取application啟動所需進(jìn)程數(shù)據(jù) 奋渔;
- Instrumentation :創(chuàng)建&啟動Application镊逝;跟蹤Application的生命周期;
5.總結(jié)
- 到此嫉鲸,
Application啟動過程
介紹完畢撑蒜。 - 如果喜歡我的分享,可以點擊 關(guān)注 或者 贊,你們支持是我分享的最大動力 座菠。
- linhaojian的Github
歡迎關(guān)注linhaojian_CSDN博客或者linhaojian_簡書狸眼!
不定期分享關(guān)于安卓開發(fā)的干貨。
寫技術(shù)文章初心
- 技術(shù)知識積累
- 技術(shù)知識鞏固
- 技術(shù)知識分享
- 技術(shù)知識交流