源码分析Android(安卓)应用进程的启动过程
接上一篇文章:《源码分析Android SystemServer进程的启动过程》
三、普通Apk应用程序的启动过程
关于这部分完成的过程分析可以看罗升阳老师的文章:http://blog.csdn.net/luoshengyang/article/details/6689748
因为其过程太长了,所以我的研究将从最重要的地方去着手分析。
一般第三方的应用程序启动都是通过桌面来启动的,所以其实它启动的第一步的底层调用也是通过startActivity来启动程序,关于这部分上面链接的文章分析得十分精彩。我要研究的地方是从Ams要准备通知Zygote创建应用进程开始。
startActivity会调用Ams的接口,经过九转十八弯,会调用ActivityStackSupervisor.startSpecificActivityLocked()接口:
源码目录:/frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java(5.1系统)
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 { if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0 || !"android".equals(r.info.packageName)) { // Don't add this if it is a platform component that is marked // to run in multiple processes, because this is actually // part of the framework so doesn't make sense to track as a // separate apk in the process. app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode, mService.mProcessStats); } realStartActivityLocked(r, app, andResume, checkConfig); return; } catch (RemoteException e) { Slog.w(TAG, "Exception when starting activity " + r.intent.getComponent().flattenToShortString(), e); } // If a dead object exception was thrown -- fall through to // restart the application. } mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0, "activity", r.intent.getComponent(), false, false, true); }
标注①:说明下参数ActivityRecord r,r是用将要启动的第三方Apk程序的MainActivity创建的ActivityRecord ;
标注②:因为这里是第一次启动,所以此处的app是为null,因此就会调用mService.startProcessLocked()接口,mService是ActivityManagerService类型,所以就会调用Ams的startProcessLocked()接口;
看到这个接口的名字,我们就知道开始有戏了,它要启动一个进程!跟进去看看;
5.1的Ams中有四个startProcessLocked的重载函数,上面调用的是其9个参数的方法,9参数的方法内部又调用了14参数的方法:
final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, boolean keepIfLarge) { return startProcessLocked(processName, info, knownToBeDead, intentFlags, hostingType, hostingName, allowWhileBooting, isolated, 0 /* isolatedUid */, keepIfLarge, null /* ABI override */, null /* entryPoint */, null /* entryPointArgs */, null /* crashHandler */); } final ProcessRecord startProcessLocked(String processName, ApplicationInfo info, boolean knownToBeDead, int intentFlags, String hostingType, ComponentName hostingName, boolean allowWhileBooting, boolean isolated, int isolatedUid, boolean keepIfLarge, String abiOverride, String entryPoint, String[] entryPointArgs, Runnable crashHandler) { long startTime = SystemClock.elapsedRealtime(); ProcessRecord app; if (!isolated) { app = getProcessRecordLocked(processName, info.uid, keepIfLarge); ① checkTime(startTime, "startProcess: after getProcessRecord"); } else { // If this is an isolated process, it can't re-use an existing process. app = null; } ... if (app != null && app.pid > 0) { ... } ... if (app == null) { checkTime(startTime, "startProcess: creating new process record"); app = newProcessRecordLocked(info, processName, isolated, isolatedUid); ② if (app == null) { Slog.w(TAG, "Failed making new process record for " + processName + "/" + info.uid + " isolated=" + isolated); return null; } app.crashHandler = crashHandler; mProcessNames.put(processName, app.uid, app); if (isolated) { mIsolatedProcesses.put(app.uid, app); } checkTime(startTime, "startProcess: done creating new process record"); } else { // If this is a new package in the process, add the package to the list app.addPackage(info.packageName, info.versionCode, mProcessStats); checkTime(startTime, "startProcess: added package to existing proc"); } // If the system is not ready yet, then hold off on starting this // process until it is. if (!mProcessesReady && !isAllowedWhileBooting(info) && !allowWhileBooting) { if (!mProcessesOnHold.contains(app)) { mProcessesOnHold.add(app); } if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app); checkTime(startTime, "startProcess: returning with proc on hold"); return app; } checkTime(startTime, "startProcess: stepping in to startProcess"); startProcessLocked( app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs); ③ checkTime(startTime, "startProcess: done starting proc!"); return (app.pid != 0) ? app : null; }
标注①:从上面的调用可以知道传进来的参数isolated是false,所以会进入判断条件;因为此处应用程序的进程还没启动,所以getProcessRecordLocked返回的结果是null;
标注②:为要启动的进程创建一个ProcessRecord;
标注③:调用6参数的startProcessLocked接口创建进程;
这个接口我们看最关键的部分:
private final void startProcessLocked(ProcessRecord app, String hostingType, String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) { ... // Start the process. It will either succeed and return a result containing // the PID of the new process, or else throw a RuntimeException. boolean isActivityProcess = (entryPoint == null); if (entryPoint == null) entryPoint = "android.app.ActivityThread"; ① checkTime(startTime, "startProcess: asking zygote to start proc"); Process.ProcessStartResult startResult = Process.start(entryPoint, ② app.processName, uid, uid, gids, debugFlags, mountExternal, app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, app.info.dataDir, entryPointArgs); checkTime(startTime, "startProcess: returned from zygote!"); if (app.isolated) { mBatteryStatsService.addIsolatedUid(app.uid, app.info.uid); } mBatteryStatsService.noteProcessStart(app.processName, app.info.uid); checkTime(startTime, "startProcess: done updating battery stats"); EventLog.writeEvent(EventLogTags.AM_PROC_START, UserHandle.getUserId(uid), startResult.pid, uid, app.processName, hostingType, hostingNameStr != null ? hostingNameStr : ""); if (app.persistent) { Watchdog.getInstance().processStarted(app.processName, startResult.pid); } ... }
标注①:终于看到我们熟悉的ActivityThread!关于ActivityThread相信大家都不陌生,从这里可以看出一个进程是对应一个ActivityThread的。从上面调用传参可知这里变量entryPoint是为null,所以entryPoint会被置为”android.app.ActivityThread”;
标注②:调用Process.start去创建进程,从注释可知,这里只有两个结果,要不返回新进程,要不就抛出RuntimeException。
再跟进去看看Process.start如何创建进程:
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 abi, String instructionSet, String appDataDir, String[] zygoteArgs) { try { return startViaZygote(processClass, niceName, uid, gid, gids, debugFlags, mountExternal, targetSdkVersion, seInfo, abi, instructionSet, appDataDir, 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进程:
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 abi, String instructionSet, String appDataDir, String[] extraArgs) throws ZygoteStartFailedEx { synchronized(Process.class) { ArrayList argsForZygote = new ArrayList(); // --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); } if (instructionSet != null) { argsForZygote.add("--instruction-set=" + instructionSet); } if (appDataDir != null) { argsForZygote.add("--app-data-dir=" + appDataDir); } argsForZygote.add(processClass); if (extraArgs != null) { for (String arg : extraArgs) { argsForZygote.add(arg); } } return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote); } }
又接着调用了zygoteSendArgsAndGetResult接口,观其名字可知该方法是传递一些参数给Zygote进程并且等待其创建的结果:
/** * Sends an argument list to the zygote process, which starts a new child * and returns the child's pid. Please note: the present implementation * replaces newlines in the argument list with spaces. * * @throws ZygoteStartFailedEx if process start failed for any reason */ private static ProcessStartResult zygoteSendArgsAndGetResult( ZygoteState zygoteState, ArrayList args) throws ZygoteStartFailedEx { 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. */ final BufferedWriter writer = zygoteState.writer; final DataInputStream inputStream = zygoteState.inputStream; writer.write(Integer.toString(args.size())); writer.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"); } writer.write(arg); writer.newLine(); } writer.flush(); // Should there be a timeout on this? ProcessStartResult result = new ProcessStartResult(); result.pid = inputStream.readInt(); if (result.pid < 0) { throw new ZygoteStartFailedEx("fork() failed"); } result.usingWrapper = inputStream.readBoolean(); return result; } catch (IOException ex) { zygoteState.close(); throw new ZygoteStartFailedEx(ex); } }
观察整个接口好像没有哪个地方创建新进程啊,可是为什么突然就有一个result变量带有新进程的pid呢?其实是这样的,在Zygote进程初始化的时候,就启动了一个Socket的服务端口供后续通信,具体代码在ZygoteInit.main函数中,其调用了registerZygoteSocket()接口启动了Socket。而上面的zygoteSendArgsAndGetResult方法中就是构造了一个BufferedWriter变量保存了参数并传递到Zygote的Socket服务端中,所以writer.flush(); 之后便跳转到了Zygote进程中了;
当Zygote Socket收到命令时,会调用ZygoteConnection.runOnce()接口去处理:
/** * Reads one start command from the command socket. If successful, * a child is forked and a {@link ZygoteInit.MethodAndArgsCaller} * exception is thrown in that child while in the parent process, * the method returns normally. On failure, the child is not * spawned and messages are printed to the log and stderr. Returns * a boolean status value indicating whether an end-of-file on the command * socket has been encountered. * * @return false if command socket should continue to be read from, or * true if an end-of-file has been encountered. * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main() * method in child process */ boolean runOnce() throws ZygoteInit.MethodAndArgsCaller { String args[]; Arguments parsedArgs = null; FileDescriptor[] descriptors; long startTime = SystemClock.elapsedRealtime(); try { args = readArgumentList(); ① descriptors = mSocket.getAncillaryFileDescriptors(); } catch (IOException ex) { Log.w(TAG, "IOException on command socket " + ex.getMessage()); closeSocket(); return true; } checkTime(startTime, "zygoteConnection.runOnce: readArgumentList"); 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); if (parsedArgs.abiListQuery) { return handleAbiListQuery(); } if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) { throw new ZygoteSecurityException("Client may not specify capabilities: " + "permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) + ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities)); } applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); applyDebuggerSystemProperty(parsedArgs); applyInvokeWithSystemProperty(parsedArgs); checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); int[][] rlimits = null; if (parsedArgs.rlimits != null) { rlimits = parsedArgs.rlimits.toArray(intArray2d); } if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) { FileDescriptor[] pipeFds = Os.pipe(); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; ZygoteInit.setCloseOnExec(serverPipeFd, true); } /** * In order to avoid leaking descriptors to the Zygote child, * the native code must close the two Zygote socket descriptors * in the child process before it switches from Zygote-root to * the UID and privileges of the application being launched. * * In order to avoid "bad file descriptor" errors when the * two LocalSocket objects are closed, the Posix file * descriptors are released via a dup2() call which closes * the socket and substitutes an open descriptor to /dev/null. */ int [] fdsToClose = { -1, -1 }; FileDescriptor fd = mSocket.getFileDescriptor(); if (fd != null) { fdsToClose[0] = fd.getInt$(); } fd = ZygoteInit.getServerSocketFileDescriptor(); if (fd != null) { fdsToClose[1] = fd.getInt$(); } fd = null; checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize"); pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, ② parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir); checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize"); } 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接口读取到的参数就是刚才buffer里保存的参数;
标注②:我们想看到的代码终于出现了!!调用了Zygote.forkAndSpecialize去fork了一个新的子进程!从这里可以看见所有应用程序的进程都是由Zygote进程fork出来的。
标注③:调用handleChildProc接口来处理新创建的子进程,在这个函数里面最终会反射一开始创建来的entryPoint参数的类,这里就是反射了ActivityThread,并调用了它的main函数;
接下来的工作就是ActivityThread的事情了,我们后续再研究。至此启动应用程序进程的过程告一段落。
小结:
1、Zygote进程初始时,启动了ZygoteSocket的服务端口,供后续一个Socket通信,例如启动创建应用进程;调用ZygoteConnection的runOnce处理接收的命令;
2、SystemServer进程是Zygote进程fork的第一个进程,它是在ZygoteInit的main函数中调用startSystemServer创建的;
3、SystemServer进程和普通的应用程序进程都是由Zygote进程fork出来,不同的地方是,SystemServer进程是通过Zygote.forkSystemServer创建的,而普通应用进程是由Zygote.forkAndSpecialize创建的。两个方法的区别,这里有源码注释:
/** * Special method to start the system server process. In addition to the * common actions performed in forkAndSpecialize, the pid of the child * process is recorded such that the death of the child process will cause * zygote to exit.
4、从上面源码可知,应用层中的一个进程对应一个ActivityThread,因为进程启动后加载的一个java文件就是ActivityThread。
更多相关文章
- Android(安卓)路由框架
- Android(安卓)Lua 相互调用
- Android学习-SharedPreferences接口的学习
- Android(安卓)IPC 机制详解:IBinder
- Android(安卓)zygote与进程创建(一)
- Android(安卓)TextView使用HTML处理字体样式、显示图片等
- 快速理解android View的测量onMeasure()与MeasureSpec
- init进程【2】——解析配置文件
- Android(安卓)根文件系统启动过程