編輯:關於Android編程
Zygote, 意為“受精卵”,Android系統中幾乎所有的應用進程都是由Zygote進程孵化出來的,Java環境也是由Zygote創建起來的,它建立了我們app運行所需要的環境,是app的祖先,因此,分析它的啟動以及內部邏輯顯得非常有必要。
Android系統是基於Linux內核的,而在Linux系統中,所有的進程都是init進程的子孫進程,也就是說,所有的進程都是直接或者間接地由init進程fork出來的。Zygote進程也不例外,它是在系統啟動的過程,由init進程創建的。在系統啟動腳本system/core/rootdir/init.rc文件中,我們可以看到啟動Zygote進程的腳本命令:
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server socket zygote stream 666 # zygote需要一個套接字 onrestart write /sys/android_power/request_state wake # zygote重啟的話,需要執行這個操作 onrestart write /sys/power/state on onrestart restart media onrestart restart netd
上述腳本表示要啟動一個進程,名稱為zygote, 可執行文件為/system/bin/app_process,
--Xzygote /system/bin --zygote --start-system-server
這些是傳給zygote的參數,其余部分的作用見注釋。
app_process對應的源碼在frameworks/base/cmds/app_process目錄下,其入口函數main在文件app_main.cpp中,接下來我們就從這個main函數入手來分析zygote的內部邏輯。
注意: 本文的源碼分析基於Android 4.4。
/*
* 啟動zygote的方式為/system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
* 所以 argc == 5
* argv裡頭存的就是這5個參數argv[0]=="/system/bin/app_process" ,argv[1] == "-Xzygote"....
*/
int main(int argc, char* const argv[])
{
......
// These are global variables in ProcessState.cpp
mArgC = argc;
mArgV = argv;
mArgLen = 0;
for (int i=0; i
main函數主要就是創建了runtime實例,並且解析參數,然後調用runtime的start函數,接著我們分析AppRuntime的start函數:
/*
* Start the Android runtime. This involves starting the virtual machine
* and calling the "static void main(String[] args)" method in the class
* named by "className".
*
* Passes the main function two arguments, the class name and the specified
* options string.
*/
// 首先我們明確下傳進來的參數 className == "com.android.internal.os.ZygoteInit" options == "start-system-server"
void AndroidRuntime::start(const char* className, const char* options)
{
ALOGD("\n>>>>>> AndroidRuntime START %s <<<<<<\n",
className != NULL ? className : "(unknown)");
/*
* 'startSystemServer == true' means runtime is obsolete and not run from
* init.rc anymore, so we print out the boot start event here.
*/
if (strcmp(options, "start-system-server") == 0) {
/* track our progress through the boot sequence */
const int LOG_BOOT_PROGRESS_START = 3000;
LOG_EVENT_LONG(LOG_BOOT_PROGRESS_START,
ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
}
const char* rootDir = getenv("ANDROID_ROOT");
if (rootDir == NULL) {
rootDir = "/system";
if (!hasDir("/system")) {
LOG_FATAL("No root directory specified, and /android does not exist.");
return;
}
setenv("ANDROID_ROOT", rootDir, 1); //配置ANDROID_ROOT環境變量
}
//const char* kernelHack = getenv("LD_ASSUME_KERNEL");
//ALOGD("Found LD_ASSUME_KERNEL='%s'\n", kernelHack);
/* start the virtual machine */
JniInvocation jni_invocation;
jni_invocation.Init(NULL);
JNIEnv* env;
if (startVm(&mJavaVM, &env) != 0) { // 創建虛擬機
return;
}
onVmCreated(env);
/*
* Register android functions.
*/
if (startReg(env) < 0) {
ALOGE("Unable to register all android natives\n");
return;
}
/*
* We want to call main() with a String array with arguments in it.
* At present we have two arguments, the class name and an option string.
* Create an array to hold them.
*/
jclass stringClass;
jobjectArray strArray;
jstring classNameStr;
jstring optionsStr;
stringClass = env->FindClass("java/lang/String");
assert(stringClass != NULL);
strArray = env->NewObjectArray(2, stringClass, NULL);
assert(strArray != NULL);
classNameStr = env->NewStringUTF(className);
assert(classNameStr != NULL);
env->SetObjectArrayElement(strArray, 0, classNameStr);
optionsStr = env->NewStringUTF(options);
env->SetObjectArrayElement(strArray, 1, optionsStr);
/*
* Start VM. This thread becomes the main thread of the VM, and will
* not return until the VM exits.
*/
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
if (startClass == NULL) {
ALOGE("JavaVM unable to locate class '%s'\n", slashClassName);
/* keep going */
} else {
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
if (startMeth == NULL) {
ALOGE("JavaVM unable to find main() in '%s'\n", className);
/* keep going */
} else {
/* 調用com.android.internal.os.ZygoteInit的main函數,strArray是參數,數組裡面有兩個元素,
className == "com.android.internal.os.ZygoteInit" options == "start-system-server" */
env->CallStaticVoidMethod(startClass, startMeth, strArray);
#if 0
if (env->ExceptionCheck())
threadExitUncaughtException(env);
#endif
}
}
free(slashClassName);
ALOGD("Shutting down VM\n");
if (mJavaVM->DetachCurrentThread() != JNI_OK)
ALOGW("Warning: unable to detach main thread\n");
if (mJavaVM->DestroyJavaVM() != 0)
ALOGW("Warning: VM did not shut down cleanly\n");
}
start函數主要做了以下幾件事情:
調用startVm函數創建虛擬機;
調用startReg函數注冊Android Natvie函數;
讓虛擬機去執行com.android.internal.os.ZygoteInit的main函數。
接下來我們分析下com.android.internal.os.ZygoteInit的main函數, 創建虛擬機以及注冊native函數的過程後續再分析。
public static void main(String argv[]) {
try {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
registerZygoteSocket(); // 1、創建一個套接字,用於監聽ams發過來的fork請求
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload(); // 2、加載classes 和resources, 後面會詳細分析
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
SystemClock.uptimeMillis());
// Finish profiling the zygote initialization.
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
gc();
// If requested, start system server directly from Zygote
if (argv.length != 2) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
if (argv[1].equals("start-system-server")) {
startSystemServer(); //3、 創建system server進程,ams wms pms等常見service都在該進程裡面
} else if (!argv[1].equals("")) {
throw new RuntimeException(argv[0] + USAGE_STRING);
}
Log.i(TAG, "Accepting command socket connections");
if (ZYGOTE_FORK_MODE) {
runForkMode();
} else {
runSelectLoopMode(); // 4、進入循環監聽模式,監聽外來請求
}
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
caller.run();
} catch (RuntimeException ex) {
Log.e(TAG, "Zygote died with exception", ex);
closeServerSocket();
throw ex;
}
}
com.android.internal.os.ZygoteInit的main函數主要做了四件事情:
調用registerZygoteSocket()創建一個套接字,用於監聽ams發過來的fork請求;
調用preload()預加載classes 和resources;
調用startSystemServer()創建system server進程,ams wms pms等常見service都在該進程裡面;
調用runSelectLoopMode()進入循環監聽模式,監聽外來請求。
今天拿到一個客戶新的訂單需求,大概有40多個需求,今天先講更改系統的藍牙/wifi 熱點/消息通知/sleep 添加 never選項,分別是:藍牙:系統界面顯示名字,重命
接著AppWidget基礎學習,今天是一個“進階版”的小例子,用來檢驗一下自己的學習效果。於是就做了一個擲骰子的Widget。方便大家觀看,先截圖如下: &nb
現在我目前知道可以獲取SharedPreferences實例的常用方法有三個: 1.通過Context的getSharedPreferences(String name,
最近幾個項目的測試結果,Android無法主動通過調用 webview.loadUrl(javascript:+callbackFunction+(+data+)); 這