編輯:關於Android編程
Android5.0.1 的啟動流程與之前的版本相比變化並不大,OK,變化雖然還是有:SystemServer 啟動過程的 init1(), init2()沒有了,但主干流程依然不變:Linux 內核加載完畢之後,首先啟動 init 進程,然後解析 init.rc,並根據其內容由 init 進程裝載 Android 文件系統、創建系統目錄、初始化屬性系統、啟動一些守護進程,其中最重要的守護進程就是 Zygote 進程。Zygote 進程初始化時會創建 Dalvik 虛擬機、預裝載系統的資源和 Java 類。所有從 Zygote 進程 fork 出來的用戶進程都將繼承和共享這些預加載的資源。init 進程是 Android 的第一個進程,而 Zygote 進程則是所有用戶進程的根進程。SystemServer 是 Zygote 進程 fork 出的第一個進程,也是整個 Android 系統的核心進程。
在文件中 /system/core/rootdir/init.rc 中包含了 zygote.rc:
import /init.${ro.zygote}.rc
${ro.zygote}是平台相關的參數,實際可對應到 init.zygote32.rc, init.zygote64.rc, init.zygote64_32.rc, init.zygote32_64.rc,前兩個只會啟動單一app_process(64) 進程,而後兩個則會啟動兩個app_process進程:第二個app_process進程稱為 secondary,在後面的代碼中可以看到相應 secondary socket 的創建過程。為簡化起見,在這裡就不考慮這種創建兩個app_process進程的情形。
以 /system/core/rootdir/init.zygote32.rc 為例:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
onrestart write /sys/android_power/request_state wake
onrestart write /sys/power/state on
onrestart restart media
onrestart restart netd
第一行創建了名為 zygote 的進程,這個進程是通過 app_process 的 main 啟動並以”-Xzygote /system/bin –zygote –start-system-server”作為main的入口參數。
app_process 對應代碼為 framework/base/cmds/app_process/app_main.cpp。在這個文件的main函數中:
AppRuntime runtime(argv[0], computeArgBlockSize(argc, argv));
if (zygote) {
runtime.start("com.android.internal.os.ZygoteInit", args);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args);
}
根據入口參數,我們知道 zygote 為true,args參數中包含了”start-system-server”。
AppRuntime 繼承自 AndroidRuntime,因此下一步就執行到 AndroidRuntime 的 start 函數。
void AndroidRuntime::start(const char* className, const Vector& options)
{
/* start the virtual machine */ // 創建虛擬機
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) {
return;
}
onVmCreated(env);
...
//調用className對應類的靜態main()函數
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
env->CallStaticVoidMethod(startClass, startMeth, strArray);
...
}
start函數主要做兩件事:創建虛擬機和調用傳入類名對應類的 main 函數。因此下一步就執行到 com.android.internal.os.ZygoteInit 的 main 函數。
public static void main(String argv[]) {
try {
boolean startSystemServer = false;
String socketName = "zygote";
for (int i = 1; i < argv.length; i++) {
if ("start-system-server".equals(argv[i])) {
startSystemServer = true;
}
...
}
registerZygoteSocket(socketName);
...
preload();
...
if (startSystemServer) {
startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
它主要做了三件事情:
1. 調用 registerZygoteSocket 函數創建了一個 socket 接口,用來和 ActivityManagerService 通訊;
2. 調用 startSystemServer 函數來啟動 SystemServer;
3. 調用 runSelectLoop 函數進入一個無限循環在前面創建的 socket 接口上等待 ActivityManagerService 請求創建新的應用程序進程。
這裡要留意 catch (MethodAndArgsCaller caller) 這一行,android 在這裡通過拋出一個異常來處理正常的業務邏輯。
socket zygote stream 660 root system
系統啟動腳本文件 init.rc 是由 init 進程來解釋執行的,而 init 進程的源代碼位於 system/core/init 目錄中,在 init.c 文件中,是由 service_start 函數來解釋 init.zygote32.rc 文件中的 service 命令的:
void service_start(struct service *svc, const char *dynamic_args)
{
...
pid = fork();
if (pid == 0) {
struct socketinfo *si;
...
for (si = svc->sockets; si; si = si->next) {
int socket_type = (
!strcmp(si->type, "stream") ? SOCK_STREAM :
(!strcmp(si->type, "dgram") ? SOCK_DGRAM : SOCK_SEQPACKET));
int s = create_socket(si->name, socket_type,
si->perm, si->uid, si->gid, si->socketcon ?: scon);
if (s >= 0) {
publish_socket(si->name, s);
}
}
...
}
...
}
每一個 service 命令都會促使 init 進程調用 fork 函數來創建一個新的進程,在新的進程裡面,會分析裡面的 socket 選項,對於每一個 socket 選項,都會通過 create_socket 函數來在 /dev/socket 目錄下創建一個文件,在 zygote 進程中 socket 選項為“socket zygote stream 660 root system”,因此這個文件便是 zygote了,然後得到的文件描述符通過 publish_socket 函數寫入到環境變量中去:
static void publish_socket(const char *name, int fd)
{
char key[64] = ANDROID_SOCKET_ENV_PREFIX;
char val[64];
strlcpy(key + sizeof(ANDROID_SOCKET_ENV_PREFIX) - 1,
name,
sizeof(key) - sizeof(ANDROID_SOCKET_ENV_PREFIX));
snprintf(val, sizeof(val), "%d", fd);
add_environment(key, val);
/* make sure we don't close-on-exec */
fcntl(fd, F_SETFD, 0);
}
這裡傳進來的參數name值為”zygote”,而 ANDROID_SOCKET_ENV_PREFIX 在 system/core/include/cutils/sockets.h 定義為:
#define ANDROID_SOCKET_ENV_PREFIX "ANDROID_SOCKET_"
#define ANDROID_SOCKET_DIR "/dev/socket"
因此,這裡就把上面得到的文件描述符寫入到以 “ANDROID_SOCKET_zygote” 為 key 值的環境變量中。又因為上面的 ZygoteInit.registerZygoteSocket 函數與這裡創建 socket 文件的 create_socket 函數是運行在同一個進程中,因此,上面的 ZygoteInit.registerZygoteSocket 函數可以直接使用這個文件描述符來創建一個 Java層的LocalServerSocket 對象。如果其它進程也需要打開這個 /dev/socket/zygote 文件來和 zygote 進程進行通信,那就必須要通過文件名來連接這個 LocalServerSocket了。也就是說創建 zygote socket 之後,ActivityManagerService 就能夠通過該 socket 與 zygote 進程通信從而 fork 創建新進程,android 中的所有應用進程都是通過這種方式 fork zygote 進程創建的。在 ActivityManagerService中 的 startProcessLocked 中調用了Process.start()方法,進而調用 Process.startViaZygote 和 Process.openZygoteSocketIfNeeded。
socket 創建完成之後,緊接著就通過 startSystemServer 函數來啟動 SystemServer 進程。
private static boolean startSystemServer(String abiList, String socketName)
{
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_BLOCK_SUSPEND,
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_RESOURCE,
OsConstants.CAP_SYS_TIME,
OsConstants.CAP_SYS_TTY_CONFIG
);
/* 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,1032,3001,3002,3003,3006,3007",
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
parsedArgs = new ZygoteConnection.Arguments(args);
...
/* Request to fork the system server process */
pid = Zygote.forkSystemServer(
parsedArgs.uid, parsedArgs.gid,
parsedArgs.gids,
parsedArgs.debugFlags,
null,
parsedArgs.permittedCapabilities,
parsedArgs.effectiveCapabilities);
} catch (IllegalArgumentException ex) {
throw new RuntimeException(ex);
}
/* For child process */
if (pid == 0) {
if (hasSecondZygote(abiList)) {
waitForSecondaryZygote(socketName);
}
handleSystemServerProcess(parsedArgs);
}
return true;
}
這裡我們可以從參數推測出:創建名為“system_server”的進程,其入口是: com.android.server.SystemServer 的 main 函數。zygote 進程通過 Zygote.forkSystemServer 函數來創建一個新的進程來啟動 SystemServer 組件,返回值 pid 等 0 的地方就是新的進程要執行的路徑,即新創建的進程會執行 handleSystemServerProcess 函數。hasSecondZygote 是針對 init.zygote64_32.rc, init.zygote32_64.rc 這兩者情況的,在這裡跳過不談。接下來來看 handleSystemServerProcess:
/**
* Finish remaining work for the newly forked system server process.
*/
private static void handleSystemServerProcess(
ZygoteConnection.Arguments parsedArgs)
throws ZygoteInit.MethodAndArgsCaller
{
closeServerSocket();
// set umask to 0077 so new files and directories will default to owner-only permissions.
Os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
ClassLoader cl = null;
if (systemServerClasspath != null) {
cl = new PathClassLoader(systemServerClasspath, ClassLoader.getSystemClassLoader());
Thread.currentThread().setContextClassLoader(cl);
}
/*
* Pass the remaining arguments to SystemServer.
*/
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
/* should never reach here */
}
handleSystemServerProcess 會拋出 MethodAndArgsCaller 異常,前面提到這個異常其實是處理正常業務邏輯的,相當於一個回調。由於由 zygote 進程創建的子進程會繼承 zygote 進程在前面創建的 socket 文件描述符,而這裡的子進程又不會用到它,因此,這裡就調用 closeServerSocket 函數來關閉它。SYSTEMSERVERCLASSPATH 是包含 /system/framework/framework.jar 的環境變量,它定義在 system/core/rootdir/init.environ.rc.in 中:
on init
export PATH /sbin:/vendor/bin:/system/sbin:/system/bin:/system/xbin
export ANDROID_BOOTLOGO 1
export ANDROID_ROOT /system
export SYSTEMSERVERCLASSPATH %SYSTEMSERVERCLASSPATH%
export LD_PRELOAD libsigchain.so
handleSystemServerProcess 函數接著調用 RuntimeInit.zygoteInit 函數來進一步執行啟動 SystemServer 組件的操作。
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller {
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
commonInit 設置線程未處理異常handler,時區等,JNI 方法 nativeZygoteInit 實現在 frameworks/base/core/jni/AndroidRuntime.cpp 中:
static AndroidRuntime* gCurRuntime = NULL;
static void com_android_internal_os_RuntimeInit_nativeZygoteInit(JNIEnv* env, jobject clazz)
{
gCurRuntime->onZygoteInit();
}
AndroidRuntime 是個帶虛函數的基類,真正的實現是在 app_main.cpp 中的 AppRuntime:
class AppRuntime : public AndroidRuntime
{
virtual void onStarted()
{
sp proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
AndroidRuntime* ar = AndroidRuntime::getRuntime();
ar->callMain(mClassName, mClass, mArgs);
IPCThreadState::self()->stopProcess();
}
virtual void onZygoteInit()
{
// Re-enable tracing now that we're no longer in Zygote.
atrace_set_tracing_enabled(true);
sp proc = ProcessState::self();
ALOGV("App process: starting thread pool.\n");
proc->startThreadPool();
}
virtual void onExit(int code)
{
if (mClassName.isEmpty()) {
// if zygote
IPCThreadState::self()->stopProcess();
}
AndroidRuntime::onExit(code);
}
};
通過執行 AppRuntime::onZygoteInit 函數,這個進程的 Binder 進程間通信機制基礎設施就准備好了,參考代碼 frameworks/native/libs/binder/ProcessState.cpp。
接下來,看 applicationInit :
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());
// let the process exit
return;
}
// Remaining arguments are passed to the start class's static main
invokeStaticMain(args.startClass, args.startArgs, classLoader);
}
applicationInit 僅僅是轉調 invokeStaticMain:
private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
throws ZygoteInit.MethodAndArgsCaller
{
Class cl;
cl = Class.forName(className, true, classLoader);
Method m;
m = cl.getMethod("main", new Class[] { String[].class });
/*
* 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);
}
invokeStaticMain 也很簡單,通過反射找到參數 className 對應的類的靜態 main 方法,然後將該方法與參數生成 ZygoteInit.MethodAndArgsCaller 對象當做異常拋出,這個異常對象在 ZygoteInit 的 main 函數被捕獲並執行該對象的 run 方法。
/**
* Helper exception class which holds a method and arguments and
* can call them. This is used as part of a trampoline to get rid of
* the initial process setup stack frames.
*/
public static class MethodAndArgsCaller extends Exception
implements Runnable {
public void run() {
...
mMethod.invoke(null, new Object[] { mArgs });
...
}
}
這麼復雜的跳轉,其實就做了一件簡單的事情:根據 className 反射調用該類的靜態 main 方法。這個類名是 ZygoteInit.startSystemServer 方法中寫死的 com.android.server.SystemServer。 從而進入 SystemServer 類的 main()方法。
在 startSystemServer 函數中,創建 system_server 進程之後,pid 等於 0 時在該新進程中執行 SystemServer.main,否則回到 zygote 進程進行執行 ZygoteInit.runSelectLoop:
private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList fds = new ArrayList();
ArrayList peers = new ArrayList();
FileDescriptor[] fdArray = new FileDescriptor[4];
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
/*
* Call gc() before we block in select().
* It's work that has to be done anyway, and it's better
* to avoid making every child do it. It will also
* madvise() any free memory as a side-effect.
*
* Don't call it every time, because walking the entire
* heap is a lot of overhead to free a few hundred bytes.
*/
if (loopCount <= 0) {
gc();
loopCount = GC_LOOP_COUNT;
} else {
loopCount--;
}
try {
fdArray = fds.toArray(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) {
ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDescriptor());
} else {
boolean done;
done = peers.get(index).runOnce();
if (done) {
peers.remove(index);
fds.remove(index);
}
}
}
}
runSelectLoop函數的邏輯比較簡單,主要有兩點:
1、 處理客戶端的連接和請求。前面創建的 LocalServerSocket 對象保存 sServerSocket,這個 socket 通過 selectReadable 等待 ActivityManagerService(簡寫 AMS) 與之通信。selectReadable 是一個native函數,內部調用select等待 AMS 連接,AMS 連接上之後就會返回: 返回值 < 0:內部發生錯誤;返回值 = 0:第一次連接到服務端 ;返回值 > 0:與服務端已經建立連接,並開始發送數據。每一個鏈接在 zygote 進程中使用 ZygoteConnection 對象表示。
2、 客戶端的請求由 ZygoteConnection.runOnce 來處理,這個方法也拋出 MethodAndArgsCaller 異常,從而進入 MethodAndArgsCaller.run 中調用根據客戶請求數據反射出的類的 main 方法。
private String[] readArgumentList()
{
int argc;
try {
String s = mSocketReader.readLine();
if (s == null) {
// EOF reached.
return null;
}
argc = Integer.parseInt(s);
} catch (NumberFormatException ex) {
Log.e(TAG, "invalid Zygote wire format: non-int at argc");
throw new IOException("invalid wire format");
}
String[] result = new String[argc];
for (int i = 0; i < argc; i++) {
result[i] = mSocketReader.readLine();
if (result[i] == null) {
// We got an unexpected EOF.
throw new IOException("truncated request");
}
}
return result;
}
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
args = readArgumentList();
parsedArgs = new Arguments(args);
...
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
...
}
在前面啟動 SystemServer一節講到,通過反射調用類 com.android.server.SystemServer main() 函數,從而開始執行 SystemServer 的初始化流程。
SystemServer.main()
/**
* The main entry point from zygote.
*/
public static void main(String[] args) {
new SystemServer().run();
}
main 函數創建一個 SystemServer 對象,調用其 run() 方法。
private void run() {
// If a device's clock is before 1970 (before 0), a lot of
// APIs crash dealing with negative numbers, notably
// java.io.File#setLastModified, so instead we fake it and
// hope that time from cell towers or NTP fixes it shortly.
if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
Slog.w(TAG, "System clock is before 1970; setting to 1970.");
SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
} // 檢測時間設置
// Here we go!
Slog.i(TAG, "Entered the Android system server!");
EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, SystemClock.uptimeMillis());
// In case the runtime switched since last boot (such as when
// the old runtime was removed in an OTA), set the system
// property so that it is in sync. We can't do this in
// libnativehelper's JniInvocation::Init code where we already
// had to fallback to a different runtime because it is
// running as root and we need to be the system user to set
// the property. http://b/11463182
SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
// Enable the sampling profiler.
if (SamplingProfilerIntegration.isEnabled()) {
SamplingProfilerIntegration.start();
mProfilerSnapshotTimer = new Timer();
mProfilerSnapshotTimer.schedule(new TimerTask() {
@Override
public void run() {
SamplingProfilerIntegration.writeSnapshot("system_server", null);
}
}, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
} // 啟動性能分析采樣
// Mmmmmm... more memory!
VMRuntime.getRuntime().clearGrowthLimit();
// The system server has to run all of the time, so it needs to be
// as efficient as possible with its memory usage.
VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);
// Some devices rely on runtime fingerprint generation, so make sure
// we've defined it before booting further.
Build.ensureFingerprintProperty();
// Within the system server, it is an error to access Environment paths without
// explicitly specifying a user.
Environment.setUserRequired(true);
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
// Prepare the main looper thread (this thread).
android.os.Process.setThreadPriority(
android.os.Process.THREAD_PRIORITY_FOREGROUND);
android.os.Process.setCanSelfBackground(false);
Looper.prepareMainLooper(); // 准備主線程循環
// Initialize native services.
System.loadLibrary("android_servers");
nativeInit();
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
// Initialize the system context.
createSystemContext();
// Create the system service manager.
mSystemServiceManager = new SystemServiceManager(mSystemContext);
LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
// Start services. // 啟動服務
try {
startBootstrapServices();
startCoreServices();
startOtherServices();
} catch (Throwable ex) {
Slog.e("System", "******************************************");
Slog.e("System", "************ Failure starting system services", ex);
throw ex;
}
// For debug builds, log event loop stalls to dropbox for analysis.
if (StrictMode.conditionallyEnableDebugLogging()) {
Slog.i(TAG, "Enabled StrictMode for system server main thread.");
}
// Loop forever.
Looper.loop(); // 啟動線程循環,等待消息處理
throw new RuntimeException("Main thread loop unexpectedly exited");
}
在這個 run 方法中,主要完成三件事情,創建 system context 和 system service manager,啟動一些系統服務,進入主線程消息循環。
接下來我們仔細分析 Zygote.forkSystemServer 與 Zygote.forkAndSpecialize 兩個方法。
private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
VM_HOOKS.preFork();
int pid = nativeForkSystemServer(
uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
VM_HOOKS.postForkCommon();
return pid;
}
在調用 nativeForkSystemServer 創建 system_server 進程之前與之後,都會調用 ZygoteHooks 進行一些前置與後置處理。
前置處理 ZygoteHooks.preFork:
public void preFork() {
Daemons.stop();
waitUntilAllThreadsStopped();
token = nativePreFork();
}
Daemons.stop(); 停止虛擬機中一些守護線程操作:如引用隊列、終接器、GC等
public static void stop() {
ReferenceQueueDaemon.INSTANCE.stop();
FinalizerDaemon.INSTANCE.stop();
FinalizerWatchdogDaemon.INSTANCE.stop();
HeapTrimmerDaemon.INSTANCE.stop();
GCDaemon.INSTANCE.stop();
}
waitUntilAllThreadsStopped 保證被 fork 的進程是單線程,這樣可以確保通過 copyonwrite fork 出來的進程也是單線程,從而節省資源。與前面提到的在新建 system_server 進程中調用 closeServerSocket 關閉 sockect 有異曲同工之妙。
/**
* We must not fork until we're single-threaded again. Wait until /proc shows we're
* down to just one thread.
*/
private static void waitUntilAllThreadsStopped() {
File tasks = new File("/proc/self/task");
while (tasks.list().length > 1) {
try {
// Experimentally, booting and playing about with a stingray, I never saw us
// go round this loop more than once with a 10ms sleep.
Thread.sleep(10);
} catch (InterruptedException ignored) {
}
}
}
本地方法 nativePreFork 實現在 art/runtime/native/dalvik_system_ZygoteHooks.cc 中。
static jlong ZygoteHooks_nativePreFork(JNIEnv* env, jclass) {
Runtime* runtime = Runtime::Current();
CHECK(runtime->IsZygote()) << "runtime instance not started with -Xzygote";
runtime->PreZygoteFork();
// Grab thread before fork potentially makes Thread::pthread_key_self_ unusable.
Thread* self = Thread::Current();
return reinterpret_cast(self);
}
ZygoteHooks_nativePreFork 通過調用 Runtime::PreZygoteFork 來完成 gc 堆的一些初始化,這部分代碼在 art/runtime/runtime.cc 中:
heap_ = new gc::Heap(...);
void Runtime::PreZygoteFork() {
heap_->PreZygoteFork();
}
nativeForkSystemServer 實現在 framework/base/core/jni/com_android_internal_os_Zygote.cpp 中:
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint debug_flags, jobjectArray rlimits, jlong permittedCapabilities,
jlong effectiveCapabilities) {
pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
debug_flags, rlimits,
permittedCapabilities, effectiveCapabilities,
MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL,
NULL, NULL);
if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
gSystemServerPid = pid;
// There is a slight window that the system server process has crashed
// but it went unnoticed because we haven't published its pid yet. So
// we recheck here just to make sure that all is well.
int status;
if (waitpid(pid, &status, WNOHANG) == pid) {
ALOGE("System server process %d has died. Restarting Zygote!", pid);
RuntimeAbort(env);
}
}
return pid;
}
它轉調 ForkAndSpecializeCommon 來創建新進程,並確保 system_server 創建成功,若不成功便成仁:重啟 zygote,因為沒有 system_server 就干不了什麼事情。ForkAndSpecializeCommon 實現如下:
static const char kZygoteClassName[] = "com/android/internal/os/Zygote";
gZygoteClass = (jclass) env->NewGlobalRef(env->FindClass(kZygoteClassName));
gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks",
"(ILjava/lang/String;)V");
// Utility routine to fork zygote and specialize the child process.
static pid_t ForkAndSpecializeCommon(JNIEnv* env, uid_t uid, gid_t gid, jintArray javaGids,
jint debug_flags, jobjectArray javaRlimits,
jlong permittedCapabilities, jlong effectiveCapabilities,
jint mount_external,
jstring java_se_info, jstring java_se_name,
bool is_system_server, jintArray fdsToClose,
jstring instructionSet, jstring dataDir)
{
SetSigChldHandler();
pid_t pid = fork();
if (pid == 0) {
// The child process.
...
rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
...
UnsetSigChldHandler();
...
env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
is_system_server ? NULL : instructionSet);
}
else if (pid > 0) {
// the parent process
}
return pid;
}
ForkAndSpecializeCommon 首先設置子進程異常處理handler,然後 fork 新進程,在新進程中設置 SELinux,並清除它的子進程異常處理 handler,然後調用 Zygote.callPostForkChildHooks 方法。
private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
long startTime = SystemClock.elapsedRealtime();
VM_HOOKS.postForkChild(debugFlags, instructionSet);
checkTime(startTime, "Zygote.callPostForkChildHooks");
}
callPostForkChildHooks 又轉調 ZygoteHooks.postForkChild :
public void postForkChild(int debugFlags, String instructionSet) {
nativePostForkChild(token, debugFlags, instructionSet);
}
本地方法 nativePostForkChild 又進到 dalvik_system_ZygoteHooks.cc 中:
static void ZygoteHooks_nativePostForkChild(JNIEnv* env, jclass, jlong token, jint debug_flags,
jstring instruction_set) {
Thread* thread = reinterpret_cast(token);
// Our system thread ID, etc, has changed so reset Thread state.
thread->InitAfterFork();
EnableDebugFeatures(debug_flags);
if (instruction_set != nullptr) {
ScopedUtfChars isa_string(env, instruction_set);
InstructionSet isa = GetInstructionSetFromString(isa_string.c_str());
Runtime::NativeBridgeAction action = Runtime::NativeBridgeAction::kUnload;
if (isa != kNone && isa != kRuntimeISA) {
action = Runtime::NativeBridgeAction::kInitialize;
}
Runtime::Current()->DidForkFromZygote(env, action, isa_string.c_str());
} else {
Runtime::Current()->DidForkFromZygote(env, Runtime::NativeBridgeAction::kUnload, nullptr);
}
}
thread->InitAfterFork(); 實現在 art/runtime/thread.cc 中,設置新進程主線程的線程id: tid。DidForkFromZygote 實現在 Runtime.cc 中:
void Runtime::DidForkFromZygote(JNIEnv* env, NativeBridgeAction action, const char* isa) {
is_zygote_ = false;
switch (action) {
case NativeBridgeAction::kUnload:
UnloadNativeBridge();
break;
case NativeBridgeAction::kInitialize:
InitializeNativeBridge(env, isa);
break;
}
// Create the thread pool.
heap_->CreateThreadPool();
StartSignalCatcher();
// Start the JDWP thread. If the command-line debugger flags specified "suspend=y",
// this will pause the runtime, so we probably want this to come last.
Dbg::StartJdwp();
}
首先根據 action 參數來卸載或轉載用於跨平台橋接用的庫。然後啟動 gc 堆的線程池。StartSignalCatcher 設置信號 處理 handler,其代碼在 signal_catcher.cc 中。
後置處理 ZygoteHooks.postForkCommon:
public void postForkCommon() {
Daemons.start();
}
postForkCommon 轉調 Daemons.start,以初始化虛擬機中引用隊列、終接器以及 gc 的守護線程。
public static void start() {
ReferenceQueueDaemon.INSTANCE.start();
FinalizerDaemon.INSTANCE.start();
FinalizerWatchdogDaemon.INSTANCE.start();
HeapTrimmerDaemon.INSTANCE.start();
GCDaemon.INSTANCE.start();
}
Zygote.forkAndSpecialize 方法
public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
String instructionSet, String appDataDir) {
long startTime = SystemClock.elapsedRealtime();
VM_HOOKS.preFork();
checkTime(startTime, "Zygote.preFork");
int pid = nativeForkAndSpecialize(
uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
instructionSet, appDataDir);
checkTime(startTime, "Zygote.nativeForkAndSpecialize");
VM_HOOKS.postForkCommon();
checkTime(startTime, "Zygote.postForkCommon");
return pid;
}
前置處理與後置處理與 forkSystemServer 中一樣的,這裡就跳過不講了。本地方法 nativeForkAndSpecialize 實現在 framework/base/core/jni/com_android_internal_os_Zygote.cpp 中:
static jint com_android_internal_os_Zygote_nativeForkAndSpecialize(
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint debug_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose, jstring instructionSet, jstring appDataDir) {
// Grant CAP_WAKE_ALARM to the Bluetooth process.
jlong capabilities = 0;
if (uid == AID_BLUETOOTH) {
capabilities |= (1LL << CAP_WAKE_ALARM);
}
return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
rlimits, capabilities, capabilities, mount_external, se_info,
se_name, false, fdsToClose, instructionSet, appDataDir);
}
這個函數與 com_android_internal_os_Zygote_nativeForkSystemServer 非常類似,只不過少了一個確保子進程創建成功的步驟。
項目介紹 因為要參加某信息安全比賽,選擇了安卓apk的行為分析與評估的課題,所以首先需要了解安卓程序是怎樣編寫和運行的。我們的第一個任務就是寫出一個多人通信的app。
前言在Android開發中,經常要獲取sha1證書指紋。例如:在嵌入高德地圖的時候,就需要使用這個東東。這個東西在Eclipse中可以直接獲取到,但是在Android S
Android Handler的使用,在講Handler之前,我們先提個小問題,就是如何讓程序5秒鐘更新一下Title.首先我們看一下習慣了Java編程的人,在不知道Ha
為了練練手,增長逆向分析的知識,本次博客打算分析一下某酒店APP的登陸請求。這次的逆向分析還是以網絡請求為例,通過分析其登陸請求數據的加解密原理,將請求數據從密文轉換成明