開機SystemServer到ActivityManagerService啟動過程
一 從Systemserver到AMS
zygote-> systemserver:java入層口:
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
接下來繼續看SystemServer run函數執行過程:
private void run() {
// 准備SystemServer運行環境:設置線程優先級,創建主線層Looper,ActivityThread和SystemContext
android.os.Process.setThreadPriority();
Looper.prepareMainLooper();
// 創建systemserver上進程的ActivityThread和SystemContext
createSystemContext();
// 增加SystemServiceManager:統一管理system services的創建,啟動和生命周期,多用戶切換
mSystemServiceManager = new SystemServiceManager(mSystemContext);
// Start services.
// 1.創建AMS
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
// Start the Power Manager service
mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);
// Start the package manager service
mPackageManagerService = PackageManagerService.main();
// 2.將SystemServer進程可加到AMS中調度管理
mActivityManagerService.setSystemProcess();
// 3.將相關provider運行在systemserver進程中:SettingsProvider
mActivityManagerService.installSystemProviders();
//
final Watchdog watchdog = Watchdog.getInstance();
watchdog.init(context, mActivityManagerService);
// Start Window Manager
wm = WindowManagerService.main();
// 4.直接保存wms對象,與WMS交互
mActivityManagerService.setWindowManager(wm);
// 5.通過WMS 彈出“正在啟動應用”框
// R.string.android_upgrading_starting_apps
ActivityManagerNative.getDefault().showBootMessage();
// 6. AMS作為Framework核心,做好准備就緒后就開始啟動應用層,和對AMS有依賴的服務
mActivityManagerService.systemReady(new Runnable(){
//啟動SystemUI
startSystemUi(context);
//啟動WatchDog監控核心服務狀態
Watchdog.getInstance().start();
//
mmsServiceF.systemRunning();
});
// Loop forever.
Looper.loop();
}
以上6個步驟是SystemServer中關於AMS的調用,完成AMS的創建和系統的初始化,下面按照這步驟繼續升入分析。
- 這里有個疑問:
AMS保存對象,本身就在同一個進程,WMS與WMS之間的交互式直接調用速度會更快,其他服務為何不這樣,是因為耦合太強,還是實時性要求更高?
彈出“正在啟動應用”框,這里為何不直接調用AMS的showBootMessage而是通過binder方式調用,其他接口都是直接調用,為何?直接調用有何不可嗎?
二 ActivityManagerService 創建過程
接上面SystemServer.run中:
mActivityManagerService = mSystemServiceManager.startService(
ActivityManagerService.Lifecycle.class).getService();
這是通過SystemServiceManager這樣一個模板類來創建運行在SystemServer中的Framework服務;
並將創建的服務統一保存在隊列管理,會涉及到多用戶切換。
// Note: This method is invoked on the main thread but may need to attach various
// handlers to other threads. So take care to be explicit about the looper.
public ActivityManagerService(Context systemContext) {
// 1.系統Context 和 ActivityThread (將systemserver進程作為應用進程管理)
mContext = systemContext;
mFactoryTest = FactoryTest.getMode();
mSystemThread = ActivityThread.currentActivityThread();
// 2.AMS工作的線程和Handler,處理顯示相關的UiHandler ---》知識點HandlerThread和Handler
mHandlerThread = new ServiceThread(TAG,
android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
mHandlerThread.start();
mHandler = new MainHandler(mHandlerThread.getLooper());
mUiHandler = new UiHandler();
// 3. 廣播隊列BroadcastQueue初始化:前台廣播隊列和后台廣播隊列
mFgBroadcastQueue = new BroadcastQueue(this, mHandler,"foreground", BROADCAST_FG_TIMEOUT, false);
mBgBroadcastQueue = new BroadcastQueue(this, mHandler,"background", BROADCAST_BG_TIMEOUT, true);
mBroadcastQueues[0] = mFgBroadcastQueue;
mBroadcastQueues[1] = mBgBroadcastQueue;
// 4. Service 和 Provider 管理
mServices = new ActiveServices(this);
mProviderMap = new ProviderMap(this);
// 5.系統數據存放目錄:/data/system/
File dataDir = Environment.getDataDirectory();
File systemDir = new File(dataDir, "system");
systemDir.mkdirs();
// 電池狀態信息,進程狀態 和 應用權限管理
mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);
// 6.多用戶管理
mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true));
mUserLru.add(UserHandle.USER_OWNER);
updateStartedUserArrayLocked();
// 7.最近任務,Activity,Task管理
mRecentTasks = new RecentTasks(this);
mStackSupervisor = new ActivityStackSupervisor(this, mRecentTasks);
mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, mRecentTasks);
// 創建一個新線程,用於監控和定時更新系統CPU信息,30分鍾更新一次CPU和電池信息
mProcessCpuTracker.init();
mProcessCpuThread = new Thread("CpuTracker") {}
// 加入Watchdog監控起來
Watchdog.getInstance().addMonitor(this);
Watchdog.getInstance().addThread(mHandler);
}
- 以上 AMS創建過程 涉及到Android 四大組件管理的初始化:
Broadcast --》BroadcastQueue
Provider --》ProviderMap
Service --》ActiveServices
Activity --》ActivityStackSupervisor
備注1:Android6.0上加入多用戶功能,增加了一些涉及多用戶的管理。
拓展知識點:HandlerThread,Handle,Looper
二 將SystemServer進程可加到AMS中調度管理
接上面systemserver.run中:
mActivityManagerService.setSystemProcess();
public void setSystemProcess() {
// 將服務加入到ServiceManager中
ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
ServiceManager.addService("meminfo", new MemBinder(this));
ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
ServiceManager.addService("dbinfo", new DbBinder(this));
// 設置application info LoadedApkinfo 有關 framework-res.apk
ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
"android", STOCK_PM_FLAGS);
mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());
//給SystemServer進程創建ProcessRecord,adj值,就是將SystemServer進程加入到AMS進程管理機制中,跟應用進程一致
synchronized (this) {
ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
app.persistent = true;
app.pid = MY_PID;
app.maxAdj = ProcessList.SYSTEM_ADJ;
app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.put(app.pid, app);
}
updateLruProcessLocked(app, false, null);
updateOomAdjLocked();
}
}
- setSystemProcess意義:
這一步就是給SystemServer進程創建ProcessRecord,adj值,就是將SystemServer進程加入到AMS進程管理機制中,跟應用進程一致;
進程調度更新優先級oomadj值,個人感覺SystemServer進程跟應用進程就不一樣,卻加入AMS來調度管理,這樣做的意義何在?
四 創建運行在SystemServer進程中Provider
接上面SystemServer.run中:
mActivityManagerService.installSystemProviders();
備注2: 將相關provider運行在systemserver進程中:SettingsProvider
具體安裝過程這里暫不詳述,在應用啟動過程中具體分析。
五 AMS systemReady過程
接上面SystemServer.run中:
mActivityManagerService.systemReady();
public void systemReady(final Runnable goingCallback) {
synchronized(this) {
if (mSystemReady) {
goingCallback.run();
}
……
// 1.升級相關處理:發送PRE_BOOT_COMPLETED廣播 等待升級處理完成才能繼續
// Check to see if there are any update receivers to run.
if (!mDidUpdate) {
// 等待升級完成,否則直接返回
if (mWaitingUpdate) {
return;
}
// 發送PRE_BOOT_COMPLETED廣播
final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
mWaitingUpdate = deliverPreBootCompleted(new Runnable() {
// 等待所有接收PRE_BOOT_COMPLETED廣播者處理完畢
public void run() {
synchronized (ActivityManagerService.this) {
mDidUpdate = true;
}
showBootMessage(mContext.getText(
R.string.android_upgrading_complete),
false);
// 將系統版本號和處理過的廣播寫入文件:/data/system/called_pre_boots.dat文件
writeLastDonePreBootReceivers(doneReceivers);
// 繼續systemReady流程
systemReady(goingCallback);
}
}, doneReceivers, UserHandle.USER_OWNER);
if (mWaitingUpdate) {
return;
}
mDidUpdate = true;
}
mSystemReady = true;
}
// 2. 收集已經啟動的進程並殺死,除過persistent常駐進程
ArrayList<ProcessRecord> procsToKill = null;
synchronized(mPidsSelfLocked) {
for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
ProcessRecord proc = mPidsSelfLocked.valueAt(i);
if (!isAllowedWhileBooting(proc.info)){
if (procsToKill == null) {
procsToKill = new ArrayList<ProcessRecord>();
}
procsToKill.add(proc);
}
}
}
synchronized(this) {
if (procsToKill != null) {
for (int i=procsToKill.size()-1; i>=0; i--) {
ProcessRecord proc = procsToKill.get(i);
Slog.i(TAG, "Removing system update proc: " + proc);
removeProcessLocked(proc, true, false, "system update done");
}
}
// Now that we have cleaned up any update processes, we
// are ready to start launching real processes and know that
// we won't trample on them any more.
mProcessesReady = true;
}
// 3.系統准備好后回調傳入的Runnable:
if (goingCallback != null) goingCallback.run();
// 4. 發送賬戶啟動的廣播,涉及多用戶
long ident = Binder.clearCallingIdentity();
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
broadcastIntentLocked(intent);
intent = new Intent(Intent.ACTION_USER_STARTING);
broadcastIntentLocked(intent);
Binder.restoreCallingIdentity(ident);
// 5. 啟動桌面Home Activity
mBooting = true;
startHomeActivityLocked(mCurrentUserId, "systemReady");
mStackSupervisor.resumeTopActivitiesLocked();
}
- 下面看下AMS systemReady的過程:
1. 升級相關處理:發送PRE_BOOT_COMPLETED廣播
顧名思義:只有系統做OTA升級 和 手機初次開機的時候,應當才會走此廣播,下面看看這個函數具體的處理。
接上面:
deliverPreBootCompleted(new Runnable() {
// 向PMS查詢,所有接收ACTION_PRE_BOOT_COMPLETED廣播的Receiver
Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
List<ResolveInfo> ris = null;
ris = AppGlobals.getPackageManager().queryIntentReceivers(
intent, null, 0, userId);
// 只有系統廣播才能接收該廣播,去掉非系統應用
for (int i=ris.size()-1; i>=0; i--) {
if ((ris.get(i).activityInfo.applicationInfo.flags
&ApplicationInfo.FLAG_SYSTEM) == 0) {
ris.remove(i);
}
}
// 給Intent設置flag:FLAG_RECEIVER_BOOT_UPGRADE,很關鍵這個看看flag的作用:
// 只有設置這個標志,才能讓應用在系統沒有ready的情況下啟動,見下文原始注釋
intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
// 將已經處理過ACTION_PRE_BOOT_COMPLETED廣播的Receiver去掉
// 已經處理該廣播的Receiver記錄 和 對應的系統版本號 都記錄在:/data/system/called_pre_boots.dat文件中,
// 通過與系統當前版本號比對,確認是否已處理過。考慮處理過程異常中斷的情況:比如斷電
ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
// 將已經處理過的廣播去除,同時記錄已處理過保存在 doneReceivers數組中
for (int i=0; i<ris.size(); i++) {
ActivityInfo ai = ris.get(i).activityInfo;
ComponentName comp = new ComponentName(ai.packageName, ai.name);
if (lastDoneReceivers.contains(comp)) {
// We already did the pre boot receiver for this app with the current
// platform version, so don't do it again...
ris.remove(i);
i--;
// ...however, do keep it as one that has been done, so we don't
// forget about it when rewriting the file of last done receivers.
doneReceivers.add(comp);
}
}
// 內部類專門用來ACTION_PRE_BOOT_COMPLETED廣播的發送,要看看這個PreBootContinuation類
// 這塊邏輯一直在變,Android5.0, 6.0 , 以及看到在7.0上又變了,基本思路不變,本文代碼基於Android6.0
PreBootContinuation cont = new PreBootContinuation(intent, onFinishCallback, doneReceivers,
ris, users);
cont.go();
return true;
}
給intent設置的廣播意義:
/**
* Set when this broadcast is for a boot upgrade, a special mode that
* allows the broadcast to be sent before the system is ready and launches
* the app process with no providers running in it.
* @hide
*/
public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;
- 繼續接着上面PreBootContinuation類:從繼承關系看到可以跨進程的
final class PreBootContinuation extends IIntentReceiver.Stub {
void go() {
//判斷是不是最后一個接收者
if (lastRi != curRi) {
// 疑問:如果不是最后一個接收者,則發給一個指定接收者ComponentName
// 為什么要在這里指定接收者,一個個發送,而不是交給廣播自己去處理?
ActivityInfo ai = ris.get(curRi).activityInfo;
ComponentName comp = new ComponentName(ai.packageName, ai.name);
intent.setComponent(comp);
doneReceivers.add(comp);
lastRi = curRi;
// 界面顯示正在處理的廣播,上面的指定接收者,就是為了這里能顯示正在處理的廣播名稱?
CharSequence label = ai.loadLabel(mContext.getPackageManager());
showBootMessage(mContext.getString(R.string.android_preparing_apk, label), false);
}
// 發送廣播,指定接收者處理完畢,會resultTo回來--》this
Slog.i(TAG, "Pre-boot of " + intent.getComponent().toShortString()
+ " for user " + users[curUser]);
broadcastIntentLocked(null, null, intent, null, this,
0, null, null, null, AppOpsManager.OP_NONE,
null, true, false, MY_PID, Process.SYSTEM_UID, users[curUser]);
}
public void performReceive(Intent intent, int resultCode,
String data, Bundle extras, boolean ordered,
boolean sticky, int sendingUser) {
// 指定接收者廣播處理完畢回調resultTo回來,繼續處理下一個,如果所有處理完,則post消息執行onFinishCallback
curUser++;
if (curUser >= users.length) {
curUser = 0;
curRi++;
if (curRi >= ris.size()) {
// All done sending broadcasts!
if (onFinishCallback != null) {
// The raw IIntentReceiver interface is called
// with the AM lock held, so redispatch to
// execute our code without the lock.
mHandler.post(onFinishCallback);
}
return;
}
}
go();
}
}
備注1:
在Android L版本上:是直接發送廣播,通過action:PRE_BOOT_COMPLETED,AMS會去發給各個接收者。處理完畢回調resultTo回來;
在Android M版本上:這里就直接指定接收者,一個個發送出去,處理完畢回調resultTo回來,繼續下一個。界面上可以看到在變化:顯示正在處理的廣播;
這樣做的好處界面體驗更好,木有看出有什么其他特別的用意。
備注2:
系統都有哪些地方接收PRE_BOOT_COMPLETED,以及什么情況下應該接收該廣播?
從目前看到的主要應用在數據庫應用升級方面,數據庫升級涉及到數據字段變化,數據的增加等會比較耗時,
為了加快應用啟動和提供數據,需要在開機過程中做升級操作,避免使用時耗時。
備注3:
這里其實存在一個隱患:從上面的流程看到,系統發送廣播給接收者處理,只有等所有接收者處理完畢,才會繼續系統的啟動流程。
試想:如果某個接收者的操作處理耗時較長,甚至被阻塞 或其他異常導致廣播處理無法完成,不能回調回來怎么辦?
結果:開機時間需要的更長了,或無法開機,一直就卡在這里無法開機。
很不幸,這種情況被我遇到過,大概是這樣的:
某次Hota升級某應用A注冊PRE_BOOT_COMPLETED廣播,處理該廣播時,由於某種情況需要訪問應用B的數據庫,等待應用B啟動,
由於系統沒有ready和應用B非persisit進程,系統不讓啟動B,結果系統就被阻塞在這里,始終無法開機。
這其實是系統不合理的地方,沒有相應的超時控制的安全機制,所幸這里只允許系統應用接收該廣播,如果允許第三方接收,后果可想而知。
2. 收集已經啟動的進程並殺死除過persistent進程
比如接收PRE_BOOT_COMPLETED啟動的應用
到此系統准備完畢,可以開始啟動應用進程,並置變量:mProcessesReady = true;
疑問:系統還沒准備之前不允許啟動非persistent進程,這之前的接收PRE_BOOT_COMPLETED廣播的應用是如何啟動的?
--》見應用啟動部分分析。
3. 系統准備好后回調傳入的Runnable
啟動應用和服務:{
startSystemUi(context);
connectivityF.systemReady();
……
Watchdog.getInstance().start();
mmsServiceF.systemRunning();
}
4. 發送賬戶啟動的廣播,涉及多用戶
多用戶的問題這里不討論。
注意發送該廣播前有如下操作:成對出現
//操作前 clear
long ident = Binder.clearCallingIdentity();
//do相關操作
……
//操作后restore
Binder.restoreCallingIdentity(ident);
通常這倆都是成對出現,具體的作用簡單說下:這涉及到權限管理后面會討論。
Binder.clearCallingIdentity():
通過IPC binder調用來遠端進程,當前進程會記錄調用者的PID和UID,即通常使用的getCallingPid和getCallingUid,
而會clearCallingIdentity把調用者PID和UID清除,將其設置為當前進程的PID和UID,並將原來的PID和UID作為返回值;
PID和UID是保存在一個long型數中,通過移位計算。
Binder.restoreCallingIdentity(ident):恢復剛才清除的遠端調用者的PID和UID。
這樣做有什么作用?
這涉及到權限管理,clearCallingIdentity接口注釋,舉了incoming call例子,看下原注釋:

大概的意思可以理解成這樣:

在ProcessB中,InterfaceA調用InterfaceB時,InterfaceB中要做權限檢查,通過getCallingPid,
這時拿到的PID是ProcessA的,權限不夠腫么辦。ProcessB的權限是夠可以的:就可以如下面

代碼里面很多這樣的例子,具體原因請自行體會,貼一段源代碼看看

5. 啟動桌面Home Activity
接上面systemReady最后部分:
// Start up initial activity.
mBooting = true;
startHomeActivityLocked(mCurrentUserId, "systemReady");
mStackSupervisor.resumeTopActivitiesLocked();
一張圖說明AMS啟動如上整個過程:

AMS的systemready過程基本如上,整個系統准備OK,下面就將開始啟動桌面流程,進入到應用啟動過程分析,應用和組件的啟動將在下一篇分析。
@閱讀原文http://www.cnblogs.com/bastard/p/5770573.html

