開機流程
Step 1啓動電源以及系統啓動
當電源按下,引導芯片代碼開始從預定義的地方(固化在ROM)開始執行。加載引導程序到RAM,然後執行。
Step2 : bootloader
引導程序是在Android操作系統開始運行前的一個小程序。引導程序是運行的第一個程序,因此它是針對特定的主板與芯片的。
引導程序分兩個階段執行。第一個階段,檢測外部的RAM以及加載對第二階段有用的程序;第二階段,引導程序設置網絡、內存等等。這些對於運行內核是必要的,爲了達到特殊的目標,引導程序可以根據配置參數或者輸入數據設置內核。
Android引導程序可以在bootable\bootloader
。
Step3: kernel
內核啓動時,設置緩存、被保護存儲器、計劃列表,加載驅動。當內核完成系統設置,它首先在系統文件中尋找”init”文件,然後啓動root進程或者系統的第一個進程。
Step4:init進程
init是第一個進程,我們可以說它是root進程或者說有進程的父進程。init進程有兩個責任,一是掛載目錄,比如/sys、/dev、/proc,二是運行init.rc腳本。
-
init進程可以在
/system/core/init
找到。 -
init.rc文件可以在
/system/core/rootdir/init.rc
。
Step 5 : Native service 啓動
在此階段,會啓動android Native service 包括 Zygote,sufaceFlinger,media server,bootanimation 等。
Step 6:Javaservice 啓動
在此階段,android 會啓動java的service。並進行package的掃描,包括所有的app以及其所有的package,並且會 check所有的app是否進行了oat的優化如果沒有則進行oat的優化。
Step 7:啓動Home界面
一旦系統服務在內存中跑起來了,Android便啓動home界面。Home界面啓動完成後,會check
wallpaper和 keygurd 是否 draw 完,如果已經draw完,則會設置service.bootanim.exit
爲1,然後bootanimation 結束,界面顯示完畢。
Debug
從上面的流程知道,開機問題分爲kernel
部分和user
space 部分,下面討論之。
Kernel
Kernel 又可分爲兩部分,包括bootloader 部分和driver 加載部分。
-
bootloader
我們可以從dmesg 中發現bootloder的KPI並且計算其時間如:
[ 0.416193] KPI: Bootloader start count = 23762 //A 爲LK 開始時間
[ 0.416205] KPI: Bootloader end count = 239354 //B 爲LK 結束時間
[ 0.416212] KPI: Bootloader display count = 37127
[ 0.416219] KPI: Bootloader load kernel count = 2321
[ 0.416226] KPI: Kernel XXX timestamp = 260735 // C bootloader 完成時間
[ 0.416232] KPI: Kernel XXX Clock frequency = 32768 //D clock
我們可以通過下面的算法來確認相關的時間。如果發現時間太長,請debug 相關部分。
Step1 時間:A/D=23762 /32768=0.72s
LK 時間:(B-A)/D=(239354-23762 )/32768=6.57s
Bootloader 時間:C/D-kmsg(C)= 260735 /32768-0.416226=7.54s
需要注意的是如果是eng 版本Bootloader的時間會多增加5s。
-
driver
在上面linux啓動階段(step3),linux會加載很多driver,以及console等。加載console是比較耗時的操作(0.5s到4s),所以如果沒有必要,可以去掉console來優化啓動時間。對於其他driver需要注意的是touchdriver,camera sensor,LCD driver。
我們也可以通過添加打印module init的log,來check每個module初始化時的時間。從而找到花費時間比較多的module。
--- a/init/main.c
+++ b/init/main.c
@@ -785,7 +785,7 @@ int __init_or_module
do_one_initcall(initcall_t fn)
if (initcall_blacklisted(fn))
return
-EPERM;
- if (initcall_debug)
+ if (1)
ret =
do_one_initcall_debug(fn);
static int __init_or_module do_one_initcall_debug(initcall_t fn)
{
ktime_t calltime, delta, rettime;
unsigned long long duration;
int ret;
printk(KERN_DEBUG "calling
%pF @ %i\n", fn, task_pid_nr(current));
calltime = ktime_get();
ret = fn();
rettime = ktime_get();
delta = ktime_sub(rettime, calltime);
duration = (unsigned long long) ktime_to_ns(delta) >> 10;
printk(KERN_DEBUG "initcall
%pF returned %d after %lld usecs\n",
fn, ret, duration);
return ret;
}
User Space
adb logcat -v threadtime -b events > logcat_envents.txt
adb logcat -v threadtime > logcat.txt
Boot Event
我們可以通過查看event來確定是哪部分花時比較多。
// user space 開始時間
07-06 22:18:00.136 I/boot_progress_start( 407): 15528 //systemclock.uptimemillis(),開機到當前時間,毫秒。
//Zygote 進程preload 開始時間 32bit zygote
07-06 22:18:03.846 I/boot_progress_preload_start( 407): 19238
//Zygote 進程preload 開始時間64bit zygote
07-06 22:18:04.551 I/boot_progress_preload_start( 408): 19943
//Zygote 進程preload 結束時間32bit zygot
07-06 22:18:06.313 I/boot_progress_preload_end( 407): 21705
//Zygote 進程preload 結束時間64bit zygote
07-06 22:18:06.356 I/boot_progress_preload_end( 408): 21747
//System server 開始運行時間
07-06 22:18:06.462 I/boot_progress_system_run( 2182): 21853
//Package Scan 開始
07-06 22:18:06.784 I/boot_progress_pms_start( 2182): 22176
//System 目錄開始scan
07-06 22:18:06.899 I/boot_progress_pms_system_scan_start(2182): 22290
//data 目錄開始scan
07-06 22:18:38.644 I/boot_progress_pms_data_scan_start(2182): 54036
//package scan 結束時間
07-06 22:18:38.660 I/boot_progress_pms_scan_end( 2182):54052
//package manager ready
07-06 22:18:38.882 I/boot_progress_pms_ready( 2182): 54274
//Activity manager ready,這個事件之後便會啓動home Activity。
07-06 22:21:40.221 I/boot_progress_ams_ready( 2182): 235613
//HomeActivity 啓動完畢,系統將檢查目前所有的window是否畫完,如果所有的window(包括wallpaper, Keyguard 等)都已經畫好,系統會設置屬性service.bootanim.exit值爲1.並且trigger下面的event。
07-06 22:21:52.740 I/boot_progress_enable_screen( 2182):248132
Code://
void enableScreenAfterBoot() {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,SystemClock.uptimeMillis()); //sent boot_progress_enable_screen
mWindowManager.enableScreenAfterBoot(); //結束 bootanimation
synchronized (this) {
updateEventDispatchingLocked();
}
}
public void enableScreenAfterBoot()
{
synchronized(mWindowMap) {
if (DEBUG_BOOT) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
....
}
if (mSystemBooted) {
return;
}
mH.sendEmptyMessageDelayed(H.BOOT_TIMEOUT, 30*1000);
}
mPolicy.systemBooted();
performEnableScreen();
//here 設置bootanimation exit
}
public void performEnableScreen()
{
synchronized(mWindowMap) {
...
if (mDisplayEnabled) {
return;
}
if (!mSystemBooted && !mShowingBootMessages) {
return;
}
// Don't enable
the screen until all existing windows have been drawn.
if (!mForceDisplayEnabled && checkWaitingForWindowsLocked()) {
return;
}
if (!mBootAnimationStopped)
{
// Do this one time.
try {
IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
if (surfaceFlinger != null) {
...
Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION,
// BOOT_FINISHED
data, null, 0);
data.recycle();
}
} catch (RemoteException ex) {
Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
}
mBootAnimationStopped = true;
}
....
}
status_t BnSurfaceComposer::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
.....
case BOOT_FINISHED:
{
CHECK_INTERFACE(ISurfaceComposer, data, reply);
bootFinished();
return NO_ERROR;
}
void SurfaceFlinger::bootFinished()
{
const nsecs_t now = systemTime();
const nsecs_t duration = now - mBootTime;
ALOGI("Boot is finished (%ld ms)", long(ns2ms(duration)) );
mBootFinished = true;
// wait patiently for the window manager death
const String16 name("window");
sp<IBinder> window(defaultServiceManager()->getService(name));
if (window != 0) {
window->linkToDeath(static_cast<IBinder::DeathRecipient*>(this));
}
// stop boot animation
// formerly we would just kill the process, but we now ask it to exit so it
// can choose where to stop the animation.
property_set("service.bootanim.exit",
"1");
}
Bootanimation
在開機啓動過程中,bootanimation在surfaceflinger實例化時啓動,在其運行過程中會擇機檢查是否可以退出(service.bootanim.exit=1),如果可以退出則會根據bootanimation
的config退出。有時,當service.bootanim.exit=1時,bootanimation沒有及時退出。我們就需要檢查其原因。
http://qoofan.com/read/R84bR212ld.html