接上一篇文章:《源码分析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。

更多相关文章

  1. Android(安卓)路由框架
  2. Android(安卓)Lua 相互调用
  3. Android学习-SharedPreferences接口的学习
  4. Android(安卓)IPC 机制详解:IBinder
  5. Android(安卓)zygote与进程创建(一)
  6. Android(安卓)TextView使用HTML处理字体样式、显示图片等
  7. 快速理解android View的测量onMeasure()与MeasureSpec
  8. init进程【2】——解析配置文件
  9. Android(安卓)根文件系统启动过程

随机推荐

  1. android架构
  2. Android设备预计将超微软
  3. Android开发之活动与任务
  4. 浅析 Android 的窗口
  5. Dagger Hilt - Android官方推荐的依赖注
  6. 学习android(1)
  7. Android NDK开发(一)——ndk-build编译生
  8. android 圆形进度条的简单实现
  9. Android下怎么使用LDD查看依赖库
  10. Android中的横竖屏