記錄進階解密學習,再看源碼層面思路不會那麼雜亂無章,有了一個很清晰的脈絡。
啟動過程
啟動過程可以分為兩步:
-
AMS 發送啟動應用程式程序請求
AMS 如果想要啟動應用程式程序,就需要向 Zygote 程序發送建立應用程式程序的請求,AMS 會通過調用 startProcessLocked 方法向 Zygote 程序發送請求。
- Zygote 接收請求并建立應用程式程序
出處。
一 AMS 發送啟動應用程式程序請求
時序圖如下
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5CO2UTOwEmYzEjZxYDNjlTN0QTMyUDMmZ2M0kDNwADN28CX0JXZ252bj91Ztl2Lc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
AMS 啟動應用程式程序,向 Zygote 程序發送建立應用程式程序的請求, AMS 會通過調用 startProcessLocked 函數向 Zygote 程序發送請求 代碼如下:
//com.android.server.am; ActivityManagerService.java
/**
* 啟動程序的函數
* @param app
* @param hostingType
* @param hostingNameStr
* @param abiOverride
* @param entryPoint
* @param entryPointArgs
*/
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();
}
1. 擷取要建立的應用程式程序的 使用者 id
int uid = app.uid;
int[] gids = null;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
...
2. 對 gids 進行建立和指派
if (ArrayUtils.isEmpty(permGids)) {
gids = new int[3];
} else {
gids = new int[permGids.length + 3];
System.arraycopy(permGids, 0, gids, 3, permGids.length);
}
gids[0] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
gids[1] = UserHandle.getCacheAppGid(UserHandle.getAppId(uid));
gids[2] = UserHandle.getUserGid(UserHandle.getUserId(uid));
}
...
boolean isActivityProcess = (entryPoint == null);
3. 如果 entryPoint == null 那麼将 ActivityThread 全類名指派給 entryPoint
if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
ProcessStartResult startResult;
if (hostingType.equals("webview_service")) {
startResult = startWebView(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, null, entryPointArgs);
} else {
4. 在 AMS 中調用 start 函數進行通知 Zygote fork 程序
startResult = Process.start(entryPoint,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
app.info.dataDir, invokeWith, entryPointArgs);
}
...
}
總結上面主要做了4個步驟
1 擷取建立應用程式程序的使用者 ID
2 對使用者組 ID(gids)進行建立和指派
3 如果 entryPoint 為 null ,就把 ActivityThread 全類名指派給它
4 調用 Process 的 start 函數
我們看下 Process 的 start 函數:
//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 invokeWith,
String[] zygoteArgs) {
1. 通過 ZygoteProcess 調用 start 函數
return zygoteProcess.start(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
}
ZygoteProcess 的Start 調用了startViaZygote 方法
//android.os; ZygoteProcess.java
public final Process.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 invokeWith,
String[] zygoteArgs) {
try {
1
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
private Process.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 invokeWith,
String[] extraArgs)
throws ZygoteStartFailedEx {
//建立字元串清單argsForZygote 并将應用程序的啟動參數儲存到argsForZygote
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-args, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-args");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
synchronized(mLock) {
2
return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
看2 處的openZygoteSocketIfNeeded
//android.os; ZygoteProcess.java
@GuardedBy("mLock")
private ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
Preconditions.checkState(Thread.holdsLock(mLock), "ZygoteProcess lock not held");
if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
try {
1
primaryZygoteState = ZygoteState.connect(mSocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
}
}
2
if (primaryZygoteState.matches(abi)) {
return primaryZygoteState;
}
// 如果不比對,則嘗試連接配接 zygote 輔模式
if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
try {
3
secondaryZygoteState = ZygoteState.connect(mSecondarySocket);
} catch (IOException ioe) {
throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
}
}
4
if (secondaryZygoteState.matches(abi)) {
return secondaryZygoteState;
}
//如果都不比對那麼就抛一個異常
throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
}
總結如上方法
1 連接配接 zygote 名稱為 "zygote" 服務端的 Socket ,建立程序間通信
2 連接配接 Zygote 主模式傳回的 ZygoteState 是否與啟動應用程式程序所需要的 ABI 比對
3 如果不比對那麼就嘗試連接配接 name 為 "zygote_secondary" 的 Socket
4 連接配接 Zygote 輔模式傳回的 ZygoteState 是否與啟動應用程式程序所需要的 ABI 比對
連接配接成功zygoteSendArgsAndGetResult 做了些什麼
//android.os; ZygoteProcess.java
private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
...
final BufferedWriter writer = zygoteState.writer;
final DataInputStream inputStream = zygoteState.inputStream;
writer.write(Integer.toString(args.size()));
writer.newLine();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
writer.write(arg);
writer.newLine();
}
writer.flush();
...
}
return result;
} catch (IOException ex) {
zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
zygote 程序的服務端 Socket 連接配接成功,那麼就将存儲起來的應用程式程序啟動參數寫入到 ZygoteState 中 .ZygoteState是ZygoteProcess的靜态内部類,表示與Zygote的狀态。
二 Zygote 接收請求并建立應用程式程序
SystemServer 跟應用程序啟動在 Zygote 處理 的方式相似,看下時序圖
服務端的Socket的建立
//com.android.internal.os.ZygoteInit.java
public static void main(String argv[]) {
....
try {
1
zygoteServer.registerServerSocket(socketName);
if (!enableLazyPreload) {
bootTimingsTraceLog.traceBegin("ZygotePreload");
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
2
preload(bootTimingsTraceLog);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
bootTimingsTraceLog.traceEnd(); // ZygotePreload
} else {
Zygote.resetNicePriority();
}
...
if (startSystemServer) {
3
startSystemServer(abiList, socketName, zygoteServer);
}
Log.i(TAG, "Accepting command socket connections");
4
zygoteServer.runSelectLoop(abiList);
//清理或者關閉對應的 Socket
zygoteServer.closeServerSocket();
} catch (Zygote.MethodAndArgsCaller caller) {
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
總結如上步驟
1 建立服務端的 Socket ,名稱為 "zygote"
2 用來預加載資源
3 啟動 SystemServer 程序
4 等待 AMS 請求建立新的應用程式程序
看下zygoteServer.runSelectLoop(abiList); 方法
// com.android.internal.os ZygoteInit.main->runSelectLoop
void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
1
fds.add(mServerSocket.getFileDescriptor());
peers.add(null);
死循環等待 AMS 的請求
while (true) {
StructPollfd[] pollFds = new StructPollfd[fds.size()];
2
for (int i = 0; i < pollFds.length; ++i) {
pollFds[i] = new StructPollfd();
pollFds[i].fd = fds.get(i);
pollFds[i].events = (short) POLLIN;
}
try {
Os.poll(pollFds, -1);
} catch (ErrnoException ex) {
throw new RuntimeException("poll failed", ex);
}
3
for (int i = pollFds.length - 1; i >= 0; --i) {
if ((pollFds[i].revents & POLLIN) == 0) {
continue;
}
//如果 i == 0 那麼就認為 服務端 Socket 與用戶端連接配接上了,就是與 AMS 建立了連接配接
if (i == 0) {
4
ZygoteConnection newPeer = acceptCommandPeer(abiList);
//将 ZygoteConnection 添加到 Socket 連接配接清單中
peers.add(newPeer);
//将 ZygoteConnection 的檔案描述符 添加到 fds 清單中
fds.add(newPeer.getFileDesciptor());
} else {//如果不等于 0 ,那麼就說明 AMS 向 Zygote 發送了一個建立應用程序的請求
5
boolean done = peers.get(i).runOnce(this);
if (done) {
peers.remove(i);
fds.remove(i);
}
}
}
}
}
上述方法的主要作用
1. 添加獲得該 Socket 的 fd 字段的值
2. 将 fds 資訊轉存到 pollFds 數組中。
3 對 pollFds 資訊進行周遊
4 添加到 Socket 連接配接清單中
5 調用 ZygoteConnection 的 runOnce 函數來建立一個新的應用程序,并在成功建立後将這個連接配接從 Socket 連接配接清單中 peers、fd 清單中關閉
如果 AMS 發來了一個新的請求任務,會走5 處通過 peers.get(i).runOnce(this); 來處理請求資料,我們看 runOnce 函數具體實作:
//com.android.internal.os; ZygoteConnection.java
boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
1. 擷取應用程式程序的啟動參數
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
...
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
try {
2. 将擷取到啟動應用程式程序的啟動參數 args 數組 封裝到 Arguments 類型的 parsedArgs 對象中
parsedArgs = new Arguments(args);
...
fd = null;
3. 通過 Zygote 來建立應用程式程序
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
parsedArgs.appDataDir);
} catch (ErrnoException ex) {
...
}
try {
//目前代碼邏輯運作在被建立出來的子程序中
if (pid == 0) {
// in child
zygoteServer.closeServerSocket();
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
4. 處理應用程式程序
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw Zygote.MethodAndArgsCaller or exec().
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);
}
}
Zygote.forkAndSpecialize主要通過建立fork目前程式建立一個子程式的,如果pid等于0 則說明目前的 代碼邏輯運作在新建立的子程序的應用程式當中。我們這裡來看下 handleChildProc怎麼處理應用程式程序
//com.android.internal.os; ZygoteConnection.java
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws Zygote.MethodAndArgsCaller {
...
if (parsedArgs.invokeWith != null) {
...
} else {
//調用 ZygoteInit 的 zygoteInit 函數
ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs, null /* classLoader */);
}
}
// com.android.internal.os ZygoteInit
public static final void zygoteInit(int targetSdkVersion, String[] argv,
ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
if (RuntimeInit.DEBUG) {
Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
}
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
RuntimeInit.redirectLogStreams();
RuntimeInit.commonInit();
1. 啟動 Binder 線程池
ZygoteInit.nativeZygoteInit();
2. 進入 ActivityThread 的 main 方法
RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}
1 處先啟動 Binder 線程池,用于程序間通信,接下來看applicationInit 處理了什麼
//com.android.internal.os RuntimeInit.java
protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller {
...
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws Zygote.MethodAndArgsCaller
{
Class<?> cl;
try {
1
cl = Class.forName(className, true, classLoader);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
2
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
...
} catch (SecurityException ex) {
...
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
...
}
3
throw new Zygote.MethodAndArgsCaller(m, argv);
}
總結如上方法做了3件事:
1 通過 className("android.app.ActivityThread" )反射得到 ActivityThread 類
2 擷取ActivityThread的main的方法,并将main的方法傳入3處的Zygote中的MethodAndArhsCaller類的構造方法當中
3将 m 、argv 傳入 MethodAndArgsCaller,然後抛一個異常,并在 ZygoteInit.main 中進行捕獲異常
//com.android.internal.os.ZygoteInit.java
public static void main(String argv[]) {
....
try {
1
zygoteServer.registerServerSocket(socketName);
2
zygoteServer.runSelectLoop(abiList);
} catch (Zygote.MethodAndArgsCaller caller) {
3
caller.run();
} catch (Throwable ex) {
Log.e(TAG, "System zygote died with exception", ex);
zygoteServer.closeServerSocket();
throw ex;
}
}
1 建立服務端的 Socket ,名稱為 "zygote"
2. 等待 AMS 請求
3. 捕獲到 RuntimeInit applicationInit 中的異常
看 RuntimeInit applicationInit 中的異常,然後看它的 run 函數
com.android.internal.os Zygote.java
public static class MethodAndArgsCaller extends Exception
implements Runnable {
/** method to call */
private final Method mMethod;
/** argument array */
private final String[] mArgs;
public MethodAndArgsCaller(Method method, String[] args) {
mMethod = method;
mArgs = args;
}
public void run() {
try {
1. 這裡就開始執行 ActivityThread main 方法了
mMethod.invoke(null, new Object[] { mArgs });
} catch (IllegalAccessException ex) {
throw new RuntimeException(ex);
} catch (InvocationTargetException ex) {
Throwable cause = ex.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
}
throw new RuntimeException(ex);
}
}
}
至此應用程式的程序建立和 應用程式程序的入口 ActivityThread main 都已經執行,我們看下ActivityThread消息的建立處理
//android.app; ActivityThread.java
//通過 ZygoteInit 反射調用執行的
public static void main(String[] args) {
...
1
Looper.prepareMainLooper();
2
ActivityThread thread = new ActivityThread();
thread.attach(false);
3
if (sMainThreadHandler == null) {
sMainThreadHandler = thread.getHandler();
}
4
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited");
}
1 主線程消息循環 Looper 建立
2 建立 ActivityThread 對象
3 拿到H類的Hander并且 指派給sMainThreadHandler
4 開啟 Looper開啟了循環,使得Looper開始處理消息。
通過對系統源碼的源碼的分析,對系統程序、系統桌面 Launcher 程序、應用程式程序的啟動過程,Binder,Hander的更加深的了解, 後續将對四大元件啟動流程進行分析.