接下來,我們再繼續分析第三個開機畫面是如何停止顯示的。
一個Activity元件在啟動起來之後,就會被記錄起來,等到它所運作在的主線程空閑的時候,這個主線程就會向ActivityManagerService發送一個Activity元件空閑的通知。由于應用程式Launcher是系統中第一個被啟動的應用程式,即它的根Activity元件是系統中第一個被啟動的Activity元件,是以,當ActivityManagerService接收到它的空閑通知的時候,就可以知道系統是剛剛啟動起來的。在這種情況下,ActivityManagerService就會停止顯示開機動畫,以便可以在螢幕中顯示應用程式Lancher的界面。
應用程式的主線程是通過ActivityThread類來描述的,它實作在檔案frameworks/base/core/java/android/app/ActivityThread.java中。每當有一個新的Activity元件啟動起來的時候,ActivityThread類都會向它所描述的應用程式主線程的消息隊列注冊一個類型為Idler的空閑消息處理器。這樣一個應用程式的主線程就可以在空閑的時候,向ActivityManagerService發送一個Activity元件空閑通知,相當于是通知ActivityManagerService,一個新的Activity元件已經準備就緒了。
Idler類定義在frameworks/base/core/java/android/app/ActivityThread.java中, 它的成員函數queueIdle的實作如下所示:
public final class ActivityThread {
......
private final class Idler implements MessageQueue.IdleHandler {
public final boolean queueIdle() {
ActivityClientRecord a = mNewActivities;
if (a != null) {
mNewActivities = null;
IActivityManager am = ActivityManagerNative.getDefault();
ActivityClientRecord prev;
do {
......
if (a.activity != null && !a.activity.mFinished) {
try {
am.activityIdle(a.token, a.createdConfig);
a.createdConfig = null;
} catch (RemoteException ex) {
}
}
prev = a;
a = a.nextIdle;
prev.nextIdle = null;
} while (a != null);
}
ensureJitEnabled();
return false;
}
}
}
ActivityThread類有一個類型為ActivityClientRecord的成員變量mNewActivities,用來描述所有在目前應用程式主線程中新啟動起來的Activity元件。這些新啟動起來的Activity元件通過ActivityClientRecord類的成員變量nextIdle連接配接在一起。一旦目前應用程式主線程向ActivityManagerService發送了這些新啟動的Activity元件的空閑通知之後,這些新啟動起來的Activity元件就不會再被儲存在ActivityThread類的成員變量mNewActivities中了,即每一個新啟動的Activity元件隻有一次機會向ActivityManagerService發送一個空閑通知。
向ActivityManagerService發送一個Activity元件空閑通知是通過調用ActivityManagerService代理對象的成員函數activityIdle來實作的,而ActivityManagerService代理對象可以通過調用ActivityManagerNative類的靜态成員函數getDefault來獲得。
ActivityManagerService代理對象的類型為ActivityManagerProxy,它的成員函數activityIdle實作在檔案frameworks/base/core/java/android/app/ActivityManagerNative.java中,如下所示:
class ActivityManagerProxy implements IActivityManager
{
public void activityIdle(IBinder token, Configuration config) throws RemoteException
{
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeStrongBinder(token);
if (config != null) {
data.writeInt(1);
config.writeToParcel(data, 0);
} else {
data.writeInt(0);
mRemote.transact(ACTIVITY_IDLE_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY);
reply.readException();
data.recycle();
reply.recycle();
ActivityManagerProxy類的成員函數activityIdle實際上是向ActivityManagerService發送一個類型為ACTIVITY_IDLE_TRANSACTION的Binder程序間通信請求,其中,參數token用來描述與這個程序間通信請求所關聯的一個Activity元件,在我們這個場景中,這個Activity元件即為應用程式Launcher的根Activity元件Launcher。
類型為ACTIVITY_IDLE_TRANSACTION的Binder程序間通信請求是由ActivityManagerService類的成員函數activityIdle來處理的,如下所示:
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
public final void activityIdle(IBinder token, Configuration config) {
final long origId = Binder.clearCallingIdentity();
mMainStack.activityIdleInternal(token, false, config);
Binder.restoreCallingIdentity(origId);
ActivityManagerService類有一個類型為ActivityStack的成員變量mMainStack,它用來描述系統的Activity元件堆棧,它的成員函數activityIdleInternal的實作如下所示:
public class ActivityStack {
final void activityIdleInternal(IBinder token, boolean fromTimeout,
Configuration config) {
......
boolean enableScreen = false;
synchronized (mService) {
......
// Get the activity record.
int index = indexOfTokenLocked(token);
if (index >= 0) {
ActivityRecord r = (ActivityRecord)mHistory.get(index);
......
if (mMainStack) {
if (!mService.mBooted && !fromTimeout) {
mService.mBooted = true;
enableScreen = true;
}
if (enableScreen) {
mService.enableScreenAfterBoot();
}
參數token用來描述剛剛啟動起來的Launcher元件,通過它來調用函數indexOfTokenLocked就可以得到Launcher元件在系統Activity元件堆棧中的位置index。得到了Launcher元件在系統Activity元件堆棧中的位置index之後,就可以在ActivityStack類的成員變量mHistory中得到一個ActivityRecord對象r。這個ActivityRecord對象r同樣是用來描述Launcher元件的。
ActivityStack類的成員變量mMainStack是一個布爾變量,當它的值等于true的時候,就說明目前正在處理的ActivityStack對象是用來描述系統的Activity元件堆棧的。 ActivityStack類的另外一個成員變量mService指向了系統中的ActivityManagerService服務。ActivityManagerService服務有一個類型為布爾值的成員變量mBooted,它的初始值為false,表示系統尚未啟動完成。
從前面的調用過程可以知道,參數fromTimeout的值等于false。在這種情況下,如果ActivityManagerService服務的成員變量mBooted也等于false,那麼就說明應用程式已經啟動起來了,即說明系統已經啟動完成了。這時候ActivityManagerService服務的成員變量mBooted以及變量enableScreen的值就會被設定為true。
當變量enableScreen的值等于true的時候,ActivityStack類就會調用ActivityManagerService服務的成員函數enableScreenAfterBoot停止顯示開機動畫,以便可以将螢幕讓出來顯示應用程式Launcher的界面。
ActivityManagerService類的成員函數enableScreenAfterBoot的實作如下所示:
void enableScreenAfterBoot() {
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_ENABLE_SCREEN,
SystemClock.uptimeMillis());
mWindowManager.enableScreenAfterBoot();
ActivityManagerService類的成員變量mWindowManager指向了系統中的Window管理服務WindowManagerService,ActivityManagerService服務通過調用它的成員函數enableScreenAfterBoot來停止顯示開機動畫。
WindowManagerService類的成員函數enableScreenAfterBoot的實作如下所示:
public class WindowManagerService extends IWindowManager.Stub
implements Watchdog.Monitor {
public void enableScreenAfterBoot() {
synchronized(mWindowMap) {
if (mSystemBooted) {
return;
mSystemBooted = true;
performEnableScreen();
WindowManagerService類的成員變量mSystemBooted用來記錄系統是否已經啟動完成的。如果已經啟動完成的話,那麼這個成員變量的值就會等于true,這時候WindowManagerService類的成員函數enableScreenAfterBoot什麼也不做就傳回了,否則的話,WindowManagerService類的成員函數enableScreenAfterBoot首先将這個成員變量的值設定為true,接着再調用另外一個成員函數performEnableScreen來執行停止顯示開機動畫的操作。
本文轉自 Luoshengyang 51CTO部落格,原文連結:http://blog.51cto.com/shyluo/967048,如需轉載請自行聯系原作者