Android 10.0系統啟動之Zygote進程(三)-「Android取經之路」

Android 10.0系統啟動之Zygote進程(三)-「Android取經之路」

前幾節已經講完了Android10.0的Init啟動過程以及Zygote的架構。






這一節開始分析Zygote在 JAVA 世界的啟動源碼。

4.2 Java世界的Zygote啟動主要代碼調用流程:

上節我們通過JNI調用ZygoteInit的main函數後,Zygote便進入了Java框架層,此前沒有任何代碼進入過Java框架層,換句換說Zygote開創了Java框架層。

Android 10.0系統啟動之Zygote進程(三)-「Android取經之路」

4.2.1 [ZygoteInit.java]main.cpp

path:frameworks\\base\\core\\java\\com\\android\\internal\\os\\ZygoteInit.java

main的主要工作:

1.調用preload()來預加載類和資源

2.調用ZygoteServer()創建兩個Server端的Socket--/dev/socket/zygote 和 /dev/socket/zygote_secondary,Socket用來等待ActivityManagerService來請求Zygote來創建新的應用程序進程。

3.調用forkSystemServer 來啟動SystemServer進程,這樣系統的關鍵服務也會由SystemServer進程啟動起來。

4.最後調用runSelectLoop函數來等待客戶端請求

後面我們主要來分析這四件事。

public static void main(String argv[]) {
// 1.創建ZygoteServer
ZygoteServer zygoteServer = null;
// 調用native函數,確保當前沒有其它線程在運行
ZygoteHooks.startZygoteNoThreadCreation();
//設置pid為0,Zygote進入自己的進程組
Os.setpgid(0, 0);
......
Runnable caller;
try {
......
//得到systrace的監控TAG
String bootTimeTag = Process.is64Bit() ? "Zygote64Timing" : "Zygote32Timing";
TimingsTraceLog bootTimingsTraceLog = new TimingsTraceLog(bootTimeTag,
Trace.TRACE_TAG_DALVIK);
//通過systradce來追蹤 函數ZygoteInit, 可以通過systrace工具來進行分析
//traceBegin 和 traceEnd 要成對出現,而且需要使用同一個tag

bootTimingsTraceLog.traceBegin("ZygoteInit");
//開啟DDMS(Dalvik Debug Monitor Service)功能
//註冊所有已知的Java VM的處理塊的監聽器。線程監聽、內存監聽、native 堆內存監聽、debug模式監聽等等
RuntimeInit.enableDdms();
boolean startSystemServer = false;
String zygoteSocketName = "zygote";
String abiList = null;
boolean enableLazyPreload = false;

//2. 解析app_main.cpp - start()傳入的參數
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true; //啟動zygote時,才會傳入參數:start-system-server
} else if ("--enable-lazy-preload".equals(argv[i])) {
enableLazyPreload = true; //啟動zygote_secondary時,才會傳入參數:enable-lazy-preload
} else if (argv[i].startsWith(ABI_LIST_ARG)) { //通過屬性ro.product.cpu.abilist64\\ro.product.cpu.abilist32 從C空間傳來的值
abiList = argv[i].substring(ABI_LIST_ARG.length());
} else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
zygoteSocketName = argv[i].substring(SOCKET_NAME_ARG.length()); //會有兩種值:zygote和zygote_secondary
} else {

throw new RuntimeException("Unknown command line argument: " + argv[i]);

}

}

// 根據傳入socket name來決定是創建socket還是zygote_secondary

final boolean isPrimaryZygote = zygoteSocketName.equals(Zygote.PRIMARY_SOCKET_NAME);

// 在第一次zygote啟動時,enableLazyPreload為false,執行preload

if (!enableLazyPreload) {

//systrace 追蹤 ZygotePreload

bootTimingsTraceLog.traceBegin("ZygotePreload");

EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,

SystemClock.uptimeMillis());

// 3.加載進程的資源和類,參考[4.2.2]

preload(bootTimingsTraceLog);

EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,

SystemClock.uptimeMillis());

//systrae結束 ZygotePreload的追蹤

bootTimingsTraceLog.traceEnd(); // ZygotePreload

} else {

// 延遲預加載, 變更Zygote進程優先級為NORMAL級別,第一次fork時才會preload

Zygote.resetNicePriority();

}

//結束ZygoteInit的systrace追蹤

bootTimingsTraceLog.traceEnd(); // ZygoteInit

//禁用systrace追蹤,以便fork的進程不會從zygote繼承過時的跟蹤標記

Trace.setTracingEnabled(false, 0);

// 4.調用ZygoteServer 構造函數,創建socket,會根據傳入的參數,

// 創建兩個socket:/dev/socket/zygote 和 /dev/socket/zygote_secondary

//參考[4.2.3]

zygoteServer = new ZygoteServer(isPrimaryZygote);

if (startSystemServer) {


//5. fork出system server,參考[4.2.4]

Runnable r = forkSystemServer(abiList, zygoteSocketName, zygoteServer);

// 啟動SystemServer

if (r != null) {

r.run();

return;

}

}

// 6. zygote進程進入無限循環,處理請求

caller = zygoteServer.runSelectLoop(abiList);

} catch (Throwable ex) {

Log.e(TAG, "System zygote died with exception", ex);

throw ex;

} finally {

if (zygoteServer != null) {

zygoteServer.closeServerSocket();

}

}

// 7.在子進程中退出了選擇循環。繼續執行命令

if (caller != null) {

caller.run();

}

}

日誌:

01-10 11:20:32.219 722 722 D Zygote : begin preload
01-10 11:20:32.219 722 722 I Zygote : Calling ZygoteHooks.beginPreload()

01-10 11:20:32.249 722 722 I Zygote : Preloading classes...

01-10 11:20:33.179 722 722 I Zygote : ...preloaded 7587 classes in 926ms.

01-10 11:20:33.449 722 722 I Zygote : Preloading resources...

01-10 11:20:33.459 722 722 I Zygote : ...preloaded 64 resources in 17ms.

01-10 11:20:33.519 722 722 I Zygote : Preloading shared libraries...

01-10 11:20:33.539 722 722 I Zygote : Called ZygoteHooks.endPreload()

01-10 11:20:33.539 722 722 I Zygote : Installed AndroidKeyStoreProvider in 1ms.

01-10 11:20:33.549 722 722 I Zygote : Warmed up JCA providers in 11ms.

01-10 11:20:33.549 722 722 D Zygote : end preload

01-10 11:2:33.649 722 722 D Zygote : Forked child process 1607

01-10 11:20:33.649 722 722 I Zygote : System server process 1607 has been created
01-10 11:20:33.649 722 722 I Zygote : Accepting command socket connections
10-15 06:11:07.749 722 722 D Zygote : Forked child process 2982
10-15 06:11:07.789 722 722 D Zygote : Forked child process 3004

4.2.2 [ZygoteInit.java] preload()

 static void preload(TimingsTraceLog bootTimingsTraceLog) {
Log.d(TAG, "begin preload");
·
}

什麼是預加載:

預加載是指在zygote進程啟動的時候就加載,這樣系統只在zygote執行一次加載操作,所有APP用到該資源不需要再重新加載,減少資源加載時間,加快了應用啟動速度,一般情況下,系統中App共享的資源會被列為預加載資源。

zygote fork子進程時,根據fork的copy-on-write機制可知,有些類如果不做改變,甚至都不用複製,子進程可以和父進程共享這部分數據,從而省去不少內存的佔用。

預加載的原理:

zygote進程啟動後將資源讀取出來,保存到Resources一個全局靜態變量中,下次讀取系統資源的時候優先從靜態變量中查找。

frameworks/base/config/preloaded-classes:

參考:

Android 10.0系統啟動之Zygote進程(三)-「Android取經之路」

相關日誌:

01-10 11:20:32.219 722 722 D Zygote : begin preload
01-10 11:20:32.219 722 722 I Zygote : Calling ZygoteHooks.beginPreload()
01-10 11:20:32.249 722 722 I Zygote : Preloading classes...
01-10 11:20:33.179 722 722 I Zygote : ...preloaded 7587 classes in 926ms.
01-10 11:20:33.539 722 722 I Zygote : Called ZygoteHooks.endPreload()
01-10 11:20:33.549 722 722 D Zygote : end preload

4.2.3 [ZygoteServer.java] ZygoteServer()

path: frameworks\\base\\core\\java\\com\\android\\internal\\os\\ZygoteServer.java

作用:ZygoteServer 構造函數初始化時,根據傳入的參數,利用LocalServerSocket 創建了4個本地服務端的socket,用來建立連接,

分別是:zygote、usap_pool_primary、zygote_secondary、usap_pool_secondary

 private LocalServerSocket mZygoteSocket;
private LocalServerSocket mUsapPoolSocket;

//創建zygote的socket
ZygoteServer(boolean isPrimaryZygote) {
mUsapPoolEventFD = Zygote.getUsapPoolEventFD();
if (isPrimaryZygote) {
//創建socket,並獲取socket對象,socketname: zygote
mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.PRIMARY_SOCKET_NAME);
//創建socket,並獲取socket對象,socketname:usap_pool_primary
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_PRIMARY_SOCKET_NAME);
} else {
//創建socket,並獲取socket對象,socketname: zygote_secondary

mZygoteSocket = Zygote.createManagedSocketFromInitSocket(Zygote.SECONDARY_SOCKET_NAME);

//創建socket,並獲取socket對象,socketname: usap_pool_secondary
mUsapPoolSocket =
Zygote.createManagedSocketFromInitSocket(
Zygote.USAP_POOL_SECONDARY_SOCKET_NAME);
}

fetchUsapPoolPolicyProps();
mUsapPoolSupported = true;
}


static LocalServerSocket createManagedSocketFromInitSocket(String socketName) {
int fileDesc;
// ANDROID_SOCKET_PREFIX為"ANDROID_SOCKET_"
//加入傳入參數為zygote,則fullSocketName:ANDROID_SOCKET_zygote
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
//init.zygote64_32.rc啟動時,指定了4個socket:
//分別是zygote、usap_pool_primary、zygote_secondary、usap_pool_secondary
// 在進程被創建時,就會創建對應的文件描述符,並加入到環境變量中
// 這裡取出對應的環境變量
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException("Socket unset or invalid: " + fullSocketName, ex);
}

try {
FileDescriptor fd = new FileDescriptor();

fd.etInt$(fileDesc); // 獲取zygote socket的文件描述符

return new LocalServerSocket(fd); // 創建Socket的本地服務端

} catch (IOException ex) {

throw new RuntimeException(

"Error building socket from file descriptor: " + fileDesc, ex);

}


}

path: \\frameworks\\base\\core\\java\\android\\net\\LocalServerSocket.java

public LocalServerSocket(FileDescriptor fd) throws IOException

{

impl = new LocalSocketImpl(fd);

impl.listen(LISTEN_BACKLOG);

localAddress = impl.getSockAddress();

}

path: \\frameworks\\base\\core\\java\\android\\net\\LocalServerSocket.java

 public LocalServerSocket(FileDescriptor fd) throws IOException
{
impl = new LocalSocketImpl(fd);
impl.listen(LISTEN_BACKLOG);
localAddress = impl.getSockAddress();
}

4.2.4 [ZygoteInit.java] forkSystemServer()

 private static Runnable forkSystemServer(String abiList, String socketName,
ZygoteServer zygoteServer) {

long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_IPC_LOCK,
OsConstants.CAP_KILL,
OsConstants.CAP_NET_ADMIN,
OsConstants.CAP_NET_BIND_SERVICE,
OsConstants.CAP_NET_BROADCAST,
OsConstants.CAP_NET_RAW,
OsConstants.CAP_SYS_MODULE,
OsConstants.CAP_SYS_NICE,
OsConstants.CAP_SYS_PTRACE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG,
OsConstants.CAP_WAKE_ALARM,
OsConstants.CAP_BLOCK_SUSPEND
);

......

//參數準備

/* Hardcoded command line to start the system server */
String args[] = {
"--setuid=1000",
"--setgid=1000",
"--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1023,"
+ "1024,1032,1065,3001,3002,3003,3006,3007,3009,3010",
"--capabilities=" + capabilities + "," + capabilities,
"--nice-name=system_server",
"--runtime-args",
"--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
"com.android.server.SystemServer",
};

ZygoteArguments parsedArgs = null;
int pid;

try {
//將上面準備的參數,按照ZygoteArguments的風格進行封裝
parsedArgs = new ZygoteArguments(args);
Zygote.applyDebuggerSystemProperty(parsedArgs);
Zygote.applyInvokeWithSystemProperty(parsedArgs);
boolean profileSystemServer = SystemProperties.getBoolean(
"dalvik.vm.profilesystemserver", false);
if (profileSystemServer) {
parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
}

//通過fork"分裂"出子進程system_server
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.mUid, parsedArgs.mGid,
parsedArgs.mGids,
parsedArgs.mRuntimeFlags,
null,
parsedArgs.mPermittedCapabilities,
parsedArgs.mEffectiveCapabilities);
} catch (IllegalArgumentException ex) {
\tthrow new RuntimeException(ex);
}

//進入子進程system_server
/* For child process */
if (pid == 0) {
// 處理32_64和64_32的情況
if (hasSecondZygote(abiList)) {
\twaitForSecondaryZygote(socketName);
}


// fork時會copy socket,system server需要主動關閉
zygoteServer.closeServerSocket();
// system server進程處理自己的工作
return handleSystemServerProcess(parsedArgs);
}
\treturn null;
}


ZygoteInit。forkSystemServer()會在新fork出的子進程中調用 handleSystemServerProcess(),

主要是返回Runtime.java的MethodAndArgsCaller的方法,然後通過r.run() 啟動com.android.server.SystemServer的main 方法

這個當我們後面的SystemServer的章節進行詳細講解。

handleSystemServerProcess代碼流程:

 handleSystemServerProcess()
|
[ZygoteInit.java]
zygoteInit()
\t\t|
[RuntimeInit.java]
applicationInit()
\t\t|
findStaticMain()
\t\t|
MethodAndArgsCaller()

4.2.5 [ZygoteServer.java] runSelectLoop()

path: frameworks\\base\\core\\java\\com\\android\\internal\\os\\ZygoteServer.java

 Runnable runSelectLoop(String abiList) {
ArrayList<filedescriptor> socketFDs = new ArrayList<filedescriptor>();

ArrayList<zygoteconnection> peers = new ArrayList<zygoteconnection>();

// 首先將server socket加入到fds

socketFDs.add(mZygoteSocket.getFileDescriptor());

peers.add(null);

while (true) {

fetchUsapPoolPolicyPropsWithMinInterval();

int[] usapPipeFDs = null;

StructPollfd[] pollFDs = null;

// 每次循環,都重新創建需要監聽的pollFds

// Allocate enough space for the poll structs, taking into account

// the state of the USAP pool for this Zygote (could be a

// regular Zygote, a WebView Zygote, or an AppZygote).

if (mUsapPoolEnabled) {

usapPipeFDs = Zygote.getUsapPipeFDs();

pollFDs = new StructPollfd[socketFDs.size() + 1 + usapPipeFDs.length];

} else {

pollFDs = new StructPollfd[socketFDs.size()];

}

/*

* For reasons of correctness the USAP pool pipe and event FDs

* must be processed before the session and server sockets. This

* is to ensure that the USAP pool accounting information is

* accurate when handling other requests like API blacklist

* exemptions.

*/

int pollIndex = 0;

for (FileDescriptor socketFD : socketFDs) {

// 關注事件到來


pollFDs[pollIndex] = new StructPollfd();

pollFDs[pollIndex].fd = socketFD;

pollFDs[pollIndex].events = (short) POLLIN;

++pollIndex;

}

final int usapPoolEventFDIndex = pollIndex;

if (mUsapPoolEnabled) {

pollFDs[pollIndex] = new StructPollfd();

pollFDs[pollIndex].fd = mUsapPoolEventFD;

pollFDs[pollIndex].events = (short) POLLIN;

++pollIndex;

for (int usapPipeFD : usapPipeFDs) {

FileDescriptor managedFd = new FileDescriptor();

managedFd.setInt$(usapPipeFD);

pollFDs[pollIndex] = new StructPollfd();

pollFDs[pollIndex].fd = managedFd;

pollFDs[pollIndex].events = (short) POLLIN;

++pollIndex;

}

}

try {

// 等待事件到來

Os.poll(pollFDs, -1);

} catch (ErrnoException ex) {

throw new RuntimeException("poll failed", ex);


}

boolean usapPoolFDRead = false;

//倒序處理,即優先處理已建立鏈接的信息,後處理新建鏈接的請求

while (--pollIndex >= 0) {

if ((pollFDs[pollIndex].revents & POLLIN) == 0) {

continue;

}

// server socket最先加入fds, 因此這裡是server socket收到數據

if (pollIndex == 0) {

// 收到新的建立通信的請求,建立通信連接

ZygoteConnection newPeer = acceptCommandPeer(abiList);

// 加入到peers和fds, 即下一次也開始監聽

peers.add(newPeer);

socketFDs.add(newPeer.getFileDescriptor());

} else if (pollIndex < usapPoolEventFDIndex) {

//說明接收到AMS發送過來創建應用程序的請求,調用processOneCommand

//來創建新的應用程序進程

// Session socket accepted from the Zygote server socket

try {

//有socket連接,創建ZygoteConnection對象,並添加到fds。


ZygoteConnection connection = peers.get(pollIndex);

//處理連接,參考[4.2.6]

final Runnable command = connection.processOneCommand(this);

// TODO (chriswailes): Is this extra check necessary?

if (mIsForkChild) {

// We're in the child. We should always have a command to run at this

// stage if processOneCommand hasn't called "exec".

if (command == null) {

throw new IllegalStateException("command == null");

}

return command;

} else {

// We're in the server - we should never have any commands to run.

if (command != null) {

throw new IllegalStateException("command != null");

}

// We don't know whether the remote side of the socket was closed or

// not until we attempt to read from it from processOneCommand. This

// shows up as a regular POLLIN event in our regular processing loop.

if (connection.isClosedByPeer()) {

connection.closeSocket();

peers.remove(pollIndex);

socketFDs.remove(pollIndex); //處理完則從fds中移除該文件描述符

}


}

} catch (Exception e) {

......

} finally {

mIsForkChild = false;

}

} else {

//處理USAP pool的事件

// Either the USAP pool event FD or a USAP reporting pipe.

// If this is the event FD the payload will be the number of USAPs removed.

// If this is a reporting pipe FD the payload will be the PID of the USAP

// that was just specialized.

long messagePayload = -1;

try {

byte[] buffer = new byte[Zygote.USAP_MANAGEMENT_MESSAGE_BYTES];

int readBytes = Os.read(pollFDs[pollIndex].fd, buffer, 0, buffer.length);

if (readBytes == Zygote.USAP_MANAGEMENT_MESSAGE_BYTES) {

DataInputStream inputStream =

new DataInputStream(new ByteArrayInputStream(buffer));

messagePayload = inputStream.readLong();

} else {

Log.e(TAG, "Incomplete read from USAP management FD of size "

+ readBytes);

continue;

}


} catch (Exception ex) {

if (pollIndex == usapPoolEventFDIndex) {

Log.e(TAG, "Failed to read from USAP pool event FD: "

+ ex.getMessage());

} else {

Log.e(TAG, "Failed to read from USAP reporting pipe: "

+ exgetMessage());

}
continue;
}

if (pollIndex > usapPoolEventFDIndex) {
Zygote.removeUsapTableEntry((int) messagePayload);
}
usapPoolFDRead = true;
}
}

// Check to see if the USAP pool needs to be refilled.
if (usapPoolFDRead) {
int[] sessionSocketRawFDs =
socketFDs.subList(1, socketFDs.size())
.stream()
.mapToInt(fd -> fd.getInt$())
.toArray();
final Runnable command = fillUsapPool(sessionSocketRawFDs);
if (command != null) {
return command;
}
}
}
}/<zygoteconnection>/<zygoteconnection>/<filedescriptor>/<filedescriptor>

4.2.6 [ZygoteConnection.java] processOneCommand()

 Runnable processOneCommand(ZygoteServer zygoteServer) {
...
//fork子進程
pid = Zygote.forkAndSpecialize(parsedArgs.mUid, parsedArgs.mGid, parsedArgs.mGids,
parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mTargetSdkVersion);

if (pid == 0) {
// 子進程執行
zygoteServer.setForkChild();
//進入子進程流程,參考[4.2.7]
return handleChildProc(parsedArgs, descriptors, childPipeFd,
parsedArgs.mStartChildZygote);
} else {
//父進程執行
// In the parent. A pid < 0 indicates a failure and will be handled in handleParentProc.
handleParentProc(pid, descriptors, serverPipeFd);
return null;
}
...
}

4.2.7 [ZygoteConnection.java] handleChildProc()

 private Runnable handleChildProc(ZygoteArguments parsedArgs, FileDescriptor[] descriptors,
FileDescriptor pipeFd, boolean isZygote) {
...
if (parsedArgs.mInvokeWith != null) {
...
throw new IllegalStateException("WrapperInit.execApplication unexpectedly returned");
} else {
if (!isZygote) {
// App進程將會調用到這裡,執行目標類的main()方法
return ZygoteInit.zygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, null /* classLoader */);
} else {
return ZygoteInit.childZygoteInit(parsedArgs.mTargetSdkVersion,
parsedArgs.mRemainingArgs, null /* classLoader */);
}
}
}

這一節主要是講解Zygote的啟動流程,後面會詳細講解Zygote fork子進程的過程


分享到:


相關文章: