編輯:關於Android編程
zygote本身是一個Linux的Native應用程序,當init進程啟動完畢之後,通過init.rc文件啟動zygote並修改進程名字為zygote(frameworks/base/cmds/app_process/app_main.cpp文件)。它是一個deamon進程,啟動VM,加載class和resource等。之後唯一的任務就是監聽socket(/dev/socket/zygote這個是用來監聽的socket)並啟動application,所有APP的父進程皆為zygote進程。
zygote從”/dev/socket/zygote”監聽到APP啟動的請求之後,最終會fork()一個子進程。我們知道fork()會完全復制父進程(clone)到另外的一個用戶空間。當zygote進行fork之後,還需要創建新的Dalvik VM,還需要preload那些APP需要的class和resource。看起來像是zygote每次啟動一個APP的時候都要重新復制整塊的內存並重新加載class和resouce,但其實不然,這是因為Linux內核實現的Copy-On-Write(COW)。有Copy-On-Write,意味著在fork復制內存操作中,沒有內存是會被馬上拷貝的。而是在進程在改寫這段內存的時候,kernel會中斷這種寫操作並先做之前沒有做的復制操作。在zygote進行preload的class和resource都是只讀的文件,所以在啟動APP和運行APP的過程中,沒有class和resource是會被復制到另外的內存的,而是所有的APP都在用同一份class和resource,也就是zygote啟動的時候加載的那些。
1.設置init.xx.rc啟動運行相關service
//system/core/rootdir/init.zygotexx.rc //xx是64或者32,看平台
service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-system-server
class main
socket zygote stream 660 root system
//設置zygote相關的socket名字,權限等。會生成/dev/socket/zygote節點,權限如下:
//srw-rw---- root system 2012-01-28 13:39 zygote
onrestart write /sys/android_power/request_state wake //??
onrestart write /sys/power/state on //??
onrestart restart media
onrestart restart netd
onrestart restart loc_launcher
2.init進程讀到上面的service之後,會跑到/frameworks/base/cmds/app_process/app_main.cpp文件的main函數,並傳入參數。main函數主要做以下幾件事情
1)修改當前進程名字為zygote
if (!niceName.isEmpty()) {
runtime.setArgv0(niceName.string());
set_process_name(niceName.string());
}
//通過這個最終用prctl()系統調用修改當前進程的名字為zygo
2)調用AppRuntime.start函數!! 下面會繼續分析AppRuntime.start函數
AppRuntime.start函數做如下一些事情
1) startVm()初始化DVM
2) startReg()注冊JNI函數
3)
char* slashClassName = toSlashClassName(className);
jclass startClass = env->FindClass(slashClassName);
jmethodID startMeth = env->GetStaticMethodID(startClass, "main",
"([Ljava/lang/String;)V");
env->CallStaticVoidMethod(startClass, startMeth, strArray)
//加載"com.android.internal.os.ZygoteInit"類並調用其main函數。
//第一個java函數調用開始了~~
ZygoteInit.main函數主要做以下幾件事情
1.調用registerZygoteSocket函數創建了一個socket接口,用來和ActivityManagerService通訊
boolean startSystemServer = false; String socketName = "zygote"; registerZygoteSocket(socketName);
registerZygoteSocket()函數如下:
private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
sServerSocket = new LocalServerSocket(
createFileDescriptor(fileDesc));
} catch (IOException ex) {
throw new RuntimeException(
"Error binding to local socket '" + fileDesc + "'", ex);
}
}
}
可以看到registerZygoteSocket()函數通過叫fullSocketName的環境變量得到env並轉換為文件描述符。
這個環境變量的名字可以從上面的函數中知道是”ANDROID_SOCKET_zygote”。這個環境變量是在哪裡設置的呢?
我們知道,系統啟動腳本文件system/core/rootdir/init.rc是由init進程來解釋執行的,而init進程的源代碼位於system/core/init目錄中,在init.c文件中,是由service_start函數來解釋init.rc文件中的service命令的。每一個service命令都會促使init進程調用fork函數來創建一個新的進程,在新的進程裡面,會分析裡面的socket選項,對於每一個socket選項,都會通過create_socket函數來在/dev/socket目錄下創建一個文件,在這個場景中,這個文件便是zygote了,然後得到的文件描述符通過publish_socket函數寫入到環境變量中去。publish_socke()函數中可以看到是如何設置環境變量的。
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);
}
因此,這裡就把上面得到的文件描述符寫入到以”ANDROID_SOCKET_zygote”為key值的環境變量中。又因為上面的ZygoteInit.registerZygoteSocket函數與這裡創建socket文件的create_socket函數是運行在同一個進程中,因此,上面的ZygoteInit.registerZygoteSocket函數可以直接使用這個文件描述符來創建一個Java層的LocalServerSocket對象。如果其它進程也需要打開這個/dev/socket/zygote文件來和Zygote進程進行通信,那就必須要通過文件名來連接這個LocalServerSocket了
2.預加載
static void preload() {
Log.d(TAG, "begin preload");
preloadClasses();
preloadResources();
preloadOpenGL();
preloadSharedLibraries();
// Ask the WebViewFactory to do any initialization that must run in the zygote process,
// for memory sharing purposes.
WebViewFactory.prepareWebViewInZygote();
Log.d(TAG, "end preload");
}
3.調用startSystemServer函數來啟動SystemServer組件
private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
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[] = {//SystemServer進程的uid,gid等等,,很多參數設置,需要仔細看看
"--setuid=1000",
"--setgid=1000",
//WTL_EDM_START
// "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
//Adds system to net_raw and net_admin (3004, 3005)
//groups, so that system can use iptables.
"-- setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1021,1032,3001,3002,3003,3004,3005,3006,3007",
//WTL_EDM_END
"--capabilities=" + capabilities + "," + capabilities,
"--runtime-init",
"--nice-name=system_server",
"com.android.server.SystemServer",
};
ZygoteConnection.Arguments parsedArgs = null;
int pid;
try {
//按照上面的參數賦值給parsedArgs
parsedArgs = new ZygoteConnection.Arguments(args);
ZygoteConnection.applyDebuggerSystemProperty(parsedArgs);
ZygoteConnection.applyInvokeWithSystemProperty(parsedArgs);
//fork出來一個SystemServer進程
/* 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);
}
//SystemServer進程跑到這裡,開始跑handleSystemServerProcess()。
handleSystemServerProcess(parsedArgs);
}
return true;
}
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");
if (systemServerClasspath != null) {
performSystemServerDexOpt(systemServerClasspath);
}
if (parsedArgs.invokeWith != null) {
String[] args = parsedArgs.remainingArgs;
// If we have a non-null system server class path, we'll have to duplicate the
// existing arguments and append the classpath to it. ART will handle the classpath
// correctly when we exec a new process.
if (systemServerClasspath != null) {
String[] amendedArgs = new String[args.length + 2];
amendedArgs[0] = "-cp";
amendedArgs[1] = systemServerClasspath;
System.arraycopy(parsedArgs.remainingArgs, 0, amendedArgs, 2, parsedArgs.remainingArgs.length);
}
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
null, args);
} else {
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 */
}
這裡重點是RuntimeInit.zygoteInit()函數
public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader
classLoader) throws ZygoteInit.MethodAndArgsCaller {
if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");
redirectLogStreams();
commonInit();
nativeZygoteInit();
applicationInit(targetSdkVersion, argv, classLoader);
}
這個函數都是做一些初始化工作,其中nativeZygoteInit最終會調用到app_main.cpp中的onZygoteInit。
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();
}
applicationInit函數中的invokeStaticMain(args.startClass, args.startArgs, classLoader)最終會調用SystemServer.java中的main函數。ZygoteInit.java的startSystemServer()函數中,args參數的最後一個就是 “com.android.server.SystemServer”,所以最後調用的就是這個庫的main函數。
/**
* The main entry point from zygote.
* */
public static void main(String[] args) {
new SystemServer().run();
}
這裡看到SystemServer啟動,但具體內容很多,需要後面再進行分析。
4.調用runSelectLoopMode函數進入一個無限循環在前面創建的socket接口上等待ActivityManagerService請求創建新的應用程序進程。
runSelectLoop()->ZygoteConnection.runOnce()函數負責接收command並啟動APP /*runSelectLoop()函數中,GC_LOOP_COUNT表示跑起來幾個APP之後調用一次gc()清理內存。 如果內存較小,可以適當調整這個值?*/
從這裡可以再進一步看看ActivityManagerService是怎麼組織參數發給zygote來啟動一個參數的。
這裡也涉及到安全等,需要仔細檢查一下。
//安全相關的
applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
//需要設置的uid,gid等,,
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal,
parsedArgs.seInfo,parsedArgs.category, parsedArgs.accessInfo,
parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
parsedArgs.appDataDir);
至此,zygote進程的啟動分析就結束了,它會一直循環在這裡,等待其他進程請求它孵化出新的進程。
Android SwitchButton(滑動開關)
版本:1.0日期:2014.5.17 2014.6.1版權:© 2014 kince 轉載注明出處 在介紹SwitchButton之前,先來看一下系統Butt
第一章,listview的簡易用法(Android)
這篇文章主要是練習了安卓listview的arrayadapter和baseadapter的簡單填充。1.arrayadapter填充布局: 代碼: pa
Android API Guides---Text and Input
文本和輸入 使用文字服務添加便利功能,例如復制/粘貼和拼寫檢查到您的應用程序。您也可以開發自己的文字服務,提供自定義的輸入法,字典和拼寫檢查,你可以分發給用戶為應用程序。
ios版android電視遙控器怎麼用
最新消息,距離Nexus Player、SHIELD TV等少數Android TV電視發布近兩年後,Google終於推出了面向iOS平台的An