android應用啟動過程
『壹』 android應用程序啟動後閃了一下就關閉了是怎麼了什麼原因導致的求高級編程人員解答,醬油勿來。。
有可能是程序內部做了某種判斷,在判斷失敗後直接退出程序,比如在啟動過程中判斷SD卡是否存在,有的程序在在判斷的過程中如果沒有找到SD卡的話會直接退出程序。如果是程序出錯的話一般情況下都會彈出「Force close」的對話框或者"application no response"的對話框(此對話框會提示用戶是等待還是關閉程序)
『貳』 如何優化 android 系統應用的啟動速度
一、應用的啟動
啟動方式
通常來說,在安卓中應用的啟動方式分為兩種:冷啟動和熱啟動。
1、冷啟動:當啟動應用時,後台沒有該應用的進程,這時系統會重新創建一個新的進程分配給該應用,這個啟動方式就是冷啟動。
2、熱啟動:當啟動應用時,後台已有該應用的進程(例:按back鍵、home鍵,應用雖然會退出,但是該應用的進程是依然會保留在後台,可進入任務列表查看),所以在已有進程的情況下,這種啟動會從已有的進程中來啟動應用,這個方式叫熱啟動。
- adb shell am start -W [packageName]/[packageName.MainActivity]
特點
1、冷啟動:冷啟動因為系統會重新創建一個新的進程分配給它,所以會先創建和初始化Application類,再創建和初始化MainActivity類(包括一系列的測量、布局、繪制),最後顯示在界面上。
2、熱啟動:熱啟動因為會從已有的進程中來啟動,所以熱啟動就不會走Application這步了,而是直接走MainActivity(包括一系列的測量、布局、繪制),所以熱啟動的過程只需要創建和初始化一個MainActivity就行了,而不必創建和初始化Application,因為一個應用從新進程的創建到進程的銷毀,Application只會初始化一次。
上面說的啟動是點擊app的啟動圖標來啟動的,而另外一種方式是進入最近使用的列表界面來啟動應用,這種不應該叫啟動,應該叫恢復。
二、應用啟動的流程
在安卓系統上,應用在沒有進程的情況下,應用的啟動都是這樣一個流程:當點擊app的啟動圖標時,安卓系統會從Zygote進程中fork創建出一個新的進程分配給該應用,之後會依次創建和初始化Application類、創建MainActivity類、載入主題樣式Theme中的windowBackground等屬性設置給MainActivity以及配置Activity層級上的一些屬性、再inflate布局、當onCreate/onStart/onResume方法都走完了後最後才進行contentView的measure/layout/draw顯示在界面上,所以直到這里,應用的第一次啟動才算完成,這時候我們看到的界面也就是所說的第一幀。
所以,總結一下,應用的啟動流程如下:
Application的構造器方法——>attachBaseContext()——>onCreate()——>Activity的構造方法——>onCreate()——>配置主題中背景等屬性——>onStart()——>onResume()——>測量布局繪制顯示在界面上。
三、測量應用啟動的時間
在上面這個啟動流程中,任何一個地方有耗時操作都會拖慢我們應用的啟動速度,而應用啟動時間是用毫秒度量的,對於毫秒級別的快慢度量我們還是需要去精確的測量到到底應用啟動花了多少時間,而根據這個時間來做衡量。
什麼才是應用的啟動時間
從點擊應用的啟動圖標開始創建出一個新的進程直到我們看到了界面的第一幀,這段時間就是應用的啟動時間。
我們要測量的也就是這段時間,測量這段時間可以通過adb shell命令的方式進行測量,這種方法測量的最為精確,命令為:
執行成功後將返回三個測量到的時間:
1、ThisTime:一般和TotalTime時間一樣,除非在應用啟動時開了一個透明的Activity預先處理一些事再顯示出主Activity,這樣將比TotalTime小。
2、TotalTime:應用的啟動時間,包括創建進程+Application初始化+Activity初始化到界面顯示。
3、WaitTime:一般比TotalTime大點,包括系統影響的耗時。
下面是測量一個應用冷啟動和熱啟動的時間:
冷啟動:
熱啟動:
以上就是本文的全部內容,希望對大家學習Android軟體編程有所幫助。
『叄』 Android啟動過程深入解析
當按下Android設備電源鍵時究竟發生了什麼?
Android的啟動過程是怎麼樣的?
什麼是linux內核?
桌面系統linux內核與Android系統linux內核有什麼區別?
什麼是引導裝載程序?
什麼是Zygote?
什麼是X86以及ARM linux?
什麼是init.rc?
什麼是系統服務?
當我們想到Android啟動過程時,腦海中總是冒出很多疑問。本文將介紹Android的啟動過程,希望能幫助你找到上面這些問題的答案。
Android是一個基於Linux的開源操作系統。x86(x86是一系列的基於intel 8086 CPU的計算機微處理器指令集架構)是linux內核部署最常見的系統。然而,所有的Android設備都是運行在ARM處理器(ARM 源自進階精簡指令集機器,源自ARM架構)上,除了英特爾的Xolo設備(http://xolo.in/xolo-x900-features)。Xolo來源自凌動1.6GHz x86處理器。Android設備或者嵌入設備或者基於linux的ARM設備的啟動過程與桌面版本相比稍微有些差別。這篇文章中,我將解釋Android設備的啟動過程。深入linux啟動過程是一篇講桌面linux啟動過程的好文。
當你按下電源開關後Android設備執行了以下步驟。
此處圖片中step2中的一個單詞拼寫錯了,Boot Loaeder應該為Boot Loader(多謝@jameslast 提醒)
第一步:啟動電源以及系統啟動
當電源按下,引導晶元代碼開始從預定義的地方(固化在ROM)開始執行。載入引導程序到RAM,然後執行。
第二步:引導程序
引導程序是在Android操作系統開始運行前的一個小程序。引導程序是運行的第一個程序,因此它是針對特定的主板與晶元的。設備製造商要麼使用很受歡迎的引導程序比如redboot、uboot、qi bootloader或者開發自己的引導程序,它不是Android操作系統的一部分。引導程序是OEM廠商或者運營商加鎖和限制的地方。
引導程序分兩個階段執行。第一個階段,檢測外部的RAM以及載入對第二階段有用的程序;第二階段,引導程序設置網路、內存等等。這些對於運行內核是必要的,為了達到特殊的目標,引導程序可以根據配置參數或者輸入數據設置內核。
Android引導程序可以在找到。
傳統的載入器包含的個文件,需要在這里說明:
init.s初始化堆棧,清零BBS段,調用main.c的_main()函數;
main.c初始化硬體(鬧鍾、主板、鍵盤、控制台),創建linux標簽。
更多關於Android引導程序的可以在這里了解。
第三步:內核
Android內核與桌面linux內核啟動的方式差不多。內核啟動時,設置緩存、被保護存儲器、計劃列表,載入驅動。當內核完成系統設置,它首先在系統文件中尋找」init」文件,然後啟動root進程或者系統的第一個進程。
第四步:init進程
init是第一個進程,我們可以說它是root進程或者說有進程的父進程。init進程有兩個責任,一是掛載目錄,比如/sys、/dev、/proc,二是運行init.rc腳本。
init進程可以在/system/core/init找到。
init.rc文件可以在/system/core/rootdir/init.rc找到。
readme.txt可以在/system/core/init/readme.txt找到。
對於init.rc文件,Android中有特定的格式以及規則。在Android中,我們叫做Android初始化語言。
Action(動作):動作是以命令流程命名的,有一個觸發器決定動作是否發生。
語法
1
2
3
4
5
; html-script: false ]
on <trigger>
<command>
<command>
<command>
Service(服務):服務是init進程啟動的程序、當服務退出時init進程會視情況重啟服務。
語法
1
2
3
4
5
; html-script: false ]
service <name> <pathname> [<argument>]*
<option>
<option>
...
Options(選項)
選項是對服務的描述。它們影響init進程如何以及何時啟動服務。
咱們來看看默認的init.rc文件。這里我只列出了主要的事件以及服務。
Table
Action/Service
描述
on early-init
設置init進程以及它創建的子進程的優先順序,設置init進程的安全環境
on init
設置全局環境,為cpu accounting創建cgroup(資源控制)掛載點
on fs
掛載mtd分區
on post-fs
改變系統目錄的訪問許可權
on post-fs-data
改變/data目錄以及它的子目錄的訪問許可權
on boot
基本網路的初始化,內存管理等等
service servicemanager
啟動系統管理器管理所有的本地服務,比如位置、音頻、Shared preference等等…
service zygote
啟動zygote作為應用進程
在這個階段你可以在設備的屏幕上看到「Android」logo了。
第五步
在java中,我們知道不同的虛擬機實例會為不同的應用分配不同的內存。假如Android應用應該盡可能快地啟動,但如果Android系統為每一個應用啟動不同的Dalvik虛擬機實例,就會消耗大量的內存以及時間。因此,為了克服這個問題,Android系統創造了」Zygote」。Zygote讓Dalvik虛擬機共享代碼、低內存佔用以及最小的啟動時間成為可能。Zygote是一個虛擬器進程,正如我們在前一個步驟所說的在系統引導的時候啟動。Zygote預載入以及初始化核心庫類。通常,這些核心類一般是只讀的,也是Android SDK或者核心框架的一部分。在Java虛擬機中,每一個實例都有它自己的核心庫類文件和堆對象的拷貝。
Zygote載入進程
載入ZygoteInit類,源代碼:/frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
registerZygoteSocket()為zygote命令連接注冊一個伺服器套接字。
preloadClassed 「preloaded-classes」是一個簡單的包含一系列需要預載入類的文本文件,你可以在/frameworks/base找到「preloaded-classes」文件。
preloadResources() preloadResources也意味著本地主題、布局以及android.R文件中包含的所有東西都會用這個方法載入。
在這個階段,你可以看到啟動動畫。
第六步:系統服務或服務
完成了上面幾步之後,運行環境請求Zygote運行系統服務。系統服務同時使用native以及java編寫,系統服務可以認為是一個進程。同一個系統服務在Android SDK可以以System Services形式獲得。系統服務包含了所有的System Services。
Zygote創建新的進程去啟動系統服務。你可以在ZygoteInit類的」startSystemServer」方法中找到源代碼。
核心服務:
啟動電源管理器;
創建Activity管理器;
啟動電話注冊;
啟動包管理器;
設置Activity管理服務為系統進程;
啟動上下文管理器;
啟動系統Context Providers;
啟動電池服務;
啟動定時管理器;
啟動感測服務;
啟動窗口管理器;
啟動藍牙服務;
啟動掛載服務。
其他服務:
啟動狀態欄服務;
啟動硬體服務;
啟動網路狀態服務;
啟動網路連接服務;
啟動通知管理器;
啟動設備存儲監視服務;
啟動定位管理器;
啟動搜索服務;
啟動剪切板服務;
啟動登記服務;
啟動壁紙服務;
啟動音頻服務;
啟動耳機監聽;
啟動AdbSettingsObserver(處理adb命令)。
第七步:引導完成
一旦系統服務在內存中跑起來了,Android就完成了引導過程。在這個時候「ACTION_BOOT_COMPLETED」開機啟動廣播就會發出去。
『肆』 安卓模擬器啟動運行的具體過程是怎樣的
BlueStacks
xp用戶需先安裝Windows Installer 4.5和.NET Framework 2.0 SP2
基礎版安卓模擬器(BlueStacks)Beta-1版參見PC6
安卓模擬器BlueStacks安裝使用教程--pc6資訊
bluestacks app player版本不一,最新版bluestacks app player模擬器 0.7.8.829 beta 版 102.7 MB
已經安裝過因為注冊列表已注入WINDOWS,有些版本限制了重復安裝,只有重做系統。
這個模擬器對系統和電腦配置要求都很挑剔,有時安裝成功未必可以運行軟體應用,能否成功還是要看電腦配置和版本兼容性
望採納。
『伍』 Android 10.0 Activity的啟動流程
本文主要學習記錄,基於Android 10的源碼,有錯誤歡迎指正,主要目的是梳理流程圖。
以進程為單位的調用棧圖如下:
1.activity中的startActivity方法最終都會通過拿到ATSM的代理IActivityTaskManager調用的startActivity;
2.之後進入system server進程中的ATMS startActivity,ATMS 經過收集Intent信息,然後使用ActivityStackSupervisor.startSpecificActivityLocked,如果進程已經存在,則直接使用realStartActivityLocked,通過App的binder客戶端的代理ApplicationThread調用回到bindApplication,走入Activity的啟動流程;如果進程不存在則通過socket鏈接Zygote,請求fork新的進程;
3.App進程創建完成後,進程啟動會調用ActivityThread.main方法,初始化主線程Handler,接著走入attach方法,然後通過AMS的代理調用AMS的attachApplication方法,並將App進程的通信代理ApplicationThread傳入AMS;
4.AMS獲取到ATMS調用ApplicationThread的bindApplication回到App進程的ActivityThread.ApplicationThread.bindApplication方法中,然後使用Handler切換到主線程執行handleBindApplication,這里初始化了App的進程名字、時間,用戶的硬體配置,包括App的文件系統,創建了App的Context實例,Instrumentation實例,調用App的onCreate回調方法,同時告訴AMS APP初始化工作完畢;
5.AMS接著會調用ATMS的attachApplication,最後調用ClientLifecycleManager的scheleTransaction方法,通過App的Binder代理ApplicationThread回到ActivityThread;
6.進入ActivityThread.ApplicationThread.scheleTransaction方法之後就進入了Activity的onStart、onResume回調
創建進程之前的過程主要是AMS的內部信息收集的判斷的過程,下面主要看一下App進程啟動的源碼流程
從應用進程被創建開始,ActivityThread.main被執行
調用ActivityThread的attach方法,然後將activity和AMS通信的Binder代理IApplicationThread實例傳入AMS
接著進入AMS進程,ActivityManagerService.attachApplicationLocked
1.thread.bindApplication :該方法主要講App進程的配置信息通過IApplicationThread Binder通信回傳到ActivityThread中
2.mAtmInternal.attachApplication :mAtmInternal實際就是ActivityTaskManager的實例,通過LocalServices載入
那麼這里相當於走到了ActivityTaskManagerServer的attachApplication中
先看第一條:
注意:ActivityThread中存在於Binder通信的代理--》ApplicationThread extends IApplicationThread.Stub
ActivityThread--》ApplicationThread--》bindApplication
這里的bindApplication主要初始化了AppBindData,然後發送BIND_APPLICATION給APP的主線程BIND_APPLICATION,最後執行了handleBindApplication
handleBindApplication如下:
ActivityThread--》class H extends Handler
該方法主要在App進程中對App的一些硬體資源配置申請的屬性、App的文件夾等完成App基本信息的初始化
接著看第二條:mAtmInternal.attachApplication
mAtmInternal.attachApplication最終會調用mRootActivityContainer.attachApplication(wpc)
RootActivityContainer.attachApplication
接著調用ActivityStackSupervisor.realStartActivityLocked開始創建Activity
ActivityStackSupervisor.realStartActivityLocked
創建ClientLifecycleManager和ClientTransactionHandler來輔助管理Activity的生命周期
注意
clientTransaction.addCallback是LaunchActivityItem
lifecycleItem是ResumeActivityItem
ClientLifecycleManager.scheleTransaction最終會調用ClientTransaction的schele方法
那麼這個mClient是IApplicationThread的實例,那麼此時也就回到了ActivityThread的ApplicationThread中
ActivityThread的ApplicationThread中
因為ActivityThread繼承ClientTransactionHandler,所以到了ClientTransactionHandler中
通過Handler發送消息EXECUTE_TRANSACTION到H中
接著TransactionExecutor的execute方法
LaunchActivityItem.execute方法
client其實是在ActivityThread的實例,那麼就回到了ActivityThread的handleLaunchActivity
接著調用performLaunchActivity
在performLaunchActivity中,主要是載入App的資源包,然後創建了Activity的context實例,並創建了Activity的實例,接著調用activity.attach方法,attach執行完之後調用了onCreate方法。
activity.attach
activity.attach中主要
1.創建了PhoneWindow實例
2.設置了Window介面的監聽
3.初始化了成員變數,包括線程和WindowManager
到此Oncreate已經完成,那麼OnStart和OnResume去哪了?
TransactionExecutor的execute方法
之前們只分析了executeCallbacks,接著executeLifecycleState方法
TransactionExecutor的executeLifecycleState方法
cycleToPath:lifecycleItem即為ResumeActivityItem
第一點:
int finish = lifecycleItem.getTargetState()
lifecycleItem對應ResumeActivityItem,如下:
ResumeActivityItem的getTargetState方法
對應ActivityLifecycleItem中的枚舉類型:
第二點:ActivityClientRecord中的mLifecycleState,由於在前面已經執行了handleLaunchActivity所以mLifecycleState=1
對應ActivityLifecycleItem中的枚舉類型:
PRE_ON_CREATE = 0
所以final int star = 1
接著看getLifecyclePath,此時start=1,finish=3
那麼返回的IntArray就是2
接著看performLifecycleSequence
最終執行的是handleStartActivity所以最終走到了ActivityThread的handleResumeActivity
兩點:
調用activity.performStart
調用Instrumetation.callActivityOnPostCreate
performStart方法:
調用了Instrumentation.callActivityOnStart方法:
最終到了activity的onStart方法
第二點:Instrumentation.callActivityOnPostCreate
上面主要走了cycleToPath,接著ResumeActivityItem.execute
調用了handleResumeActivity方法
handleResumeActivity最終調用performResumeActivity
調用了Instrumentation.callActivityOnResume,
到了activity.onResume()方法
參考文章: https://blog.csdn.net/u011386173/article/details/87802765
『陸』 android怎麼在launcher前啟動一個應用程序
如果你要定製一個Android系統,你想用你自己的Launcher(Home)作主界面來替換Android自帶的Home,而且不希望用戶安裝的Launcher來替換掉你的Launcher,應該如何來實現呢?
我們可以通過修改Framework層來實現這樣的功能。
1) 首先了解一下Android的啟動過程。
Android系統的啟動先從Zygote開始啟動,然後......(中間的過程就不說了).....一直到了SystemServer(framework)這個地方,看到這段代碼:
/**
* This method is called from Zygote to initialize the system. This willcause the native
* services (SurfaceFlinger, AudioFlinger, etc..) to be started. Afterthat it will call back
* up into init2() to start the Android services.
*/
native public static void init1(String[] args);
public static void main(String[] args) {
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
timer = new Timer();
timer.schele(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server");
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
}
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
System.loadLibrary("android_servers");
init1(args);
}
public static final void init2() {
Log.i(TAG, "Entered the Android system server!");
Thread thr = new ServerThread();
thr.setName("android.server.ServerThread");
thr.start();
}
}
從SystemServer的main函數開始啟動各種服務:
首先啟動init1,然後啟動init2.從上面的注釋可以看到:init1這個方法時被Zygote調用來初始化系統的,init1會啟動native的服務如SurfaceFlinger,AudioFlinger等等,這些工作做完以後會回調init2來啟動Android的service。
這里我們主要來關注init2的過程。init2中啟動ServerThread線程,ServerThread中啟動了一系列的服務,比如這些:
ActivityManagerService
EntropyService
PowerManagerService
TelephonyRegistry
PackageManagerService
AccountManagerService
BatteryService
HardwareService
Watchdog
SensorService
BluetoothService
StatusBarService
ClipboardService
InputMethodManagerService
NetStatService
ConnectivityService
AccessibilityManagerService
NotificationManagerService
MountService
DeviceStorageMonitorService
LocationManagerService
SearchManagerService
FallbackCheckinService
WallpaperManagerService
AudioService
BackupManagerService
AppWidgetService
這些大大小小的服務起來以後,開始
((ActivityManagerService)ActivityManagerNative.getDefault()).systemReady()
在systemReady後開始開始啟動Launcher。在尋找Launcher的時候是根據HOME的filter(在Manifest中定義的<categoryandroid:name="android.intent.category.HOME" />)來過濾。
然後根據filter出來的HOME來啟動,如果只有一個HOME,則啟動這個HOME,如果用戶自己裝了HOME,那就會彈出來一個列表供用戶選擇。
我們現在希望從這里彈出我們自己定製的Launcher,同時也不希望彈出選擇HOME的界面,我們不希望用戶修改我們的home,比如我們的home上放了好多廣告,以及強制安裝的程序,不希望用戶把它幹掉。
我們可以通過這樣來實現:
2) 定義一個私有的filter選項,然後用這個選項來過濾HOME.
一般情況下我們使用Manifest中定義的<categoryandroid:name="android.intent.category.HOME"來過濾的,我們現在增加一個私有的HOME_FIRST過濾。
在Intent.java(frameworks/base/core/java/android/content/Intent.java)中添加兩行代碼
//lixinso:添加CATEGORY_FS_HOME
@SdkConstant(SdkConstantType.INTENT_CATEGORY)
public static final String CATEGORY_FS_HOME= "android.intent.category.FS_HOME";
3)修改和CATEGORY_HOME相關的所有的地方,都改成CATEGORY_FS_HOME,主要是framework中的這幾個地方:使用grep命令查找要修改的地方:
grep CATEGORY_HOME -l * -R
將上述文件中和CATEGORY_HOME相關的所有的地方,都改成CATEGORY_FS_HOME。
4) 寫一個自己的Launcher.
可以參考android sample中的Launcher,或者android源代碼中的 /packages/apps/Launcher 來寫。
在Launcher中標記其是不是Launcher的最關鍵的代碼時Manifest中的filter:android:name="android.intent.category.HOME"
現在我們定義了自己的filter,那麼,我們在我們自己寫的Launcher中將Manifest改為:
<application android:process="android.process.acore3"android:icon="@drawable/icon"android:label="@string/app_name">
<activity android:name=".FirstAppActivity"
android:label="@string/app_name">
<intent-filter>
<actionandroid:name="android.intent.action.MAIN" />
<categoryandroid:name="android.intent.category. FS_HOME" />
<categoryandroid:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MONKEY"/>
</intent-filter>
</activity>
</application>
然後將編譯好的apk放到方式fs100_root/system/app目錄下。
5)將Android自帶的Launcher刪除掉
包括源代碼(packages/apps/Launcher)和apk(/out/target/proct/generic/system/app/Launcher.apk)。
6) 重新編譯Android
做完這些工作,就可以重新編譯Android了,我們可以編譯修改過的幾個相關的包,可以用mmm命令來編譯部分的改動。這里需要這樣編譯:
$ source build/envsetup.sh
$ lunch
$ mmm frameworks/base
$ mmm frameworks/base/services/java
$ mmm frameworks/policies/base/mid
$ mmm frameworks/policies/base/phone
重新啟動開發板,從開發板上就可以看到啟動的Launcher是我們自己的Launcher,不會出現默認的Launcher了,也不會出現選擇界面。
9)我們再驗證一下,如果用戶裝上了一個其他的Launcher(Home)會怎麼樣。
從網上找一個一般的Launcher或者自己寫一個一般的Launcher裝上去,重新啟動,不會出現選擇界面。
按HOME鍵也不會出來兩個HOME來選擇。
這樣我們就牢牢控制了用戶的桌面。
只有我們自己定製的HOME才能裝上。這對於定製Android設備的廠商很有用處。
『柒』 安卓應用啟動詳解:從Zygote到你的Activity.onCreate()
翻譯自: https://android.jlelse.eu/android-application-launch-explained-from-zygote-to-your-activity-oncreate-8a8f036864b
這篇文章講解當用戶點擊應用圖標時,安卓如何啟動你的應用。安卓系統做了很多幕後工作,來使得你的launch activity對用戶可見。本文通過重要階段的講解和調用序列詳細講解這一過程。
安卓應用在這兩個方面是獨特的:
多個入口點 :Android應用程序由不同的組件組成,它們可以調用其他應用程序擁有的組件。這些組件大致對應於任何應用程序的多個入口點。因此,它們不同於具有像main()方法那樣的單個入口點的傳統應用程序。
擁有自己的小世界 :每個Android應用程序都生活在自己的世界中,它在單獨的進程中運行,擁有自己的Dalvik VM實例,並分配有唯一的用戶ID。
必要時會啟動Android進程。
每當用戶或其他系統組件請求執行屬於您應用程序的組件(可能是服務,活動或意圖接收器)時,Android系統都會為您的應用程序啟動一個新進程(如果尚未運行)。通常,進程一直運行直到被系統殺死。應用程序流程是按需創建的,在您看到應用程序的啟動活動啟動並運行之前,發生了許多事情。
每個應用程序都在其自己的進程中運行 :默認情況下,每個Android應用程序都在其自己的Android進程中運行,而這個進程只不過是一個Linux進程,而該進程首先需要一個執行線程。例如,當您單擊電子郵件中的超鏈接時,網頁將在瀏覽器窗口中打開。您的郵件客戶端和瀏覽器是兩個單獨的應用程序,它們分別在兩個單獨的進程中運行。click事件使Android平台啟動新進程,以便它可以在其自身進程的上下文中實例化瀏覽器活動。這對於應用程序中的任何其他組件同樣適用。
讓我們退後一會兒,快速瀏覽一下系統啟動過程。與大多數基於Linux的系統一樣,啟動載入程序在啟動時將載入內核並啟動init進程。然後,init會生成稱為「守護程序」的低級Linux進程,例如android debug守護程序,USB守護程序等。這些守護程序通常處理低級硬體介面,包括無線電介面。
然後,初始化過程會啟動一個非常有趣的過程,稱為「zygote'。
顧名思義,這是其餘Android應用程序的開始。這是初始化Dalvik虛擬機的第一個實例的過程。它還預載入Android應用程序框架和系統上安裝的各種應用程序使用的所有常見類。因此,它准備進行復制。它統計偵聽套接字介面上的將來請求,以產生新的虛擬機(VM)來管理新的應用程序進程。收到新請求後,它會分叉以創建一個新進程,該進程將獲取預先初始化的VM實例。
zygote之後,init啟動運行時過程。
然後zygote分叉以啟動一個名為System server的託管良好的進程。系統伺服器在其自己的上下文中啟動所有核心平台服務,例如活動管理器服務和硬體服務。
此時,完整的堆棧已准備就緒,可以啟動第一個應用程序流程-主頁應用程序,該應用程序顯示主屏幕(也稱為啟動器應用程序)。
click事件被轉換為 startActivity(intent), 並通過Binder IPC路由到 ActivityManagerService 。ActvityManagerService執行多個步驟
如您所見,當用戶單擊圖標並啟動新應用程序時,許多事情發生在幕後。這是全圖:
流程創建:
ActivityManagerService 通過調用 startProcessLocked() 方法創建一個新進程,該方法通過套接字連接將參數發送到Zygote進程。Zygote派生自己並調用 ZygoteInit.main() ,然後實例化 ActivityThread 對象並返回新創建的進程的進程ID。
默認情況下,每個進程都有一個線程。主線程有一個 Looper 實例來處理來自消息隊列的消息,並且它在 run() 方法的每次迭代中都調用 Looper.loop() 。 Looper 的工作是從消息隊列中彈出消息並調用相應的方法來處理它們。然後,ActivityThread通過隨後調用 Looper.prepareLoop() 和 Looper.loop()來 啟動消息循環。
以下序列詳細捕獲了調用序列:
<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android應用啟動:單擊事件以執行Looper調用順序</figcaption>
應用程序綁定:
下一步是將此新創建的過程附加到特定應用程序。這是通過在線程對象上調用 bindApplication() 來完成的。此方法將 BIND_APPLICATION 消息發送到消息隊列。該消息由 Handler 對象檢索,該對象隨後調用 handleMessage() 方法以觸發特定於消息的操作 -handleBindApplication() 。此方法調用 makeApplication() 方法,該方法將應用程序特定的類載入到內存中。
下圖描述了該調用序列。
<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android應用啟動:BIND_APPLICATION消息處理</figcaption>
啟動活動:
在上一步之後,系統包含負責應用程序的進程,並將應用程序類載入到進程的私有內存中。在新創建的流程和現有流程之間,啟動活動的調用順序很常見。
實際的啟動過程從 realStartActivity() 方法開始, 該 方法在應用程序線程對象上調用 sheleLaunchActivity() 。此方法將 LAUNCH_ACTIVITY 消息發送到消息隊列。該消息由 handleLaunchActivity() 方法處理,如下所示。
假設用戶單擊「視頻瀏覽器」應用程序。啟動該活動的調用順序如圖所示。
<figcaption class="jv jw di dg dh jx jy bo b fc cp ga" data-selectable-paragraph="" style="box-sizing: inherit; font-weight: 400; font-family: sohne, "Helvetica Neue", Helvetica, Arial, sans-serif; line-height: 20px; margin-left: auto; margin-right: auto; max-width: 728px; font-size: 14px; color: rgb(117, 117, 117); margin-top: 10px; text-align: center;">Android應用啟動: LAUNCH_ACTIVITY消息處理 </figcaption>
該活動通過 onCreate() 方法調用開始其託管生命周期。該活動通過 onRestart() 調用進入前台,並通過 onStart() 調用開始與用戶進行交互。
『捌』 如何讓應用隨系統啟動 android
如果您是一位Java Android開發人員,那麼實現一個隨系統自啟動的應用對您來說應該非常Easy,但對於一位使用Adobe Flash技術開發應用,然後用AIR打包機制製作.APK的開發者來說,實現這個功能卻不是很輕松的。Flash的優勢就是跨平台,一位Flash開發者可以使用自身積累的知識體系,以最小的學習成本進入Android開發的世界。AIR在打包的時候對我們隱藏了很多細節,這樣一方面可以減少我們的學習阻力,一方面卻也因為這個不透明的過程造成一些困擾(後面詳述)。如果我們要實現一個功能,AIR核心API卻沒有提供實現,就成了非常麻煩的事情,不過現在好在AIR已經提供了一種擴展自己功能的機制,就是ANE。對於Android開發來說,我們可以使用Java代碼來完成AIR本身不提供的功能。
關於ANE的基本知識,您可以參閱這里(中文)
很棒的ANE for Android實例教程http://t.cn/SbsI5j跟這個過一遍就明白ANE的原理,創建過程和使用方式了。
下面我們來看看如何讓一個AIR打包的APK實現隨系統自己啟動的功能(當然也要藉助ANE了)。
APK的AndroidManifest.xml分析
在動手之前,您最好先把AIR打包產生的APK文件做一下分析,了解它的特性,後面就可以少走一些彎路。將.apk文件直接改擴展名為.zip,解壓即可看到它的結構。注意AndroidManifest.xml,這是Android應用非常核心的一個配置文件。這個文件是AIR打包自動產生的,但是和AIR應用本身的XML配置文件也是有管理的(AIR應用的XML配置中的android節點部分會被合並到AndroidManifest.xml,這樣方便我們做一些許可權設定等等)。
解壓得到的AndroidManifest.xml是個二進制的XML文檔,無法用文本工具查看,您可以先使用AXMLPrinter2.jar將它轉換為普通文本格式即可閱讀。
這個文件中我們要注意幾個細節:
1. manifest節點的package屬性不能由我們設定,這是AIR打包的時候自動設定的,規則是「air.應用ID」,比如我們的應用ID是TestAppANEs,那麼這里的設置就是package=」air.TestAppANEs」
2. 在application部分會自動產生一個activity,名稱是.AppEntry。activity相當於Android應用的視圖,AIR會自動產生一個視圖,用來承載我們的Flash內容。
了解這些細節之後,我們就可以繼續實施ANE部分的開發了。
ANE實現
創建ANE項目的過程就不細述了,您可以參閱Adobe的文檔。這里只說和隨系統啟動相關的部分。您首先要創建一個包,命名和manifest節點的package屬性保持一致,比如這里應該是air.TestAppANEs。這個地方要非常注意,包名必須遵循這樣的結構,否則運行時會找不到類。
然後在這個包中創建一個Java類:BootBroadCastReceiver,繼承BroadcastReceiver,完整代碼如下:
然後將Java項目編譯為JAR包,然後建立一個ActionScript庫項目,最終和JAR包打包為一個ANE文件(略過N多細節,請參閱Adobe文檔)。
這里再補充兩個細節問題,首先是ADT打包,ANE打包的參數確實很容易弄錯,估計第一次打包的同學很難能一次性通過,最後一個參數的點前面還有一個空格,提醒您千萬注意了 -platform Android-ARM -C .Android-ARM .
其次是您應該給extension.xml設置一個 ,並使用ActionScript實現一個模擬功能實施,並打包到ANE中,這樣方便您在PC測試,否則您會得到不支持調試的提示。
和主項目的整合
ANE製作完畢後,您可以用Flash Builder,在您的主項目上點擊右鍵,屬性,庫構建路徑,在ANE面板上,加入剛才製作的ANE文件(Flash Builder會自動在AIR應用的XML配置文件中加入這個ANE的ID,確保這個ID必須有)。然後在發布的時候,ANE的部分還有一個對勾(確定是否包含),一定記得點上,不然就會找不到類。
先別急著打包,我們還需要修改一下配置文件,打開AIR應用的XML配置文件,找到android部分,加入.BootBroadCastReceiver的定義,完整結構如下:
注意.BootBroadCastReceiver這個定義很關鍵,以.開頭才能實現隨系統啟動的功能。
然後…就沒有然後了。您可以測試您的應用,安裝後讓手機重啟,不出意外的話,您可以看到自己的應用在系統啟動完畢後,就會自己啟動並顯示主界面。
您也可以不顯示主界面,而是注冊一個Service,實現後台的通知和提醒。
『玖』 怎麼修改android 啟動過程中的第二個開機畫面
第一個開機畫面是在內核啟動的過程中出現的,它是一個靜態的畫面。第二個開機畫面是在init進程啟動的過程中出現的,它也是一個靜態的畫面。第三個開機畫面是在系統服務啟動的過程中出現的,它是一個動態的畫面。無論是哪一個畫面,它們都是在一個稱為幀緩沖區(frame buffer,簡稱fb)的硬體設備上進行渲染的。接下來,我們就分別分析這三個畫面是如何在fb上顯示的。
1. 第一個開機畫面的顯示過程
Android系統的第一個開機畫面其實是Linux內核的啟動畫面。在默認情況下,這個畫面是不會出現的,除非我們在編譯內核的時候,啟用以下兩個編譯選項:
CONFIG_FRAMEBUFFER_CONSOLE
CONFIG_LOGO
第一個編譯選項表示內核支持幀緩沖區控制台,它對應的配置菜單項為:Device Drivers ---> Graphics support ---> Console display driver support ---> Framebuffer Console support。第二個編譯選項表示內核在啟動的過程中,需要顯示LOGO,它對應的配置菜單項為:Device Drivers ---> Graphics support ---> Bootup logo。配置Android內核編譯選項可以參考在Ubuntu上下載、編譯和安裝Android最新內核源代碼(Linux Kernel)一文。
幀緩沖區硬體設備在內核中有一個對應的驅動程序模塊fbmem,它實現在文件kernel/goldfish/drivers/video/fbmem.c中,它的初始化函數如下所示:
/**
* fbmem_init - init frame buffer subsystem
*
* Initialize the frame buffer subsystem.
*
* NOTE: This function is _only_ to be called by drivers/char/mem.c.
*
*/
static int __init
fbmem_init(void)
{
proc_create("fb", 0, NULL, &fb_proc_fops);
if (register_chrdev(FB_MAJOR,"fb",&fb_fops))
printk("unable to get major %d for fb devs\n", FB_MAJOR);
fb_class = class_create(THIS_MODULE, "graphics");
if (IS_ERR(fb_class)) {
printk(KERN_WARNING "Unable to create fb class; errno = %ld\n", PTR_ERR(fb_class));
fb_class = NULL;
}
return 0;
}
這個函數首先調用函數proc_create在/proc目錄下創建了一個fb文件,接著又調用函數register_chrdev來注冊了一個名稱為fb的字元設備,最後調用函數class_create在/sys/class目錄下創建了一個graphics目錄,用來描述內核的圖形系統。
模塊fbmem除了會執行上述初始化工作之外,還會導出一個函數register_framebuffer:
EXPORT_SYMBOL(register_framebuffer);
這個函數在內核的啟動過程會被調用,以便用來執行注冊幀緩沖區硬體設備的操作,它的實現如下所示:
/**
* register_framebuffer - registers a frame buffer device
* @fb_info: frame buffer info structure
*
* Registers a frame buffer device @fb_info.
*
* Returns negative errno on error, or zero for success.
*
*/
int
register_framebuffer(struct fb_info *fb_info)
{
int i;
struct fb_event event;
......
if (num_registered_fb == FB_MAX)
return -ENXIO;
......
num_registered_fb++;
for (i = 0 ; i < FB_MAX; i++)
if (!registered_fb[i])
break;
fb_info->node = i;
mutex_init(&fb_info->lock);
fb_info->dev = device_create(fb_class, fb_info->device,
MKDEV(FB_MAJOR, i), NULL, "fb%d", i);
if (IS_ERR(fb_info->dev)) {
/* Not fatal */
printk(KERN_WARNING "Unable to create device for framebuffer %d; errno = %ld\n", i, PTR_ERR(fb_info->dev));
fb_info->dev = NULL;
} else
fb_init_device(fb_info);
......
registered_fb[i] = fb_info;
event.info = fb_info;
fb_notifier_call_chain(FB_EVENT_FB_REGISTERED, &event);
return 0;
}
由於系統中可能會存在多個幀緩沖區硬體設備,因此,fbmem模塊使用一個數組registered_fb保存所有已經注冊了的幀緩沖區硬體設備,其中,每一個幀緩沖區硬體都是使用一個結構體fb_info來描述的。
『拾』 android系統在啟動的過程中什麼時候會調用systempropertys
System Properties是怎麼一回事,又是如何實現的呢?
屬性系統是android的一個重要特性。它作為一個服務運行,管理系統配置和狀態。所有這些配置和狀態都是屬性。
每個屬性是一個鍵值對(key/value pair),其類型都是字元串。
這些屬性可能是有些資源的使用狀態,進程的執行狀態,系統的特有屬性……
可以通過命令adb shell :
getprop查看手機上所有屬性狀態值。
或者 getprop init.svc.bootanim制定查看某個屬性狀態
使用setprop init.svc.bootanim start 設置某個屬性的狀態
特別屬性 :
如果屬性名稱以「ro.」開頭,那麼這個屬性被視為只讀屬性。一旦設置,屬性值不能改變。
如果屬性名稱以「persist.」開頭,當設置這個屬性時,其值也將寫入/data/property。
如果屬性名稱以「net.」開頭,當設置這個屬性時,「net.change」屬性將會自動設置,以加入到最後修改的屬性名。
(這是很巧妙的。 netresolve模塊的使用這個屬性來追蹤在net.*屬性上的任何變化。)
屬性「 ctrl.start 」和「 ctrl.stop 」是用來啟動和停止服務。每一項服務必須在/init.rc中定義.系統啟動時,與init守護
進程將解析init.rc和啟動屬**。一旦收到設置「 ctrl.start 」屬性的請求,屬**將使用該屬性值作為服務
名找到該服務,啟動該服務。這項服務的啟動結果將會放入「 init.svc.<服務名>「屬性中。客戶端應用程序可以輪詢那個屬性值,以確定結果。