Android 應用程序啟動流程
我們知道啟動Activity時,在ActivityStackSupervisor.java中函式startSpecificActivityLocked裡面會判斷當前Activity所在application是否已經啟動,如果啟動,則直接建立Activity也即呼叫realStartActivityLocked,本篇討論需要啟動的Activity所屬的application沒有啟動的情況,此時就會通過AMS來呼叫startProcessLocked建立新程序。
AMS獲取請求
在ActivityStackSupervisor中分析完確定啟動新程序,就會操作權交給AMS來處理,如圖:startSpecificActivityLocked分析是否要建立程序
mService.startProcessLocked進入AMS處理流程,最終會進入AMS內部私有函式private final void startProcessLocked(ProcessRecord app,void startSpecificActivityLocked(ActivityRecord r, boolean andResume, boolean checkConfig) { // Is this activity's application already running? ProcessRecord app = mService.getProcessRecordLocked(r.processName, r.info.applicationInfo.uid, true); r.task.stack.setLaunchTime(r); if (app != null && app.thread != null) { try { ...... realStartActivityLocked(r, app, andResume, checkConfig); return; } catch (RemoteException e) { ...... } ...... } mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }
String hostingType, String hostingNameStr),如下:
接著Process接手啟動應用主執行緒ActivityThread的任務private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr) { ...... try { ...... // Start the process. It will either succeed and return a result containing // the PID of the new process, or else throw a RuntimeException. Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread", app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, null); ...... if (app.persistent) { Watchdog.getInstance().processStarted(app.processName, startResult.pid); } ...... } } catch (RuntimeException e) { // XXX do better error recovery. app.setPid(0); Slog.e(TAG, "Failure starting process " + app.processName, e); } }
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[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
throw new RuntimeException(
"Starting VM process through Zygote failed", ex);
}
}
然後,startViaZygote封裝相關資訊,向Zygote服務程序傳送啟動新應用程序的請求,並通過/dev/socket/zygote通道傳送請求資訊。
private static 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[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
ArrayList<String> argsForZygote = new ArrayList<String>();
// --runtime-init, --setuid=, --setgid=,
// and --setgroups= must go first
argsForZygote.add("--runtime-init");
argsForZygote.add("--setuid=" + uid);
argsForZygote.add("--setgid=" + gid);
if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
argsForZygote.add("--enable-jni-logging");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
argsForZygote.add("--enable-safemode");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
argsForZygote.add("--enable-debugger");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
argsForZygote.add("--enable-checkjni");
}
if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
argsForZygote.add("--enable-assert");
}
if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER) {
argsForZygote.add("--mount-external-multiuser");
} else if (mountExternal == Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL) {
argsForZygote.add("--mount-external-multiuser-all");
}
argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
//TODO optionally enable debuger
//argsForZygote.add("--enable-debugger");
// --setgroups is a comma-separated list
if (gids != null && gids.length > 0) {
StringBuilder sb = new StringBuilder();
sb.append("--setgroups=");
int sz = gids.length;
for (int i = 0; i < sz; i++) {
if (i != 0) {
sb.append(',');
}
sb.append(gids[i]);
}
argsForZygote.add(sb.toString());
}
if (niceName != null) {
argsForZygote.add("--nice-name=" + niceName);
}
if (seInfo != null) {
argsForZygote.add("--seinfo=" + seInfo);
}
argsForZygote.add(processClass);
if (extraArgs != null) {
for (String arg : extraArgs) {
argsForZygote.add(arg);
}
}
return zygoteSendArgsAndGetResult(argsForZygote);
}
}
zygoteSendArgsAndGetResult傳送封裝的資訊並獲取返回結果
private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
throws ZygoteStartFailedEx {
openZygoteSocketIfNeeded();
try {
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
* Presently the wire format to the zygote process is:
* a) a count of arguments (argc, in essence)
* b) a number of newline-separated argument strings equal to count
*
* After the zygote process reads these it will write the pid of
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
sZygoteWriter.write(Integer.toString(args.size()));
sZygoteWriter.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++) {
String arg = args.get(i);
if (arg.indexOf('\n') >= 0) {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
sZygoteWriter.write(arg);
sZygoteWriter.newLine();
}
sZygoteWriter.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
result.pid = sZygoteInputStream.readInt();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
result.usingWrapper = sZygoteInputStream.readBoolean();
return result;
} catch (IOException ex) {
try {
if (sZygoteSocket != null) {
sZygoteSocket.close();
}
} catch (IOException ex2) {
// we're going to fail anyway
Log.e(LOG_TAG,"I/O exception on routine close", ex2);
}
sZygoteSocket = null;
throw new ZygoteStartFailedEx(ex);
}
}
openZygoteSocketIfNeeded建立通訊需要使用的通道
private static void openZygoteSocketIfNeeded()
throws ZygoteStartFailedEx {
......
for (int retry = 0
; (sZygoteSocket == null) && (retry < (retryCount + 1))
; retry++ ) {
......
try {
sZygoteSocket = new LocalSocket();
sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
LocalSocketAddress.Namespace.RESERVED));
sZygoteInputStream
= new DataInputStream(sZygoteSocket.getInputStream());
sZygoteWriter =
new BufferedWriter(
new OutputStreamWriter(
sZygoteSocket.getOutputStream()),
256);
Log.i("Zygote", "Process: zygote socket opened");
sPreviousZygoteOpenFailed = false;
break;
} catch (IOException ex) {
if (sZygoteSocket != null) {
try {
sZygoteSocket.close();
} catch (IOException ex2) {
Log.e(LOG_TAG,"I/O exception on close after exception",
ex2);
}
}
sZygoteSocket = null;
}
}
if (sZygoteSocket == null) {
sPreviousZygoteOpenFailed = true;
throw new ZygoteStartFailedEx("connect failed");
}
}
其中“ZYGOTE_SOCKET”為"zygote",建立通道後,對應裝置檔案“/dev/socket/zygote”,接著就使用sZygoteWriter將資訊傳送給服務端,服務端接手到後就會建立新程序,最後通過sZygoteInputStream分別獲取pid(=sZygoteInputStream.readInt()),usingWrapper(= sZygoteInputStream.readBoolean())。
Zygote孵化子程序
以上Prcess向Zygote傳送啟動子程序的訊息後,Zygote守護程序就會開始建立子程序。Zygote服務程序會監聽“/dev/socket/zygote”裝置檔案,一旦有讀寫動作,內部的輪詢函授runSelectLoop就會建立ZygoteConnection,並執行runOnce
boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
String args[];
Arguments parsedArgs = null;
FileDescriptor[] descriptors;
try {
args = readArgumentList();
descriptors = mSocket.getAncillaryFileDescriptors();
} catch (IOException ex) {
Log.w(TAG, "IOException on command socket " + ex.getMessage());
closeSocket();
return true;
}
if (args == null) {
// EOF reached.
closeSocket();
return true;
}
/** the stderr of the most recent request, if avail */
PrintStream newStderr = null;
if (descriptors != null && descriptors.length >= 3) {
newStderr = new PrintStream(
new FileOutputStream(descriptors[2]));
}
int pid = -1;
FileDescriptor childPipeFd = null;
FileDescriptor serverPipeFd = null;
try {
parsedArgs = new Arguments(args);
applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyCapabilitiesSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext);
applyDebuggerSystemProperty(parsedArgs);
applyInvokeWithSystemProperty(parsedArgs);
int[][] rlimits = null;
if (parsedArgs.rlimits != null) {
rlimits = parsedArgs.rlimits.toArray(intArray2d);
}
if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
FileDescriptor[] pipeFds = Libcore.os.pipe();
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
ZygoteInit.setCloseOnExec(serverPipeFd, true);
}
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
parsedArgs.niceName);
} catch (IOException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (ErrnoException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (IllegalArgumentException ex) {
logAndPrintError(newStderr, "Invalid zygote arguments", ex);
} catch (ZygoteSecurityException ex) {
logAndPrintError(newStderr,
"Zygote security policy prevents request: ", ex);
}
try {
if (pid == 0) {
// in child
IoUtils.closeQuietly(serverPipeFd);
serverPipeFd = null;
handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
// should never get here, the child is expected to either
// throw ZygoteInit.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);
}
}
readArgumentList獲取引數列表,也即startViaZygote中封裝的引數列表,接著呼叫Zygote的forkAndSpecialize,在到JNI層的nativeForkAndSpecialize,
forkAndSpecializeCommon,在到核心的fork函式,完成程序的建立,後面呼叫handleChildProc,handleParentProc對父子程序做相關處理。
private boolean handleParentProc(int pid,
FileDescriptor[] descriptors, FileDescriptor pipeFd, Arguments parsedArgs) {
if (pid > 0) {
setChildPgid(pid);
}
if (descriptors != null) {
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
}
boolean usingWrapper = false;
if (pipeFd != null && pid > 0) {
DataInputStream is = new DataInputStream(new FileInputStream(pipeFd));
int innerPid = -1;
try {
innerPid = is.readInt();
} catch (IOException ex) {
Log.w(TAG, "Error reading pid from wrapped process, child may have died", ex);
} finally {
try {
is.close();
} catch (IOException ex) {
}
}
// Ensure that the pid reported by the wrapped process is either the
// child process that we forked, or a descendant of it.
if (innerPid > 0) {
int parentPid = innerPid;
while (parentPid > 0 && parentPid != pid) {
parentPid = Process.getParentPid(parentPid);
}
if (parentPid > 0) {
Log.i(TAG, "Wrapped process has pid " + innerPid);
pid = innerPid;
usingWrapper = true;
} else {
Log.w(TAG, "Wrapped process reported a pid that is not a child of "
+ "the process that we forked: childPid=" + pid
+ " innerPid=" + innerPid);
}
}
}
try {
mSocketOutStream.writeInt(pid);
mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
Log.e(TAG, "Error reading from command socket", ex);
return true;
}
return false;
}
handleParentProc設定程序組,返回pid,usingWrapper的值。
private void handleChildProc(Arguments parsedArgs,
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
closeSocket();
ZygoteInit.closeServerSocket();
if (descriptors != null) {
try {
ZygoteInit.reopenStdio(descriptors[0],
descriptors[1], descriptors[2]);
for (FileDescriptor fd: descriptors) {
IoUtils.closeQuietly(fd);
}
newStderr = System.err;
} catch (IOException ex) {
Log.e(TAG, "Error reopening stdio", ex);
}
}
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
}
if (parsedArgs.runtimeInit) {
if (parsedArgs.invokeWith != null) {
WrapperInit.execApplication(parsedArgs.invokeWith,
parsedArgs.niceName, parsedArgs.targetSdkVersion,
pipeFd, parsedArgs.remainingArgs);
} else {
RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion,
parsedArgs.remainingArgs);
}
} else {
String className;
try {
className = parsedArgs.remainingArgs[0];
} catch (ArrayIndexOutOfBoundsException ex) {
logAndPrintError(newStderr,
"Missing required class name argument", null);
return;
}
String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1];
System.arraycopy(parsedArgs.remainingArgs, 1,
mainArgs, 0, mainArgs.length);
if (parsedArgs.invokeWith != null) {
WrapperInit.execStandalone(parsedArgs.invokeWith,
parsedArgs.classpath, className, mainArgs);
} else {
ClassLoader cloader;
if (parsedArgs.classpath != null) {
cloader = new PathClassLoader(parsedArgs.classpath,
ClassLoader.getSystemClassLoader());
} else {
cloader = ClassLoader.getSystemClassLoader();
}
try {
ZygoteInit.invokeStaticMain(cloader, className, mainArgs);
} catch (RuntimeException ex) {
logAndPrintError(newStderr, "Error starting.", ex);
}
}
}
}
handleChildProc最主要的任務就調到ZygoteInit的invokeStaticMain方法,中間主要是使用放射方式構造ActivityThread類並呼叫main方法 static void invokeStaticMain(ClassLoader loader,
String className, String[] argv)
throws ZygoteInit.MethodAndArgsCaller {
Class<?> cl;
try {
cl = loader.loadClass(className);
} catch (ClassNotFoundException ex) {
throw new RuntimeException(
"Missing class when invoking static main " + className,
ex);
}
Method m;
try {
m = cl.getMethod("main", new Class[] { String[].class });
} catch (NoSuchMethodException ex) {
throw new RuntimeException(
"Missing static main on " + className, ex);
} catch (SecurityException ex) {
throw new RuntimeException(
"Problem getting static main on " + className, ex);
}
int modifiers = m.getModifiers();
if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
throw new RuntimeException(
"Main method is not public and static on " + className);
}
/*
* 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);
}
調完ActivityThread.main方法之後,應用的程序的啟動也就完成了。Activity在主執行緒ActivityThread建立之後,程序空間就準備完畢,後續就call onCreate,onResume來完成介面佈局。相關推薦
Android 應用程序啟動流程
我們知道啟動Activity時,在ActivityStackSupervisor.java中函式startSpecificActivityLocked裡面會判斷當前Activity所在application是否已經啟動,如果啟動,則直接建立Activity也即呼叫realS
Android 應用程序啟動流程
閱讀的收益 討論的內容也就是一個應用程序是如何啟動的,私以為這一部分的內容頗為重要,即便不瞭解細節,也要知道其中的大體步驟。特別是針對我們應用開發者而言,理應瞭解我們的 App 是如何被啟動的,App 中的元件是如何被系統服務呼叫和組織的。 講應用程序啟動的文章不是很多,也
Android原始碼解析之(十一)-->應用程序啟動流程
本節主要是通過分析Activity的啟動過程介紹應用程式程序的啟動流程。關於Android的應用程序在android guide中有這樣的一段描述: By default, every application runs in its own Linu
Android程式入口ActivityThread和Android應用程式啟動流程詳解
大家初學java時候都知道java的程式入口是從main方法進入,那麼Android是基於java編寫的,那Android的程式入口做了哪些操作呢?還有Android的應用程式到底是怎樣啟動的呢?我們一起來看一下. 首先附上ActivityThread.
Android APK打包安裝、應用程序啟動過程、Activity啟動流程
目錄 一、Android APK的構建過程 通過IDE可以生成可以在android裝置中安裝的apk檔案,Google官方提供的構建APK的過程流程圖如下: 打包APK流程總結如下: AAPT(Android Asset Packaging Tool)工
Android中system server程序啟動流程原始碼解析 系統服務啟動
system server 前言 System Server fork SystemServer SystemServer.main() SystemServer.createSystemContext SystemSe
Android雜談:systrace簡單檢視一個應用的啟動流程
騰空.png systrace是用來檢視應用和系統執行狀態的工具,利用他可以分析一些效能問題。例如檢視應用是否卡頓,卡在那個方法了之類的問題。本文簡單抓一個瀏覽器啟動的systrace隨便看看吧。 一.啟動Andriod Device Monitor 連線
Android進階(二): 應用程序啟動過程
1.前言 最近一直在看 《Android進階解密》 的一本書,這本書編寫邏輯、流程都非常好,而且很容易看懂,非常推薦大家去看看(沒有收廣告費,單純覺得作者寫的很好)。 今天就將 應用程序啟動過程 總結一下(基於Android 8.0 系統)。 文章中例項&nbs
Android原始碼解析之(九)-->SystemServer程序啟動流程
上面一文中我們講過android系統中比較重要的幾個程序:init程序,Zygote程序,SystemServer程序已經各種應用程序,其中Zygote程序是整個android系統的根程序,包含SystemServer程序已經各種應用程序在內的程序都是通過Z
Android 7.0應用冷啟動流程分析
最近在為自己Moto G定製Rom,順便重新讀了一遍Android 7.0的相關原始碼,特此記錄當做筆記. 在開始正文之前,首先要明白冷啟動和熱啟動.所謂冷啟動就是啟動該應用時,後臺沒有該應用的程序,此時系統會建立一個程序分配給它(AMS通過Socket和Zy
android應用程式啟動詳情之程序相關
當某個應用元件啟動且該應用沒有執行其他任何元件時,Android 系統會使用單個執行執行緒為應用啟動新的 Linux 程序。 預設情況下,同一應用的所有元件在相同的程序和執行緒(稱為“主”執行緒)中執行。 如果某個應用元件啟動且該應用已存在程序(因為存在
Android O: init程序啟動流程分析(階段三)
本篇部落格我們就來看看init程序啟動時,解析init.rc檔案相關的工作。 一、建立Parser並決定解析檔案 int main(int argc, char** argv) { .............. //定義Action中
關於Android應用程序漏洞的防護措施
android 應用程序 移動應用 開發者 目前,Android應用程序市場的發展速度飛快,不少開發者為了追求開發速度而忽視應用程序的安全。但由於Android系統的開源性及其Java編寫的特殊性,各類Android App經常被爆出漏洞,有的Android開發者只是對App進行
最優雅退出 Android 應用程序的 6 種方式
home鍵 應用 一點 container new 出棧 manage 而且 rec 一、容器式建立一個全局容器,把所有的Activity存儲起來,退出時循環遍歷finish所有Activity import java.util.ArrayList; impor
【苦讀官方文檔】2.Android應用程序基本原理概述
project 做出 系統默認 體驗 告訴 sta 執行過程 顏色 硬件配置 官方文檔原文地址 應用程序原理 Android應用程序是通過Java編程語言來寫。Android軟件開發工具把你的代碼和其它數據、資源文件一起編譯、打包成一個APK文件
在Android應用程序中實現推送通知
xamarin android 幾乎每一個應用程序的一個重要特性是支持推送通知的能力。使用推送通知,您可以更新用戶,而不需要應用程序在任何時候運行或輪詢服務器, 避免潛在的電池電量不足。 隨著火力點雲信息的介紹(FCM),谷歌使得在Android應用程序中實現推送通知變
Android應用程序訪問linux驅動第一步:實現並測試Linux驅動
sizeof 屬性文件 rup sla 沒有 lov /dev/ art kmalloc 一直都想親自做一次使用android應用程序訪問Linux內核驅動的嘗試,但總是沒能做到。最近抽出時間,下決心重新嘗試一次。嘗試的開始當然是先寫一個Linux內核驅動了。 我希望
iOS 應用程序啟動時要做什麽
通過 有關 撤銷 任務 臨時 hone 分享 ext 後臺 當您的應用程序啟動(無論是在前臺或後臺),使用您的應用程序委托application:willFinishLaunchingWithOptions:和application:didFinishLaunchingWi
Android應用一般上架流程
blog 個人 con 地址 -m cal 截圖 click mil Android App上架所需文件 上架準備 ?App文件: 1.?安裝包 2.?應用商標:圖
C#使用Xamarin開發Android應用程序 -- 系列文章
android界面 百度 0.11 itl 利用 設備 android安裝 tor href Xamarin開發Android應用程序 利用Xamaria構建Android應用-公交發車信息屏 Xamarin版的C# SVG路徑解析器 C#使用Xamarin開發可移植