相關文章
Android系統架構與系統原始碼目錄
Android系統啟動流程(一)解析init程式啟動過程
Android系統啟動流程(二)解析Zygote程式啟動過程
Android系統啟動流程(三)解析SyetemServer程式啟動過程
Android系統啟動流程(四)Launcher啟動過程與系統啟動流程
前言
在此前我講過Android系統的啟動流程,系統啟動後,我們就比較關心應用程式是如何啟動的,這一篇我們來一起學習Android7.0 應用程式程式啟動過程,需要注意的是“應用程式程式啟動過程”,而不是應用程式啟動過程。關於應用程式啟動過程,我會在後續系列的文章中講到。希望閱讀這篇文章前先閱讀本文列出的相關文章,要不你一臉矇蔽,就別怪我了。
1.應用程式程式概述
要想啟動一個應用程式,首先要保證這個應用程式所需要的應用程式程式已經被啟動。ActivityManagerService在啟動應用程式時會檢查這個應用程式需要的應用程式程式是否存在,不存在就會請求Zygote程式將需要的應用程式程式啟動。在Android系統啟動流程(二)解析Zygote程式啟動過程這篇文章中,我提到了Zygote的Java框架層中,會建立一個Server端的Socket,這個Socket用來等待ActivityManagerService來請求Zygote來建立新的應用程式程式的。我們知道Zygote程式通過fock自身建立的應用程式程式,這樣應用程式程式程式就會獲得Zygote程式在啟動時建立的虛擬機器例項。當然,在應用程式建立過程中除了獲取虛擬機器例項,還可以獲得Binder執行緒池和訊息迴圈,這樣執行在應用程式中應用程式就可以方便的使用Binder進行程式間通訊以及訊息處理機制了。先給出應用程式程式啟動過程的時序圖,然後對每一個步驟進行詳細分析,如下圖所示。
2.應用程式程式建立過程
傳送建立應用程式程式請求
ActivityManagerService會通過呼叫startProcessLocked函式來向Zygote程式傳送請求,如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
private final void startProcessLocked(ProcessRecord app, String hostingType,
String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
...
try {
try {
final int userId = UserHandle.getUserId(app.uid);
AppGlobals.getPackageManager().checkPackageStartable(app.info.packageName, userId);
} catch (RemoteException e) {
throw e.rethrowAsRuntimeException();
}
int uid = app.uid;//1
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
...
/**
* 2 對gids進行建立和賦值
*/
if (ArrayUtils.isEmpty(permGids)) {
gids = new int[2];
} else {
gids = new int[permGids.length + 2];
System.arraycopy(permGids, 0, gids, 2, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getUserGid(UserHandle.getUserId(uid));
}
...
if (entryPoint == null) entryPoint = "android.app.ActivityThread";//3
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
/**
* 4
*/
Process.ProcessStartResult startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
app.info.dataDir, entryPointArgs);
...
} catch (RuntimeException e) {
...
}
}
...
}複製程式碼
在註釋1處的達到建立應用程式程式的使用者ID,在註釋2處對使用者組ID:gids進行建立和賦值。註釋3處如果entryPoint 為null則賦值為"android.app.ActivityThread"。在註釋4處呼叫Process的start函式,將此前得到的應用程式程式使用者ID和使用者組ID傳進去,第一個引數entryPoint我們得知是"android.app.ActivityThread",後文會再次提到它。接下來我們來檢視Process的start函式,如下所示。
frameworks/base/core/java/android/os/Process.java
public static final ProcessStartResult start(final String processClass,
final String niceName,
int uid, int gid, int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
...
}
}複製程式碼
start函式中只呼叫了startViaZygote函式:
frameworks/base/core/java/android/os/Process.java
private static ProcessStartResult startViaZygote(final String processClass,
final String niceName,
final int uid, final int gid,
final int[] gids,
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
String abi,
String instructionSet,
String appDataDir,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
/**
* 1
*/
ArrayList<String> argsForZygote = new ArrayList<String>();
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
...
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}複製程式碼
在註釋1處建立了字串列表argsForZygote ,並將啟動應用程式的啟動引數儲存在argsForZygote中,函式的最後會呼叫zygoteSendArgsAndGetResult函式,需要注意的是,zygoteSendArgsAndGetResult函式中第一個引數中呼叫了openZygoteSocketIfNeeded函式,而第二個引數是儲存應用程式的啟動引數的argsForZygote。zygoteSendArgsAndGetResult函式如下所示。
frameworks/base/core/java/android/os/Process.java
private static ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
try {
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
writer.write(arg);
writer.newLine();
}
writer.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
result.pid = inputStream.readInt();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
result.usingWrapper = inputStream.readBoolean();
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}複製程式碼
zygoteSendArgsAndGetResult函式主要做的就是將傳入的應用程式的啟動引數argsForZygote,寫入到ZygoteState中,結合上文我們知道ZygoteState其實是由openZygoteSocketIfNeeded函式返回的,那麼我們接著來看openZygoteSocketIfNeeded函式,程式碼如下所示。
frameworks/base/core/java/android/os/Process.java
private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);//1
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
if (primaryZygoteState.matches(abi)) {//2
return primaryZygoteState;
}
// The primary zygote didn't match. Try the secondary.
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);//3
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);複製程式碼
在講到Zygote程式啟動過程時我們得知,在Zygote的main函式中會建立name為“zygote”的Server端Socket。在註釋1處會呼叫ZygoteState的connect函式與名稱為ZYGOTE_SOCKET的Socket建立連線,這裡ZYGOTE_SOCKET的值為“zygote”。註釋2處如果連線name為“zygote”的Socket返回的primaryZygoteState與當前的abi不匹配,則會在註釋3處連線name為“zygote_secondary”的Socket。這兩個Socket區別就是:name為"zygote”的Socket是執行在64位Zygote程式中的,而name為“zygote_secondary”的Socket則執行在32位Zygote程式中。既然應用程式程式是通過Zygote程式fock產生的,當要連線Zygote中的Socket時,也需要保證位數的一致。
接收請求並建立應用程式程式
Socket進行連線成功並匹配abi後會返回ZygoteState型別物件,我們在分析zygoteSendArgsAndGetResult函式中講過,會將應用程式的啟動引數argsForZygote寫入到ZygoteState中,這樣Zygote程式就會收到一個建立新的應用程式程式的請求,我們回到ZygoteInit的main函式,如下所示。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
...
try {
...
//註冊Zygote用的Socket
registerZygoteSocket(socketName);//1
...
//預載入類和資源
preload();//2
...
if (startSystemServer) {
//啟動SystemServer程式
startSystemServer(abiList, socketName);//3
}
Log.i(TAG, "Accepting command socket connections");
//等待客戶端請求
runSelectLoop(abiList);//4
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}複製程式碼
這些內容在Android系統啟動流程(二)解析Zygote程式啟動過程講過,但為了更好的理解我再講一遍。註釋1處通過registerZygoteSocket函式來建立一個Server端的Socket,這個name為”zygote”的Socket用來等待ActivityManagerService來請求Zygote來建立新的應用程式程式。註釋2處用來預載入類和資源。註釋3處用來啟動SystemServer程式,這樣系統的關鍵服務也會由SystemServer程式啟動起來。註釋4處呼叫runSelectLoop函式來等待ActivityManagerService的請求。我們就來檢視runSelectLoop函式:
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();//2
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
while (true) {
...
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
if (i == 0) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done = peers.get(i).runOnce();//1
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}複製程式碼
當有ActivityManagerService的請求資料到來時會呼叫註釋1處的程式碼,結合註釋2處的程式碼,我們得知註釋1處的程式碼其實是呼叫ZygoteConnection的runOnce函式來處理請求的資料:
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = readArgumentList();//1
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
...
try {
parsedArgs = new Arguments(args);//2
...
/**
* 3
*/
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
} catch (ErrnoException ex) {
....
}
try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
} else {
// in parent...pid of < 0 means failure
IoUtils.closeQuietly(childPipeFd);
childPipeFd = null;
return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
}
} finally {
IoUtils.closeQuietly(childPipeFd);
IoUtils.closeQuietly(serverPipeFd);
}
}複製程式碼
在註釋1處呼叫readArgumentList函式來獲取應用程式程式的啟動引數,並在註釋2處將readArgumentList函式返回的字串封裝到Arguments物件parsedArgs中。註釋3處呼叫Zygote的forkAndSpecialize函式來建立應用程式程式,引數為parsedArgs中儲存的應用程式啟動引數,返回值為pid。forkAndSpecialize函式主要是通過fork當前程式來建立一個子程式的,如果pid等於0,則說明是在新建立的子程式中執行的,就會呼叫handleChildProc函式來啟動這個子程式也就是應用程式程式,如下所示。
frameworks/base/core/java/com/android/internal/os/ZygoteConnection.java
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
...
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}複製程式碼
handleChildProc函式中呼叫了RuntimeInit的zygoteInit函式,如下所示。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();
commonInit();
nativeZygoteInit();//1
applicationInit(targetSdkVersion, argv, classLoader);//2
}複製程式碼
註釋1處會在新建立的應用程式程式中建立Binder執行緒池,這個在下一篇文章會詳細介紹。在註釋2處呼叫了applicationInit函式:
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
private static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
...
final Arguments args;
try {
args = new Arguments(argv);
} catch (IllegalArgumentException ex) {
Slog.e(TAG, ex.getMessage());
return;
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
invokeStaticMain(args.startClass, args.startArgs, classLoader);//1
}複製程式碼
在applicationInit中會在註釋1處呼叫invokeStaticMain函式,需要注意的是第一個引數args.startClass,這裡指的就是此篇文章開頭提到的引數:android.app.ActivityThread。接下來我們檢視invokeStaticMain函式,如下所示。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
cl = Class.forName(className, true, classLoader);//1
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });//2
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
}
...
throw new ZygoteInit.MethodAndArgsCaller(m, argv);//3
}複製程式碼
可以看到註釋1處通過反射來獲得android.app.ActivityThread類,接下來在註釋2處來獲得ActivityThread的main函式,並將main函式傳入到註釋3處的ZygoteInit中的MethodAndArgsCaller類的建構函式中,MethodAndArgsCaller類內部會通過反射呼叫ActivityThread的main函式,這樣應用程式程式就建立完成了。
3.Binder執行緒池啟動過程
我們首先來看RuntimeInit類的zygoteInit函式,如下所示
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
redirectLogStreams();
commonInit();
nativeZygoteInit();//1
applicationInit(targetSdkVersion, argv, classLoader);
}複製程式碼
註釋1處會在新建立的應用程式程式中建立Binder執行緒池,來檢視nativeZygoteInit函式:
private static final native void nativeZygoteInit();複製程式碼
很明顯nativeZygoteInit是一個jni方法,它對應的函式是什麼呢。在 AndroidRuntime.cpp的JNINativeMethod陣列中我們得知它對應的函式是com_android_internal_os_RuntimeInit_nativeZygoteInit,如下所示。
frameworks/base/core/jni/AndroidRuntime.cpp
static const JNINativeMethod gMethods[] = {
{ "nativeFinishInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
{ "nativeZygoteInit", "()V",
(void*) com_android_internal_os_RuntimeInit_nativeZygoteInit },
{ "nativeSetExitWithoutCleanup", "(Z)V",
(void*) com_android_internal_os_RuntimeInit_nativeSetExitWithoutCleanup },
};複製程式碼
接著來檢視 com_android_internal_os_RuntimeInit_nativeZygoteInit函式:
frameworks/base/core/jni/AndroidRuntime.cpp
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}複製程式碼
gCurRuntime是在AndroidRuntime初始化就建立的。如下所示。
frameworks/base/core/jni/AndroidRuntime.cpp
AndroidRuntime::AndroidRuntime(char* argBlockStart, const size_t argBlockLength) :
mExitWithoutCleanup(false),
mArgBlockStart(argBlockStart),
mArgBlockLength(argBlockLength)
{
...
gCurRuntime = this;
}複製程式碼
在Android系統啟動流程(二)解析Zygote程式啟動過程這篇文章我們得知AppRuntime繼承AndroidRuntime,AppRuntime建立時就會呼叫AndroidRuntime的建構函式,gCurRuntime就會被初始化,它指向的是AppRuntime,因此我們來檢視AppRuntime的onZygoteInit函式,AppRuntime的實現在app_main.cpp中,如下所示。
frameworks/base/cmds/app_process/app_main.cpp
virtual void onZygoteInit()
{
sp<ProcessState> proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}複製程式碼
最後一行會呼叫ProcessState的startThreadPool函式:
frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::startThreadPool()
{
AutoMutex _l(mLock);
if (!mThreadPoolStarted) {
mThreadPoolStarted = true;
spawnPooledThread(true);
}
}複製程式碼
支援Binder通訊的程式中都有一個ProcessState類,它裡面有一個mThreadPoolStarted 變數,來表示Binder執行緒池是否已經被啟動過,預設值為false。在每次呼叫這個函式時都會先去檢查這個標記,從而確保Binder執行緒池只會被啟動一次。如果Binder執行緒池未被啟動則設定mThreadPoolStarted為true,最後呼叫spawnPooledThread函式來建立執行緒池中的第一個執行緒,也就是執行緒池的main執行緒,如下所示。
frameworks/native/libs/binder/ProcessState.cpp
void ProcessState::spawnPooledThread(bool isMain)
{
if (mThreadPoolStarted) {
String8 name = makeBinderThreadName();
ALOGV("Spawning new pooled thread, name=%s\n", name.string());
sp<Thread> t = new PoolThread(isMain);
t->run(name.string());//1
}
}複製程式碼
可以看到Binder執行緒為一個PoolThread。註釋1呼叫PoolThread的run函式來啟動一個啟動一個新的執行緒。來檢視PoolThread類裡做了什麼:
frameworks/native/libs/binder/ProcessState.cpp
class PoolThread : public Thread
{
..
protected:
virtual bool threadLoop()
{
IPCThreadState::self()->joinThreadPool(mIsMain);//1
return false;
}
const bool mIsMain;
};複製程式碼
PoolThread類繼承了Thread類。註釋1處會將呼叫IPCThreadState的joinThreadPool函式,將當前執行緒註冊到Binder驅動程式中,這樣我們建立的執行緒就加入了Binder執行緒池中,這樣新建立的應用程式程式就支援Binder程式間通訊了,Binder執行緒池啟動過程就講到這,接下來我們來學習訊息迴圈建立過程。
4.訊息迴圈建立過程
首先我們回到上篇最後講到的RuntimeInit的invokeStaticMain函式,程式碼如下所示。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
...
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}複製程式碼
invokeStaticMain函式在上篇已經講過,這裡不再贅述,主要是看最後一行,會丟擲一個MethodAndArgsCaller異常,這個異常會被ZygoteInit的main函式捕獲,如下所示。
frameworks/base/core/java/com/android/internal/os/ZygoteInit.java
public static void main(String argv[]) {
...
try {
...
} catch (MethodAndArgsCaller caller) {
caller.run();//1
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}複製程式碼
註釋1處捕獲到MethodAndArgsCaller 時會執行caller的run函式,如下所示。
frameworks/base/core/java/com/android/internal/os/RuntimeInit.java
public static class MethodAndArgsCaller extends Exception
implements Runnable {
private final Method mMethod;
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
mMethod.invoke(null, new Object[] { mArgs });//1
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
}
...
throw new RuntimeException(ex);
}
}
}複製程式碼
根據上一篇文章我們得知,mMethod指的就是ActivityThread的main函式,mArgs 指的是應用程式程式的啟動引數。在註釋1處呼叫ActivityThread的main函式,程式碼如下所示。
frameworks/base/core/java/android/app/ActivityThread.java
public static void main(String[] args) {
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
SamplingProfilerIntegration.start();
...
Looper.prepareMainLooper();//1
ActivityThread thread = new ActivityThread();//2
thread.attach(false);
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
Looper.loop();//3
throw new RuntimeException("Main thread loop unexpectedly exited");
}複製程式碼
註釋1處在當前應用程式程式中建立訊息迴圈,註釋2處建立ActivityThread,註釋3處呼叫Looper的loop,使得Looper開始工作,開始處理訊息。可以看出,系統在應用程式程式啟動完成後,就會建立一個訊息迴圈,用來方便的使用Android的訊息處理機制。
歡迎關注我的微信公眾號,第一時間獲得部落格更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,即可關注。