開機SystemServer到ActivityManagerService啓動過程java
zygote-> systemserver:java入層口:android
/** * The main entry point from zygote. */ public static void main(String[] args) { new SystemServer().run(); }
接下來繼續看SystemServer run函數執行過程:redis
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方式調用,其餘接口都是直接調用,爲什麼?直接調用有何不可嗎?數組
接上面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); }
Broadcast --》BroadcastQueue
Provider --》ProviderMap
Service --》ActiveServices
Activity --》ActivityStackSupervisor
備註1:Android6.0上加入多用戶功能,增長了一些涉及多用戶的管理。app
拓展知識點:HandlerThread,Handle,Looperide
接上面systemserver.run中:函數
mActivityManagerService.setSystemProcess();oop
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(); } }
這一步就是給SystemServer進程建立ProcessRecord,adj值,就是將SystemServer進程加入到AMS進程管理機制中,跟應用進程一致;
進程調度更新優先級oomadj值,我的感受SystemServer進程跟應用進程就不同,卻加入AMS來調度管理,這樣作的意義何在?
接上面SystemServer.run中:
mActivityManagerService.installSystemProviders();
備註2: 將相關provider運行在systemserver進程中:SettingsProvider
具體安裝過程這裏暫不詳述,在應用啓動過程當中具體分析。
接上面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(); }
顧名思義:只有系統作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;
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,結果系統就被阻塞在這裏,始終沒法開機。
這實際上是系統不合理的地方,沒有相應的超時控制的安全機制,所幸這裏只容許系統應用接收該廣播,若是容許第三方接收,後果可想而知。
好比接收PRE_BOOT_COMPLETED啓動的應用
到此係統準備完畢,能夠開始啓動應用進程,並置變量:mProcessesReady = true;
疑問:系統還沒準備以前不容許啓動非persistent進程,這以前的接收PRE_BOOT_COMPLETED廣播的應用是如何啓動的?
--》見應用啓動部分分析。
啓動應用和服務:{
startSystemUi(context);
connectivityF.systemReady();
……
Watchdog.getInstance().start();
mmsServiceF.systemRunning();
}
多用戶的問題這裏不討論。
注意發送該廣播前有以下操做:成對出現
//操做前 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的權限是夠能夠的:就能夠以下面
代碼裏面不少這樣的例子,具體緣由請自行體會,貼一段源代碼看看
接上面systemReady最後部分: // Start up initial activity.
mBooting = true; startHomeActivityLocked(mCurrentUserId, "systemReady"); mStackSupervisor.resumeTopActivitiesLocked();
一張圖說明AMS啓動如上整個過程:
AMS的systemready過程基本如上,整個系統準備OK,下面就將開始啓動桌面流程,進入到應用啓動過程分析,應用和組件的啓動將在下一篇分析。