該篇是Android啟動系列的最后一篇站绪,本文從應(yīng)用進程的創(chuàng)建啟動角度出發(fā)候引,分析ActivityThread是如何創(chuàng)建的。相對于上篇勘天,本文內(nèi)容較少媚狰,閱讀無壓力~
從接觸Android的那一刻開始型檀,看到最多的是:耗時任務(wù)不能在主線程執(zhí)行憎妙,UI操作要在主線程執(zhí)行……當(dāng)時人傻無知,從來沒有想過什么是主線程口锭,為啥不能在主線程做耗時任務(wù)等等朦前。
大家都說ActivityThread是主線程,那它是線程嗎鹃操?它為什么被稱為主線程韭寸?它做啥了?
回顧
在上文《沉思曲:Activity啟動》一文中荆隘,分析了Activity的啟動過程恩伺。并在調(diào)用startSpecificActivityLocked方法時,提到這里會判斷目的Activity進程是否存在椰拒,如果不存在晶渠,就會創(chuàng)建新進程,本文就從這個創(chuàng)建新進程的分支開始燃观。
創(chuàng)建應(yīng)用進程
先回顧下startSpecificActivityLocked方法
該方法在ActivityStackSupervisor.java中
void startSpecificActivityLocked(ActivityRecord r,
boolean andResume, boolean checkConfig) {
//獲取待啟動Activity的進程信息
ProcessRecord app = mService.getProcessRecordLocked(r.processName,
r.info.applicationInfo.uid, true);
r.task.stack.setLaunchTime(r);
//待啟動Activity所在進程存在
if (app != null && app.thread != null) {
try {
app.addPackage(r.info.packageName, mService.mProcessStats);
//接著往下執(zhí)行
realStartActivityLocked(r, app, andResume, checkConfig);
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting activity "
+ r.intent.getComponent().flattenToShortString(), e);
}
}
//待啟動Activity所在進程不存在褒脯,為其創(chuàng)建新進程
mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
"activity", r.intent.getComponent(), false, false, true);
}
- 上方法中,如果目的Activity所在進程不存在缆毁,調(diào)用AMS的startProcessLocked方法創(chuàng)建目的應(yīng)用進程番川。
1.1、startProcessLocked
startProcessLocked定義在ActivityManagerService.java中脊框,該方法會調(diào)用Process的start方法颁督。
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null);
- 該方法調(diào)用Process的start方法,注意傳入?yún)?shù):<u>"android.app.ActivityThread"</u>
1.2浇雹、 start | Process.java
/**
* Start a new process.
*
* <p>If processes are enabled, a new process is created and the
* static main() function of a <var>processClass</var> is executed there.
* The process will continue running after this function returns.
*
* <p>If processes are not enabled, a new thread in the caller's
* process is created and main() of <var>processClass</var> called there.
*
* <p>The niceName parameter, if not an empty string, is a custom name to
* give to the process instead of using processClass. This allows you to
* make easily identifyable processes even if you are using the same base
* <var>processClass</var> to start them.
*
* @param processClass The class to use as the process's main entry
* point.
* @param niceName A more readable name to use for the process.
* @param uid The user-id under which the process will run.
* @param gid The group-id under which the process will run.
* @param gids Additional group-ids associated with the process.
* @param debugFlags Additional flags.
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SE Android information for the new process.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
* @throws RuntimeException on fatal start failure
*
* {@hide}
*/
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[] zygoteArgs) {
try {
//通過Zygote啟動新進程
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
從注釋可知沉御,該方法用來啟動一個新進程:
- 如果進程啟動,則processClass(此處入?yún)椤癮ndroid.app.ActivityThread”)會運行在該新進程中昭灵,并且在該方法調(diào)用完成后嚷节,新進程會繼續(xù)運行。
- 如果進程未啟動虎锚,則調(diào)用該start方法所在的進程會創(chuàng)建一個新的線程,然后processClass運行在該新線程中衩婚。
方法調(diào)用startViaZygote方法窜护,從方法名看出,進程創(chuàng)建似乎是要交給zygote非春。
1.3柱徙、startViaZygote | 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[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
//啟動新進程的參數(shù)
ArrayList<String> argsForZygote = new ArrayList<String>();
//添加各種參數(shù)到argsForZygote
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
...
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
argsForZygote.add(processClass);
...
//調(diào)用該方法缓屠,由zygote創(chuàng)建進程,并獲取新進程信息
return zygoteSendArgsAndGetResult(argsForZygote);
}
}
這個方法設(shè)置啟動新進程所需參數(shù)护侮,并往下調(diào)用zygoteSendArgsAndGetResult方法敌完。
1.4、zygoteSendArgsAndGetResult | Process.java
private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx {
//進程通信羊初,連接到Zygote的Server Socket滨溉,交由Zygote創(chuàng)建
openZygoteSocketIfNeeded();
try {
//sZygoteWriter將參數(shù)發(fā)送到Server Socket
sZygoteWriter.write(Integer.toString(args.size()));
sZygoteWriter.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");
}
sZygoteWriter.write(arg);
sZygoteWriter.newLine();
}
sZygoteWriter.flush();
//sZygoteInputStream從Server Socket讀取結(jié)果
ProcessStartResult result = new ProcessStartResult();
result.pid = sZygoteInputStream.readInt();
...
result.usingWrapper = sZygoteInputStream.readBoolean();
return result;
...
}
從方法名可以猜出該方法大致干啥了:發(fā)送啟動參數(shù)給Zygote進程,交由Zygote進程啟動长赞,并獲得啟動結(jié)果晦攒。看下是否如此:
1得哆、調(diào)用openZygoteSocketIfNeeded方法脯颜。
2、調(diào)用sZygoteWriter往ServerSocket寫創(chuàng)建進程所需要的參數(shù)贩据,ServerSocket是啥栋操?
3、創(chuàng)建ProcessStartResult饱亮,并寫入從ServerSocket讀取的數(shù)據(jù)矾芙,作為結(jié)果返回。
看來重點在openZygoteSocketIfNeeded方法近尚!
1.5蠕啄、openZygoteSocketIfNeeded | Process.java
private static void openZygoteSocketIfNeeded()
throws ZygoteStartFailedEx {
//重連次數(shù)
int retryCount;
if (sPreviousZygoteOpenFailed) {
retryCount = 0;
} else {
retryCount = 10;
}
for (int retry = 0
; (sZygoteSocket == null) && (retry < (retryCount + 1))
; retry++ ) {
...
try {
//client socket
sZygoteSocket = new LocalSocket();
//連接到Zygote的server socket
sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
LocalSocketAddress.Namespace.RESERVED));
//sZygoteInputStream負責(zé)讀取server socket信息
sZygoteInputStream
= new DataInputStream(sZygoteSocket.getInputStream());
//sZygoteWriter發(fā)送信息到server socket
sZygoteWriter =
new BufferedWriter(
new OutputStreamWriter(
sZygoteSocket.getOutputStream()),
256);
sPreviousZygoteOpenFailed = false;
break;
...
}
詳細大家都能一眼看懂,這不是Java中的Socket的連接嗎戈锻,這不過這里是用來進程連接歼跟。
1、創(chuàng)建Client Socket:sZygoteSocket
2格遭、ClientSocket連接到服務(wù)端哈街,ServerSocket:ZYGOTE_SOCKET
3、創(chuàng)建輸入流負責(zé)從ServerSocket讀數(shù)據(jù)拒迅,創(chuàng)建輸出流向ServerSocket寫數(shù)據(jù)骚秦。
即:
- openZygoteSocketIfNeeded方法負責(zé)連接到Zygote的Server Socket,并發(fā)送/讀取Server Socket的信息璧微。
- ServerSocket即ZYGOTE_SOCKET作箍,它有Zygote進程創(chuàng)建。
既然client socket連接到Zygote的創(chuàng)建的ServerSocket了前硫,那接下來看下Zygote是如何處理連接的胞得。
Zygote處理客戶端連接
Zygote進程由init進程啟動,Zygote的實現(xiàn)在ZygoteInit.java中屹电,其main方法調(diào)用標志著Zygote的啟動阶剑。
2.1跃巡、main | ZygoteInit.java
public static void main(String argv[]) {
try {
//注冊server socket
//其它進程的創(chuàng)建,通過連接到該Socket后,由zygote孵化出來
registerZygoteSocket();
...
//預(yù)加載android framework類和資源
preload();
...
if (argv[1].equals("start-system-server")) {
//啟動SystemServer
startSystemServer();
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
//死循環(huán)接收client socket連接牧愁,由此創(chuàng)建新進程
runSelectLoop();
closeServerSocket();
} catch (MethodAndArgsCaller caller) { //標注加紅素邪,這個異常捕獲是重點!V戆搿兔朦!
caller.run();
} catch (RuntimeException ex) {
closeServerSocket();
throw ex;
}
}
- Zygote進程啟動時,注冊了ServerSocket办龄,即上面提到的ZYGOTE_SOCKET烘绽,就是它來處理client socket的連接。
- Zygote進程啟動時還啟動了SystemServer俐填,這在第一篇文章中已經(jīng)分析過了安接。
- 最后調(diào)用runSelectLoop方法,死循環(huán)處理client socket連接英融。
最后需要注意的是:
main方法采用了try-catch的方式盏檐,其中捕獲了異常MethodAndArgsCaller。由后面代碼可知驶悟,通過這種拋異常的方式胡野,使進程跳出死循環(huán),并執(zhí)行caller.run方法痕鳍。
2.2硫豆、runSelectLoop | ZygoteInit.java
上面方法調(diào)用runSelectLoop,死循環(huán)處理client連接笼呆,看下其內(nèi)容熊响。
private static void runSelectLoop() throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
//client socket連接列表
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
//將server socket添加到fds中
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
...
try {
//將fds轉(zhuǎn)換成數(shù)組
fdArray = fds.toArray(fdArray);
//在fdArray中找到可讀的連接
index = selectReadable(fdArray);
} catch (IOException ex) {
throw new RuntimeException("Error in select()", ex);
}
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
//第一個為Server socket,此時等待client socket連接
ZygoteConnection newPeer = acceptCommandPeer();
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
boolean done;
//處理連接
done = peers.get(index).runOnce();
//處理完連接诗赌,從列表中移除
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
代碼邏輯還是比較清楚:
- Zygote死循環(huán)處理已連接的client socket汗茄,client的連接封裝成ZygoteConnection 表示,并調(diào)用其的runOnce()方法铭若。
- 如果已連接的client socket都處理完成洪碳,那就等待新的client連接。
2.3叼屠、runOnce | ZygoteConnection.java
看下連接的處理方法runOnce():
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
//讀取client socket傳入的參數(shù)列表
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
}
...
try {
//轉(zhuǎn)換參數(shù)
parsedArgs = new Arguments(args);
...
//Zygote創(chuàng)建 新進程并負責(zé)虛擬機實例到該進程
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);
}
...
try {
//新進程
if (pid == 0) {
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
//新進程中調(diào)用
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
return true;
}
...
}
要劃重點了:
1瞳腌、該方法讀取client socket連接時傳入的參數(shù),并封裝镜雨。
2纯趋、調(diào)用Zygote的forkAndSpecialize創(chuàng)建指定進程。
3、pid=0時即子進程吵冒,在子進程中調(diào)用handleChildProc方法。
這里涉及到以下幾點:
- 應(yīng)用進程的確是有Zygote進程創(chuàng)建的西剥,包括前文提到的SystemServer進程
- 新進程時如何與虛擬機關(guān)聯(lián)的痹栖?
在forkAndSpecialize方法中,Zygote會將創(chuàng)建的Dalvik虛擬機實例復(fù)制到新的應(yīng)用程序進程里面去瞭空,從而使得每一個應(yīng)用程序進程都有一個獨立的Dalvik虛擬機實例揪阿。
好了,新進程已經(jīng)創(chuàng)建好了咆畏,但似乎還沒解決問題南捂,ActivityThread是如何運行在新進程中的呢?接著往下看handleChildProc方法旧找。
2.4溺健、handleChildProc | ZygoteConnection.java
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
//子進程中關(guān)閉client/server socket
closeSocket();
ZygoteInit.closeServerSocket();
...
if (parsedArgs.niceName != null) {
//設(shè)置進程名
Process.setArgV0(parsedArgs.niceName);
}
//是否設(shè)置了runtimeInit參數(shù)
if (parsedArgs.runtimeInit) {
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
} else {
//zygoteInit最后仍會創(chuàng)建ActivityThread實例,并調(diào)用其main方法
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs);
}
} else {
String className;
try {
//傳入的類全限定名钮蛛,此處為:“android.app.ActivityThread”
className = parsedArgs.remainingArgs[0];
}
...
if (parsedArgs.invokeWith != null) {
WrapperInit.execStandalone(parsedArgs.invokeWith,
parsedArgs.classpath, className, mainArgs);
} else {
ClassLoader cloader;
if (parsedArgs.classpath != null) {
//ClassLoader
cloader = new PathClassLoader(parsedArgs.classpath,
ClassLoader.getSystemClassLoader());
} else {
cloader = ClassLoader.getSystemClassLoader();
}
try {
//反射創(chuàng)建className(此處為ActivityThread)實例鞭缭,并調(diào)用其main方法
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
}
...
}
}
}
注意哦,現(xiàn)在已經(jīng)是在新創(chuàng)建的子進程了哦:
1魏颓、子進程關(guān)閉client/server socket連接岭辣,為什么呢?
2甸饱、解析參數(shù)沦童,根據(jù)前面?zhèn)魅氲膮?shù)“android.app.ActivityThread”,調(diào)用ZygoteInit.invokeStaticMain方法叹话,反射創(chuàng)建ActivityThread實例偷遗,并調(diào)用該實例main方法。
回答兩個問題:
1渣刷、子進程為什么要關(guān)閉client/server socket連接鹦肿,關(guān)閉client還好理解,server socket不是在Zygote進程嗎辅柴?
了解Linux的都知道箩溃,通過fork創(chuàng)建的子進程會繼承父進程的代碼、數(shù)據(jù)碌嘀,也就是:子進程除了自己的堆棧地址跟父進程不同外涣旨,其它數(shù)據(jù)都是直接從父進程拷貝過來的。那新創(chuàng)建的子進程股冗,肯定也是有一份ServerSocket實例拷貝霹陡,子進程在創(chuàng)建完成后當(dāng)然需要關(guān)閉。
2、為什么ActivityThread被稱為主線程烹棉?
首先攒霹,ActivityThread不是線程,被稱為主線程是因為:它運行在新進程的主線程中(當(dāng)然了浆洗,主線程就是進程中的第一個線程了催束,此處沒有額外再創(chuàng)建新線程,那肯定是主線程了)伏社。
2.5抠刺、invokeStaticMain | ZygoteInit.java
static void invokeStaticMain(ClassLoader loader,
String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
cl = loader.loadClass(className);
} 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 });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* This throw gets caught in ZygoteInit.main(), which responds
* by invoking the exception's run() method. This arrangement
* clears up all the stack frames that were required in setting
* up the process.
*/
throw new ZygoteInit.MethodAndArgsCaller(m, argv);
}
這個方法不寫注釋也能一眼看懂:
1、反射獲得入?yún)?yīng)的Class摘昌,此處入?yún)椋骸癮ndroid.app.ActivityThread”
2速妖、反射獲取main方法對應(yīng)的Method
3、新建MethodAndArgsCaller聪黎,并以異常形式拋出
- 前面都好理解罕容,關(guān)鍵是為什么要將main方法封裝成異常的形式拋出呢?
前面提到:子進程實際是從父進程將代碼數(shù)據(jù)拷貝而來挺举,父進程Zygote在死循環(huán)中創(chuàng)建了子進程杀赢,那子進程當(dāng)然也存在這份死循環(huán)的代碼。子進程通過異常拋出的形式湘纵,然后異常被捕獲脂崔,跳出死循環(huán),并在調(diào)用異常的run方法梧喷,在該run方法中調(diào)用被封裝的方法main砌左。
ActivityThread
至此,應(yīng)用進程已經(jīng)創(chuàng)建好了铺敌,并通過反射方式創(chuàng)建了ActivityThread的實例汇歹,然后調(diào)用該實例的main方法。那看下其main方法都做了啥:
3.1偿凭、main | ActivityThread.java
public static void main(String[] args) {
SamplingProfilerIntegration.start();
// CloseGuard defaults to true and can be quite spammy. We
// disable it here, but selectively enable it later (via
// StrictMode) on debug builds, but using DropBox, not logs.
CloseGuard.setEnabled(false);
Environment.initForCurrentUser();
// Set the reporter for event logging in libcore
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
Process.setArgV0("<pre-initialized>");
//為當(dāng)前線程創(chuàng)建Looper,并未改Looper創(chuàng)建關(guān)聯(lián)的MessageQueue
Looper.prepareMainLooper();
//創(chuàng)建實例
ActivityThread thread = new ActivityThread();
//入口
thread.attach(false);
//創(chuàng)建Handler产弹,即:H
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread"));
}
//mainLooper循環(huán)從消息隊列中取消息,并交給H處理
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
有代碼知弯囊,main方法創(chuàng)建了主線程關(guān)聯(lián)的Looper已經(jīng)H handler痰哨,這些相信大家都很熟了,但還是廢話幾句吧:
-
main方法在當(dāng)前進程的主線程中運行匾嘱,即主線程創(chuàng)建了Looper斤斧,并為Looper創(chuàng)建了關(guān)聯(lián)的消息隊列,以及handler H霎烙。創(chuàng)建完成后撬讽,調(diào)用Looper的loop方法蕊连,循環(huán)從消息隊列中取出消息交給Looper處理。
- 關(guān)于Looper游昼、MessageQueue甘苍、Handler以及Message的關(guān)系,大致如下:
- Looper與線程相關(guān)聯(lián)烘豌,在Looper類中采用線程局部變量保存每個線程關(guān)聯(lián)的Looper羊赵。主線程默認關(guān)聯(lián)一個Looper,即MainLooper扇谣;當(dāng)然也可以為子線程手動創(chuàng)建關(guān)聯(lián)的Looper,即調(diào)用Looper.prepare()方法闲昭。
- 每個Looper實例中罐寨,存在一個關(guān)聯(lián)的MessageQueue實例,調(diào)用Looper的prepare方法時序矩,會創(chuàng)建Looper實例鸯绿,以及Looper關(guān)聯(lián)的MessageQueue實例。調(diào)用Looper.loop()方法簸淀,Looper會循環(huán)去關(guān)聯(lián)的MessageQueue中取出消息處理瓶蝴。
- Handler,當(dāng)構(gòu)造Handler的實例時租幕,會獲取當(dāng)前線程關(guān)聯(lián)的Looper對象和MessageQueue對象引用舷手。調(diào)用handler發(fā)送消息時,實際是將消息放入到MessageQueue中劲绪。
- Message男窟,每個Message對象都關(guān)聯(lián)了一個target,該target就是發(fā)送該消息的Handler實例贾富。當(dāng)Looper從MessageQueue中取出消息時歉眷,會將消息發(fā)送給其關(guān)聯(lián)的target進行處理。(why:因為一個MessageQueue可能被多個handler引用颤枪。)
- 關(guān)于Looper游昼、MessageQueue甘苍、Handler以及Message的關(guān)系,大致如下:
方法中另外創(chuàng)建了一個ActivityThread的實例汗捡,并調(diào)用其attach方法,開始應(yīng)用的啟動畏纲。
3.2扇住、attach | ActivityThread.java
private void attach(boolean system) {
sCurrentActivityThread = this;
mSystemThread = system;
//普通App進這里
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run() {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>",
UserHandle.myUserId());
//VM中保存該應(yīng)用標志,用于上報錯誤
//mAppThread是Binder對象霍骄,AMS通過該對象實現(xiàn)與該應(yīng)用進程通信台囱,ActivityThread初始化時會創(chuàng)建該實例
RuntimeInit.setApplicationObject(mAppThread.asBinder());
//AMS代理
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
//AMS保存該應(yīng)用進程信息,通過該Binder實現(xiàn)與該應(yīng)用進程通信
mgr.attachApplication(mAppThread); //入口
} catch (RemoteException ex) {
// Ignore
}
} else {
......
}
......
}
- 該方法入?yún)閒alse读整,即普通應(yīng)用app簿训。
- 將應(yīng)用進程Binder關(guān)聯(lián)到VM,用于上報錯誤信息;
- 將應(yīng)用進程Binder關(guān)聯(lián)到AMS强品,用于AMS與該應(yīng)用進程通信膘侮;
- 最后,通過AIDL調(diào)用AMS的attachApplication方法的榛,所以此時又交由AMS來處理了琼了。
什么是應(yīng)用進程Binder?
在上文《沉思曲:Acitivity啟動》中提到夫晌,AMS通過持有應(yīng)用進程的Binder實現(xiàn)與應(yīng)用進程的通信雕薪。該Binder實現(xiàn)了IApplicationThread接口,實現(xiàn)是ApplicaitonThread晓淀。
3.3所袁、attachApplication | ActivityManagerService.java
public final void attachApplication(IApplicationThread thread) {
synchronized (this) {
//應(yīng)用進程pid
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
//入口
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
- 該方法繼續(xù)調(diào)用attachApplicationLocked方法。
- attachApplicationLocked方法主要是應(yīng)用進程進行校驗凶掰,并調(diào)用thread的bindApplication方法燥爷。thread就是上一方法中的入?yún)ⅲ簯?yīng)用進程Binder,實現(xiàn)為ApplicaitonThread懦窘,是Binder對象前翎。
- 由于thread是Binder對象,即應(yīng)用進程在AMS中的Binder對象畅涂,所以此處又由AMS進程切換到應(yīng)用進程中8刍!毅戈!
3.4苹丸、bindApplication | ActivityThread.java
note:ApplicaitonThread是ActivityThread的內(nèi)部類。
public final void bindApplication(String processName,
ApplicationInfo appInfo, List<ProviderInfo> providers,
ComponentName instrumentationName, String profileFile,
ParcelFileDescriptor profileFd, boolean autoStopProfiler,
Bundle instrumentationArgs, IInstrumentationWatcher instrumentationWatcher,
IUiAutomationConnection instrumentationUiConnection, int debugMode,
boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
Bundle coreSettings) {
if (services != null) {
// Setup the service cache in the ServiceManager
ServiceManager.initServiceCache(services);
}
setCoreSettings(coreSettings);
AppBindData data = new AppBindData();
data.processName = processName;
data.appInfo = appInfo;
data.providers = providers;
data.instrumentationName = instrumentationName;
data.instrumentationArgs = instrumentationArgs;
data.instrumentationWatcher = instrumentationWatcher;
data.instrumentationUiAutomationConnection = instrumentationUiConnection;
data.debugMode = debugMode;
data.enableOpenGlTrace = enableOpenGlTrace;
data.restrictedBackupMode = isRestrictedBackupMode;
data.persistent = persistent;
data.config = config;
data.compatInfo = compatInfo;
data.initProfileFile = profileFile;
data.initProfileFd = profileFd;
data.initAutoStopProfiler = false;
//發(fā)送消息到H苇经,消息類型為H.BIND_APPLICATION
queueOrSendMessage(H.BIND_APPLICATION, data);
}
該方法在應(yīng)用進程中赘理,調(diào)用H handler發(fā)送消息H.BIND_APPLICATION,看下H handler是如何處理該消息的扇单。
3.5商模、 H處理H.BIND_APPLICATION消息 | ActivityThread.java
case BIND_APPLICATION:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
AppBindData data = (AppBindData)msg.obj;
//入口
handleBindApplication(data);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
- 該方法接著調(diào)用 handleBindApplication
3.6、 handleBindApplication | ActivityThread.java
private void handleBindApplication(AppBindData data) {
mBoundApplication = data;
mConfiguration = new Configuration(data.config);
mCompatConfiguration = new Configuration(data.config);
mProfiler = new Profiler();
mProfiler.profileFile = data.initProfileFile;
mProfiler.profileFd = data.initProfileFd;
mProfiler.autoStopProfiler = data.initAutoStopProfiler;
//設(shè)置進程名
Process.setArgV0(data.processName);
android.ddm.DdmHandleAppName.setAppName(data.processName,
UserHandle.myUserId());
//是否開啟硬件加速
if (data.persistent) {
if (!ActivityManager.isHighEndGfx()) {
HardwareRenderer.disable(false);
}
}
if (mProfiler.profileFd != null) {
mProfiler.startProfiling();
}
//Honeycomb MR1版本前蜘澜,設(shè)置AsyncTask的底層由線程池實現(xiàn)
if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
//設(shè)置TimeZone施流、Locale
TimeZone.setDefault(null);
Locale.setDefault(data.config.locale);
//更新系統(tǒng)設(shè)置,AppBindData中配置默認是最新的
mResourcesManager.applyConfigurationToResourcesLocked(data.config, data.compatInfo);
mCurDefaultDisplayDpi = data.config.densityDpi;
applyCompatConfiguration(mCurDefaultDisplayDpi);
//獲取Package信息鄙信,返回LoadedApk對象瞪醋。先從緩存讀,沒有則創(chuàng)建装诡。
data.info = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
//設(shè)置分辨率信息
if ((data.appInfo.flags&ApplicationInfo.FLAG_SUPPORTS_SCREEN_DENSITIES)
== 0) {
mDensityCompatMode = true;
Bitmap.setDefaultDensity(DisplayMetrics.DENSITY_DEFAULT);
}
updateDefaultDensity();
//創(chuàng)建ContextImpl實例
final ContextImpl appContext = new ContextImpl();
appContext.init(data.info, null, this);
if (!Process.isIsolated()) {
final File cacheDir = appContext.getCacheDir();
if (cacheDir != null) {
// Provide a usable directory for temporary files
System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath());
setupGraphicsSupport(data.info, cacheDir);
} else {
Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
}
}
//系統(tǒng)應(yīng)用银受,開啟debug log
if ((data.appInfo.flags &
(ApplicationInfo.FLAG_SYSTEM |
ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)) != 0) {
StrictMode.conditionallyEnableDebugLogging();
}
//Honeycomb版本以后践盼,不允許在主線程進行網(wǎng)絡(luò)操作
if (data.appInfo.targetSdkVersion > 9) {
StrictMode.enableDeathOnNetwork();
}
//設(shè)置debug
......
// 是否啟動GL
if (data.enableOpenGlTrace) {
GLUtils.setTracingLevel(1);
}
// Allow application-generated systrace messages if we're debuggable.
boolean appTracingAllowed = (data.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0;
Trace.setAppTracingAllowed(appTracingAllowed);
//設(shè)置time zone時,走http代理宾巍;通過ConnectivityManager設(shè)置
IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
if (b != null) {
IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
try {
ProxyProperties proxyProperties = service.getProxy();
Proxy.setHttpProxySystemProperty(proxyProperties);
} catch (RemoteException e) {}
}
//是否指定trumentation類名咕幻,難道可以指定?顶霞!
if (data.instrumentationName != null) {
InstrumentationInfo ii = null;
try {
//獲取Instrumentation信息
ii = appContext.getPackageManager().
getInstrumentationInfo(data.instrumentationName, 0);
}
......
mInstrumentationAppDir = ii.sourceDir;
mInstrumentationAppLibraryDir = ii.nativeLibraryDir;
mInstrumentationAppPackage = ii.packageName;
mInstrumentedAppDir = data.info.getAppDir();
mInstrumentedAppLibraryDir = data.info.getLibDir();
//創(chuàng)建ApplicationInfo肄程,用來保存應(yīng)用信息
ApplicationInfo instrApp = new ApplicationInfo();
instrApp.packageName = ii.packageName;
instrApp.sourceDir = ii.sourceDir;
instrApp.publicSourceDir = ii.publicSourceDir;
instrApp.dataDir = ii.dataDir;
instrApp.nativeLibraryDir = ii.nativeLibraryDir;
//創(chuàng)建LoadedApk實例,保存應(yīng)用APK信息
LoadedApk pi = getPackageInfo(instrApp, data.compatInfo,
appContext.getClassLoader(), false, true);
//創(chuàng)建應(yīng)用關(guān)聯(lián)的CotextImpl
ContextImpl instrContext = new ContextImpl();
instrContext.init(pi, null, this);
try {
java.lang.ClassLoader cl = instrContext.getClassLoader();
//為應(yīng)用創(chuàng)建指定的Instrumentation實例
mInstrumentation = (Instrumentation)
cl.loadClass(data.instrumentationName.getClassName()).newInstance();
}
......
//init选浑,保存應(yīng)用信息到Instrumentation
mInstrumentation.init(this, instrContext, appContext,
new ComponentName(ii.packageName, ii.name), data.instrumentationWatcher,
data.instrumentationUiAutomationConnection);
......
} else {
//未指定Instrmentation名稱蓝厌,創(chuàng)建默認Instrumentation
mInstrumentation = new Instrumentation();
}
if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) {
dalvik.system.VMRuntime.getRuntime().clearGrowthLimit();
}
//允許application和provider啟動時訪問disk
final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskWrites();
try {
//創(chuàng)建Application實例
Application app = data.info.makeApplication(data.restrictedBackupMode, null);
mInitialApplication = app;
//restricted模式下,c處理provider
if (!data.restrictedBackupMode) {
List<ProviderInfo> providers = data.providers;
if (providers != null) {
installContentProviders(app, providers);
mH.sendEmptyMessageDelayed(H.ENABLE_JIT, 10*1000);
}
}
try {
//調(diào)用Instrumentation的onCreate方法古徒,用于Applicaiton啟動onCreate()啟動前的操作
mInstrumentation.onCreate(data.instrumentationArgs);
}
......
try {
//Instrumentation回調(diào)應(yīng)用Applicaiton的onCreate褂始,啟動應(yīng)用
mInstrumentation.callApplicationOnCreate(app);
}
......
}
該方法負責(zé)啟動應(yīng)用:
- 設(shè)置進程名、是否開啟硬件加速
- 設(shè)置AsyncTask的底層實現(xiàn)方式
- 設(shè)置TimeZone描函、Locale
- 設(shè)置分辨率、不允許主線程網(wǎng)絡(luò)操作等
- 為應(yīng)用進程設(shè)置Instrumentation狐粱,用于管理應(yīng)用進程
- 通過Instrumentation調(diào)用應(yīng)用Applicationde 的onCreate方法舀寓,實現(xiàn)應(yīng)用的啟動等
- 設(shè)置timezone、openGl等信息后肌蜻,創(chuàng)建Instrumentation用于管理該應(yīng)用進程互墓,最后并回調(diào)該應(yīng)用的Application的onCreate方法啟動應(yīng)用。
至此蒋搜,本文內(nèi)容就差不多結(jié)束了篡撵,后面應(yīng)用的啟動就不講了,感興趣的可以看源碼豆挽,大同小異。
總結(jié)
三篇文章到此結(jié)束了膛檀,三文粗略的分析了Android系統(tǒng)啟動娘侍、Activity啟動咖刃、ActivityThread創(chuàng)建三部分內(nèi)容。內(nèi)容都是整理之前資料得到的嚎杨,網(wǎng)上關(guān)于這部分內(nèi)容的資料也很多氧腰,但都比較零散刨肃。這里把這部分內(nèi)容整理出來,一來備忘自脯,二來拋磚引玉。本人才疏學(xué)淺膏潮,大部分內(nèi)容都是自己理解加注釋,有不當(dāng)錯誤之處轻纪,懇請指正~