Android9.0 Activity啟動流程分析(二)
文章目錄
在Android9.0 Activity啟動流程分析(一)中,我們最終分析到AMS通過zygote啟動Activity對應的程序,接下來繼續分析。
1、ActivityThread的main函式
通過zygote啟動程序時,傳入的className為android.app.ActivityThread。
因此,當zygote通過反射呼叫程序的main函式時,ActivityThread的main函式將被呼叫
// frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
// Make sure TrustedCertificateStore looks in the right place for CA certificates
final File configDir = Environment. getUserConfigDirectory(UserHandle.myUserId());
TrustedCertificateStore.setDefaultUserDirectory(configDir);
Process.setArgV0("<pre-initialized>");
//準備主執行緒的Looper
Looper.prepareMainLooper();
// Find the value for {@link #PROC_START_SEQ_IDENT} if provided on the command line.
// It will be in the format "seq=114"
long startSeq = 0;
if (args != null) {
for (int i = args.length - 1; i >= 0; --i) {
if (args[i] != null && args[i].startsWith(PROC_START_SEQ_IDENT)) {
startSeq = Long.parseLong(
args[i].substring(PROC_START_SEQ_IDENT.length()));
}
}
}
// 建立當前程序的ActivityThread
ActivityThread thread = new ActivityThread();
//呼叫attach函式
thread.attach(false, startSeq);
if (sMainThreadHandler == null) {
// 儲存程序對應的主執行緒Handler
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
// End of event ActivityThreadMain.
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
// 進入主執行緒的訊息迴圈
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
從上述程式碼可以看出,ActivityThread的main函式最主要工作是:
- 創建出一個Looper,並將主執行緒加入到訊息迴圈中。
- 創建出ActivityThread,並呼叫其attach函式。
接下來看ActivityThread的attach函式
// frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system, long startSeq) {
sCurrentActivityThread = this;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
//JIT-Just in time
//JIT技術主要是對多次執行的程式碼進行編譯,當再次呼叫時使用編譯之後的機器碼,而不是每次都解釋,以節約時間
//JIT原理:
//每啟動一個應用程式,都會相應地啟動一個dalvik虛擬機器,啟動時會建立JIT執行緒,一直在後臺執行。
//當某段程式碼被呼叫時,虛擬機器會判斷它是否需要編譯成機器碼,如果需要,就做一個標記。
//JIT執行緒在後臺檢測該標記,如果發現標記被設定,就把對應程式碼編譯成機器碼,並將其機器碼地址及相關資訊儲存起來
//當程序下次執行到此段程式碼時,就會直接跳到機器碼執行,而不再解釋執行,從而提高執行速度
//這裡開啟JIT,應該是為了提高android繪製的速度
ensureJitEnabled();
}
});
// 設定在DDMS中看到的程序名為"<pre-initialized>"
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
//設定RuntimeInit的mApplicationObject引數
RuntimeInit.setApplicationObject(mAppThread.asBinder());
final IActivityManager mgr = ActivityManager.getService();
try {
// 與AMS通訊,呼叫其attachApplication介面
mgr.attachApplication(mAppThread, startSeq);
} catch (RemoteException ex) {
throw ex.rethrowFromSystemServer();
}
// 監控GC操作; 當程序內的一些Activity發生變化,同時記憶體佔用量較大時
// 通知AMS釋放一些Activity
// Watch for getting close to heap limit.
BinderInternal.addGcWatcher(new Runnable() {
@Override public void run() {
if (!mSomeActivitiesChanged) {
return;
}
Runtime runtime = Runtime.getRuntime();
long dalvikMax = runtime.maxMemory();
long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();
// 判斷記憶體佔用量是否過大
if (dalvikUsed > ((3*dalvikMax)/4)) {
if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)
+ " total=" + (runtime.totalMemory()/1024)
+ " used=" + (dalvikUsed/1024));
mSomeActivitiesChanged = false;
try {
// 通知AMS釋放一些Activity,以緩解記憶體緊張
mgr.releaseSomeActivities(mAppThread);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
});
} else {
// SystemServer程序為了融入Android體系,呼叫createSystemContext函式。
// 在createSystemContext函式中,SystemServer程序建立了自己的ActivityThread,並呼叫了attach函式。
// 下面處理的是SystemServer程序
// Don't set application object here -- if the system crashes,
// we can't display an alert, we just want to die die die.
android.ddm.DdmHandleAppName.setAppName("system_process",
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
mInstrumentation.basicInit(this);
ContextImpl context = ContextImpl.createAppContext(
this, getSystemContext().mPackageInfo);
mInitialApplication = context.mPackageInfo.makeApplication(true, null);
mInitialApplication.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
....
}
2. AMS的attachApplication函式
接下來通過Binder呼叫AMS的attachApplication函式,我們從應用程序又回到了SystemServer的AMS中.由於該函式比較長我們分段分析。
2.1 Part-I
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService
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);
Binder.restoreCallingIdentity(origId);
}
}
----------------------------------------------------------------------------------------------------------------------------------------------------------
private final boolean attachApplicationLocked(IApplicationThread thread,
int pid, int callingUid, long startSeq) {
// 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;
long startTime = SystemClock.uptimeMillis();
if (pid != MY_PID && pid >= 0) {
synchronized (mPidsSelfLocked) {
// 根據pid查詢對應的ProcessRecord物件
app = mPidsSelfLocked.get(pid);
}
} else {
app = null;
}
// 如果無法根據pid查詢到對應的ProcessRecord則從mPendingStarts列表中查詢
// It's possible that process called attachApplication before we got a chance to
// update the internal state.
if (app == null && startSeq > 0) {
final ProcessRecord pending = mPendingStarts.get(startSeq);
if (pending != null && pending.startUid == callingUid
&& handleProcessStartedLocked(pending, pid, pending.usingWrapper,
startSeq, true)) {
app = pending;
}
}
// 如果程序由AMS啟動,則它在AMS中一定有對應的ProcessRecord
// 此處app為null,則表示AMS沒有該程序的記錄,故需要kill掉此異常程序
if (app == null) {
Slog.w(TAG, "No pending application record for pid " + pid
+ " (IApplicationThread " + thread + "); dropping process");
EventLog.writeEvent(EventLogTags.AM_DROP_PROCESS, pid);
if (pid > 0 && pid != MY_PID) {
killProcessQuiet(pid);
//TODO: killProcessGroup(app.info.uid, pid);
} else {
// pid < 0時,fork程序失敗,因此僅上層完成清理工作即可
// 呼叫ApplicationThread的scheduleExit函式
// 應用程序將進行一些掃尾工作,例如結束訊息迴圈,然後退出執行
try {
thread.scheduleExit();
} catch (Exception e) {
// Ignore exceptions.
}
}
return false;
}
// 判斷pid對應processRecord的IApplicationThread是否為null
// AMS建立ProcessRecord後,在attach之前,正常情況下IApplicationThread應該為null
// 特殊情況下:如果舊應用程序被殺死,底層對應的pid被釋放,在通知到達AMS之前(AMS在下面的程式碼裡註冊了“訃告”接收物件),
// 使用者又啟動了一個新的程序,新程序剛好分配到舊程序的pid時
// 此處得到的processRecord可能就是舊程序的,於是app.thread可能不為null,因此需要作判斷和處理
// If this application record is still attached to a previous
// process, clean it up now.
if (app.thread != null) {
handleAppDiedLocked(app, true, true);
}
// Tell the process all about itself.
if (DEBUG_ALL) Slog.v(
TAG, "Binding process pid " + pid + " to record " + app);
// 建立一個“訃告”接收物件,註冊到應用程序的ApplicationThread中
// 當應用程序退出時,該物件的binderDied將被呼叫,這樣AMS就能做相應的處理
// binderDied函式將在另一個執行緒中被呼叫,其內部也會呼叫handleAppDiedLocked函式
final String processName = app.processName;
try {
AppDeathRecipient adr = new AppDeathRecipient(
app, pid, thread);
thread.asBinder().linkToDeath(adr, 0);
app.deathRecipient = adr;
} catch (RemoteException e) {
app.resetPackageList(mProcessStats);
startProcessLocked(app, "link fail", processName);
return false;
}
EventLog.writeEvent(EventLogTags.AM_PROC_BOUND, app.userId, app.pid, app.processName);
// 設定app的一些變數,例如排程優先順序和oom_adj相關的成員
app.makeActive(thread, mProcessStats);
app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
app.forcingToImportant = null;
updateProcessForegroundLocked(app, false, false);
app.hasShownUi = false;
app.debugging = false;
app.cached = false;
app.killedByAm = false;
app.killed = false;
// We carefully use the same state that PackageManager uses for
// filtering, since we use this flag to decide if we need to install
// providers when user is unlocked later
app.unlocked = StorageManager.isUserKeyUnlocked(app.userId);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
至此,attachApplicationLocked的第一部分介紹完畢。
這部分程式碼的核心功能比較簡單,其實就是:
1. 判斷程序的有效性,同時註冊觀察者監聽程序的死亡訊號。
2. 設定pid對應的ProcessRecord物件的一些成員變數,例如和應用程序互動的IApplicationThread物件、程序排程的優先順序等。
2.2 Part-II
下面我們看看attachApplicationLocked第二部分的程式碼:
// frameworks/base/services/core/java/com/android/server/am/ActivityManagerService
// AMS正常啟動後,mProcessesReady就已經變為true了
boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
// generateApplicationProvidersLocked將通過PKMS查詢定義在程序中的ContentProvider,並將其儲存在AMS的資料結構中
List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
//這裡應該是處理:載入ContentProvider時,啟動程序的場景
//checkAppInLaunchingProvidersLocked主要將當前啟動程序的ProcessRecord,和AMS中mLaunchingProviders的ProcessRecord進行比較
//當判斷出該程序是由於啟動ContentProvider而被載入的,那麼就傳送一個延遲訊息(10s)
//通過這裡可以看出,當由於載入ContentProvider啟動程序時,在程序啟動後,ContentProvider在10s內要完成釋出
if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
msg.obj = app;
mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
}
checkTime(startTime, "attachApplicationLocked: before bindApplication");
// 獲取App的資訊,準備bindApplication的引數
...
if (app.isolatedEntryPoint != null) {
// This is an isolated process which should just call an entry point instead of
// being bound to an application.
thread.runIsolatedEntryPoint(app.isolatedEntryPoint, app.isolatedEntryPointArgs);
} else if (app.instr != null) {
// 回撥程序ApplicationThread的bindApplication介面
thread.bindApplication(processName, appInfo, providers,
app.instr.mClass,
profilerInfo, app.instr.mArguments,
app.instr.mWatcher,
app.instr.mUiAutomationConnection, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
} else {
thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
null, null, null, testMode,
mBinderTransactionTrackingEnabled, enableTrackAllocation,
isRestrictedBackupMode || !normalMode, app.persistent,
new Configuration(getGlobalConfiguration()), app.compat,
getCommonServicesLocked(app.isolated),
mCoreSettingsObserver.getCoreSettingsLocked(),
buildSerial, isAutofillCompatEnabled);
}
if (profilerInfo != null) {
profilerInfo.closeFd();
profilerInfo = null;
}
checkTime(startTime, "attachApplicationLocked: immediately after bindApplication");
// 更新程序排程策略
updateLruProcessLocked(app, false, null);
checkTime(startTime, "attachApplicationLocked: after updateLruProcessLocked");
app.lastRequestedGc = app.lastLowMemory = SystemClock.uptimeMillis();
} catch (Exception e) {
...
}
從程式碼來看,第二階段最核心工作就是:
呼叫程序ApplicationThread的bindApplication函式,接下來我們分析一下該函式。
2.2.1 ApplicationThread的bindApplication函式
從之前的程式碼,我們知道應用程序由zygote fork得到,然後呼叫ActivityThread的main函式,進入到Java世界。在Process.java通知zygote fork程序的時候並沒有包含任何與Activity相關的資訊,也就是說該程序並沒有融入到Android的體系中,因此僅能被稱為一個Java程序,甚至連程序名也只是“敷衍”地定義為“pre-initialized”。
此處的bindApplication函式,就是在新程序中建立並初始化對應的Android執行環境。
現在,我們看看bindApplication函式的主要流程:
// frameworks/base/core/java/android/app/ActivityThread.java
public final void bindApplication(String processName, ApplicationInfo appInfo,
List<ProviderInfo> providers, ComponentName instrumentationName,
ProfilerInfo profilerInfo, Bundle instrumentationArgs,
IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableBinderTracking, boolean trackAllocation
相關推薦
Android9.0 Activity啟動流程分析(二)
文章目錄
1、ActivityThread的main函式
2. AMS的attachApplication函式
2.1 Part-I
2.2 Part-II
2.2.1 ApplicationThread的bindApp
Android9.0 Activity啟動流程分析(一)
1、ActivityRecord、TaskRecord、ActivityStack和ActivityDisplay介紹
本篇文章是基於Android refs/tags/android-9.0.0_r8分支的程式碼進行分析的 在分析Activity啟動的原始碼之前先介紹一下Act
ContentProvider啟動流程分析(二)
## 0x01 扯東扯西的前言&概述
## 0x02 ContentProvider啟動流程分析
step6: ActivityManagerProxy#getContentProvider()
代理類ActivityManagerProxy位於ActivityManagerNative.j
springboot啟動流程分析(二)
現在繼續看啟動過程的詳情,詳細描述下SpringApplication建構函式:
1.載入過程中的SpringApplication初始化如下:
public SpringApplication(ResourceLoader resourceLoader
SpringBoot啟動流程分析(二):SpringApplication的run方法
SpringBoot系列文章簡介
SpringBoot原始碼閱讀輔助篇:
Spring IoC容器與應用上下文的設計與實現
SpringBoot啟動流程原始碼分析:
SpringBoot啟動流程分析(一):SpringApplication類初始化過程
SpringBoot啟動流程分析(二)
Activity啟動流程分析(基於android 5.1)
最近由於工作需要,需要深入瞭解AMS的內部實現。說老實話,雖然已經經過了幾輪重構,AMS的程式碼還是又臭又長。。。
萬事開頭難,先找個入口開始看吧。當從Launcher介面點選啟動一個app時,會啟動一個新的activity。所以就從startActivity()看起,研究
[Android6.0][RK3399] 雙屏異顯程式碼實現流程分析(二)
Platform: RK3399
OS: Android 6.0
Version: v2016.08
LCD interface: eDP + mipi
Patch Code
Date: Fri, 09 Dec 2016 10:53:11
AliOS Things的啟動過程分析(二)
AliOS Things的啟動過程分析(二)
在AliOS Things的啟動過程分析(一)中分析了developerkit從系統上電到呼叫main函式所經歷的一些步驟,接下來詳細分析一下main函式的一些工作,主要是核心的相關初始化工作。main函式所處的位置位於  
HBase原始碼分析之HRegion上compact流程分析(二)
2016年03月03日 21:38:04 辰辰爸的技術部落格 閱讀數:2767
版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/lipeng_bigdata/article/details/50791205
dart 非同步事件執行流程分析(二)
// use two list to test the async envet exe order.
// one record the emitted order;
// and the other record the captured order;
import 'dart:
nu-lb-nuc140 RTX 流程 分析(二)
0 參考資料
http://www.stmcu.org.cn/module/forum/thread-605101-1-1.html 【安富萊】【RTX作業系統教程】第18章 記憶體管理
1 巨集定義
__TARGET_ARCH_6S_M __USE_EXCLUSIVE_AC
ContentProvider啟動流程分析(三)
## 0x01 扯東扯西的前言&概述
## 0x02 ContentProvider啟動流程分析
step15: ApplicationThread#bindApplication()
上一步,在ApplicationThreadProxy類的bindApplication()函式中,通過B
ContentProvider啟動流程分析(一)
## 0x01 扯東扯西的前言&概述
作為安卓設計的四大元件之一,是跨程序共享資料的一把利器,所謂跨程序共享資料,通俗理解就是,應用程式A可以訪問操作應用程式B共享出來的資料,這些共享出來的資料一般都有其對應的URI(統一資源識別符號),那麼就涉及到兩個過程:
提供資料內容的過程:
A應用(
springboot啟動流程分析(一)
以springboot 2.0.2.RELEASE版本為例
1.pom.xml引入依賴
<parent>
<groupId>org.springframework.boot</groupId>
Oracle11g RAC 啟動流程梳理(二)OHASD簡析和啟停實驗
簡單說明:
11gRAC啟動分為四個層次,第一個層次是OHASD和子代理程序啟動:
init——>init.ohasd——>ohasd——>agent子程序啟動
即:
OS啟動——>/etc/rc.d/init.d/init.o
(O)Telephony分析之通話流程分析(二)撥打電話流程分析(上)
撥打電話,是從通話的撥號盤開始的,而撥號盤的介面是在DialpadFragment,因此,需要從這個地方進行分析一.撥號盤介面撥號流程
public void onClick(View view) {
......
if (resId == R.id.dia
Activity啟動流程筆記(一)
從startActivity開始說起:
public void startActivity(Intent intent, Bundle options) {
if (options != null) {
startA
Android 呼吸燈流程分析(二)
一、Android呼吸燈Driver實現
1、註冊驅動
程式碼位置:mediatek/kernel/drivers/leds/leds_drv.c
602static struct platform_driver mt65xx_leds_drive
Quartz原始碼——scheduler.start()啟動原始碼分析(二)
scheduler.start()是Quartz的啟動方式!下面進行分析,方便自己檢視!
我都是分析的jobStore 方式為jdbc的SimpleTrigger!RAM的方式類似分析方式!
解釋:
{0} : 表的字首 ,如表qrtz_
Android OTA升級原理和流程分析(二)---update.zip差分包問題的解決
Android OTA升級原理和流程分析(二)—update.zip差分包問題的解決
在上一篇末尾提到的生成差分包時出現的問題,現已解決,由於最近比較忙,相隔的時間也比較長,所以單列一個篇幅提示大家。這個問題居然是原始碼中的問題,可能你已經制作成功了,不過我的