App启动流程:启动App进程

目录

  • 概述
  • 总结
  • 详细过程
  • 问题&主要类说明

概述

-1-
在冷启动过程中,当“为App启动做完准备”之后( <<为目标App启动做准备>>),就需要检查App进程是否开启了,如果没有则需要先执行 App进程的创建操作。
-2-
当前源码的分析是基于 Android8.0。


总结

应用程序进程的启动可以是分为2个部分的。

第一部分:
AMS向Zygote进程发起启动app进程的请求。
1:AMS调用其内部的“startProcessLocked()”来开启启动app进程的入口。该方法主要做的是:组装发给zygote进城的用于启动子进程的参数列表(这些参数包括:uid,gid,entryPoint 参数等,entryPoint参数的值为ActivityThread的类全限定名。该参数用于fork子进程之后启动每个app进程的ActivityThread去做初始化操作。)
2:通过层层调用最终会执行ZygoteProcess.startViaZygote(),该方法首先会把AMS服务传过来的参数封装到一个argsForZygote参数列表中。
3:调用ZygoteProcess内部的openZygoteSocketIfNeeded()与Zygote进程建立Socket连接。
4:调用ZygoteProcess的zygoteSendArgsAndGetResult(),该方法主要做的事情是:将请求参数列表发送到zygote进程,并接收Zygote进程启动子进程的响应结果。

第二部分:
Zygote接收到AMS请求fork子进程过程
1:Zygote进程被init进程拉起后,会通过反射调用ZygotInit的main(),该方法主要做的事情是:
1.1:初始化ZygoteServer并创建服务端Socket用于接收、执行其它进程向Zygote进程发起的请求。
1.2:启动SystemServer进程。
1.3:最后调用runSelectLoop()开始循环接收其它进程发起的请求。
2:如果检测到有请求发过来,runSlectLoop()中会把一次Socket封装成ZygoteConnection,而后执行其runOnce()方法。
3:在runOnce()内部会调用Zygote.forkAndSpecialize():内部调用native方法进行实际的fork子进程操作。fork成功的话则子进程pid等于0,不为0则表示fork失败(fork()采用copy on write技术,这是linux创建进程的标准方法,调用一次,返回两次。)。
4:如果pid为0,则表示当前代码执行在子进程,需要执行handleChildProc(),该方法主要做的是:关闭与Zygote进程的Socket连接,执行ZygoteInit.zygoteInit()。
5:ZygoteInit.zygoteInit(),该方法主要执行"子进程"的运行时初始化操作(这些初始化包括:启动Binder线程池、创建VM、以及反射执行子进程ActivityThread线程等)。
5.1:RuntimeInit.commonInit():该方法用于执行一些“通用工作的初始化操作”(eg:设置异常捕获程序(Thread.setDefaultUncaughtExceptionHandler())、设置默认的UA(user agent等等))。
5.2:ZygoteInit.nativeZygoteInit():启动Binder线程池。
5.3:RuntimeInit.applicationInit():设置虚拟机参数,反射执行ActivityThread.main(),对main线程进行初始化。


详细过程

第一部分:AMS向Zygot进程发起启动app进程的请求

1.startSpecificActivityLocked()

总结
1:通过AMS.getProcessRecordLocked()根据“进程名、uid”查询是否App的进程启动了,如果进程未创建则返回null(ProcessRecord“用于记录app所运行在的进程的信息”)。
2:通过ActivityStack.setLaunchTime()记录下执行Activity启动操作的时间点。
3:App进程未启动,通过AMS.startProcessLocked()继续后续操作。

源码

 void startSpecificActivityLocked(ActivityRecord r,
            boolean andResume, boolean checkConfig) {
        //App进程是否已经启动了
        ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                r.info.applicationInfo.uid, true);

        //该时间被记录在ActivityStack中,记录何时执行“Activity的启动”操作的。
        //在统计“冷启动耗时”与单个“Activity启动耗时”时会用到。
        //见[小节1.2]
        r.getStack().setLaunchTime(r);
    
        //如果App进程已经启动了,则直接激活待启动Activity。
        if (app != null && app.thread != null) {
            try {
                ......

                realStartActivityLocked(r, app, andResume, checkConfig);
                return;
            } catch (RemoteException e) {
                ......
            }

        }
    
        //App进程还没创建,则需要先创建App所运行在的进程
        //见[小节1.3]
        mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                "activity", r.intent.getComponent(), false, false, true);
    }

1.1.AMS.getProcessRecordLocked()
源码

final ProcessRecord getProcessRecordLocked(String processName, int uid, boolean keepIfLarge) {
    //如果要查找的是系统进程
        if (uid == SYSTEM_UID) {
            ......
        }
        ProcessRecord proc = mProcessNames.get(processName, uid);
        ......
        return proc;
    }

1.1.1:ProcessMap.get()

public E get(String name, int uid) {
        SparseArray<E> uids = mMap.get(name);
        //未缓存则返回null
        if (uids == null) return null;
        return uids.get(uid);
    }

1.2.ActivityStack.setLaunchTime()
总结
1:记录下执行Activity启动操作的时间点。
2:在待启动Activity所在的视图树经过第一次解析、测量、布局、绘制之后会用到存储在ActivityStack中的这个时间点。具体的会在ActivityRecord.reportLaunchTimeLocked()借助此时间点来统计“当前Activity的启动耗时”

源码
1.2.1:ActivityStack.setLaunchTime()

void setLaunchTime(ActivityRecord r) {
        if (r.displayStartTime == 0) {
            r.fullyDrawnStartTime = r.displayStartTime = SystemClock.uptimeMillis();
            if (mLaunchStartTime == 0) {
                startLaunchTraces(r.packageName);
        
                //记录执行Activity启动操作的时间点
                mLaunchStartTime = mFullyDrawnStartTime = r.displayStartTime;
            }
        } else if (mLaunchStartTime == 0) {
            startLaunchTraces(r.packageName);
            //记录执行Activity启动操作的时间点
            mLaunchStartTime = mFullyDrawnStartTime = SystemClock.uptimeMillis();
        }
    }

1.2.2.ActivityRecord.reportLaunchTimeLocked()

源码

    private void reportLaunchTimeLocked(final long curTime) {
        ......
        final long thisTime = curTime - displayStartTime;
        final long totalTime = stack.mLaunchStartTime != 0
                ? (curTime - stack.mLaunchStartTime) : thisTime;
        if (SHOW_ACTIVITY_START_TIME) {
            Trace.asyncTraceEnd(TRACE_TAG_ACTIVITY_MANAGER, "launching: " + packageName, 0);
            EventLog.writeEvent(AM_ACTIVITY_LAUNCH_TIME,
                    userId, System.identityHashCode(this), shortComponentName,
                    thisTime, totalTime);
            StringBuilder sb = service.mStringBuilder;
            sb.setLength(0);
            sb.append("Displayed ");
            sb.append(shortComponentName);
            sb.append(": ");
            TimeUtils.formatDuration(thisTime, sb);
            if (thisTime != totalTime) {
                sb.append(" (total ");
                TimeUtils.formatDuration(totalTime, sb);
                sb.append(")");
            }
            Log.i(TAG, sb.toString());
        }
        .....
    }

1.3.启动App进程
启动应用程序的进程主要分2个方面来分析:
1:AMS向Zygote发起fork子进程的过程。
2:Zygote接收AMS的请求创建子进程过程。


1.4.AMS向Zygote发起fork子进程的过程。

源码

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 */);
    }

1.5.AMS.startProcessLocked()

参数:
1:String processName:待启动的进程名。
2:ApplicationInfo info:存储的是Manifest文件中对<application>标签中声明的属性信息。
3:boolean knownToBeDead:此值为 true。
4:int intentFlags:此值为0。
5:String hostingType:此值为“activity”。用于表示“是因为执行什么操作才导致创建进程”的吗??
6:ComponentName hostingName:Intent 中保存的待启动Activity的组件信息。其中包括app的包名与待启动Activity的类名。
7:boolean allowWhileBooting:此值为 false。
8:boolean isolated:此值为 false。
9:int isolatedUid:此值为 0。
10:boolean keepIfLarge:此值为 true。
11:String abiOverride:此值为null。
12:String entryPoint:此值为null。

  • entryPoint在启动 App 进程之前会被重新赋值为“ActivityThread的全限定名”。
  • 在后续启动完进程后,会反射执行ActivityThread.main()开启ActivityThread表示的主线程并对其做相应初始化操作。

13:String[] entryPointArgs:此值为null。
14:Runnable crashHandler:此值为null。

总结

在启动App进程之前,需要先该把保存进程信息的ProcessRecord创建并缓存至AMS内部的ArrayMap中。
具体的:执行AMS. newProcessRecordLocked()先把保存待启动App进程的ProcessRecord创建完毕 并 缓存到AMS内部的一个ArrayMap。

源码

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;
        //isolated为false,所以走这里
        if (!isolated) {
            //获取每个进程对应的ProcessRecord。
            //因为待启动App还没有运行起来,所以获取的ProcessRecord为null。
            app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
            ......
        } else {
            app = null;
        }
        ......

        if (app == null) {
            //先把ProcessRecord创建好,其次缓存至AMS服务中的“mProcessNames”属性指向的ProcessMap中( ProcessMap内部维护了一个ArrayMap来缓存已经启动完毕的进程信息)。
            //见[小节1.6]
            app = newProcessRecordLocked(info, processName, isolated, isolatedUid);
            if (app == null) {
                //如果创建失败,则退出此次启动进程操作,并返回null表示启动进程操作失败了。
                return null;
            }
            ......
        } else {
            ......
        }

        //AMS服务已经在system_server进程中被初始化完毕了,mProcessesReady已经被赋值为了true。具体请查看`问题小节`。
        //不会走这里
        if (!mProcessesReady
                && !isAllowedWhileBooting(info)
                && !allowWhileBooting) {
            ......
            return app;
        }

       ......
       //见[小节1.7]
        startProcessLocked(
                app, hostingType, hostingNameStr, abiOverride, entryPoint, entryPointArgs);
        ......
        return (app.pid != 0) ? app : null;
    }

1.6.AMS.newProcessRecordLocked()
总结:
1:创建保存进程信息的ProcessRecord。
2:调用AMS.addProcessNameLocked()把此ProcessRecord缓存起来。

源码

final ProcessRecord newProcessRecordLocked(ApplicationInfo info, String customProcess,
            boolean isolated, int isolatedUid) {
        String proc = customProcess != null ? customProcess : info.processName;
        BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
        final int userId = UserHandle.getUserId(info.uid);
        int uid = info.uid;
        if (isolated) {
        ......
        }
        //创建一个ProcessRecord
        final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
        ......
        //见[小节1.6.1]
        addProcessNameLocked(r);
        return r;
    

1.6.1.AMS.addProcessNameLocked():把目标ProcessRecord缓存起来

private final void addProcessNameLocked(ProcessRecord proc) {
        ......
        //把ProcessRecord缓存起来
        mProcessNames.put(proc.processName, proc.uid, proc);
        ......
    }

1.7.AMS.startProcessLocked()
总结

1:重新对entryPoint的内容赋值,赋值后它存储的是“ActivityThread类的全限定名”,ActivityThread在后续进程启动完毕后,系统会反射执行ActivityThread.main()开启ActivityThread表示的主线程并对其做相应初始化操作。
2:继续后续进程的创建操作。
3:创建进程的系统事件会被记录到trace中,方便采用trace工具获得此事件花费的时间。进程创建完毕后,还会输出相应信息至logcat。
4:进程创建完毕,保存进程信息至ProcessRecord(如更新进程id只ProcessRecord中)。

源码

private final void startProcessLocked(ProcessRecord app, String hostingType,
            String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
        //App进程还未启动,此时pid为0。
        if (app.pid > 0 && app.pid != MY_PID) {
            ......
        }
        ......
        try {
            //设置该App是否可debug。
            //应用进程是否可被调试,是由在Manifest文件注册Application时对<application>添加“android:debuggable”属性来支持的。true是可debug,false是不可以。
            //在打debug包时,该属性是开启的。relase包是禁止的。
            if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
                ......
            }
            ......
            //因为entryPoint为null,所以isActivityProcess为true
            boolean isActivityProcess = (entryPoint == null);
            //因为entryPoint为null,所以为它赋值为“ActivityThread的全限定名”。
            //entryPoint很重要,用于后续启动完进程后,开启ActivityThread表示的主线程。
            if (entryPoint == null) entryPoint = "android.app.ActivityThread";
            //各种系统trace信息,此时这里开始记录进程的创建事件
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                    app.processName);
            ......
            ProcessStartResult startResult;
            //hostingType被初始化为“activity”,所以不会走这里。
            if (hostingType.equals("webview_service")) {
                ......
            } else {
                //见[小节1.8]
                startResult = Process.start(entryPoint,
                        app.processName, uid, uid, gids, debugFlags, mountExternal,
                        app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                        app.info.dataDir, invokeWith, entryPointArgs);
            }
            //保存 创建进程所花费的时间。
            Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
            ......
            //进程创建完毕后,会输出相应信息至logcat
            StringBuilder buf = mStringBuilder;
            buf.setLength(0);
            buf.append("Start proc ");
            buf.append(startResult.pid);
            buf.append(':');
            buf.append(app.processName);
            buf.append('/');
            UserHandle.formatUid(buf, uid);
            if (!isActivityProcess) {
                buf.append(" [");
                buf.append(entryPoint);
                buf.append("]");
            }
            buf.append(" for ");
            buf.append(hostingType);
            if (hostingNameStr != null) {
                buf.append(" ");
                buf.append(hostingNameStr);
            }
            Slog.i(TAG, buf.toString());
            //进程创建完毕,保存进程信息至ProcessRecord。
            app.setPid(startResult.pid);
            app.usingWrapper = startResult.usingWrapper;
            app.removed = false;
            app.killed = false;
            app.killedByAm = false;
            ......
        } catch (RuntimeException e) {
            ......
        }
    }

进程创建完毕log

04-25 16:40:20.824 1644-3146/? I/ActivityManager: Start proc 7880:sj.com.github_workspace/u0a83 for activity sj.com.github_workspace/.MainActivity


1.8.Process.start()
总结:
1:Process:用于管理操作系统进程的工具。

  • 该类中定义了一些进程的uid。例如:系统uid包括 电话,wifi等进程。应用程序进程uid的取值范围(FIRST_APPLICATION_UID与LAST_APPLICATION_UID之间,也就是[10000,19999])。
  • 提供了获取进程uid(应用id),userId(用户id),gid(进程组id),pid(进程id),ppid(父进程id)等信息的工具方法。(关于uid,userId,gid概念请参考 https://blog.csdn.net/zhanglianyu00/article/details/50253187)

2:Process类内部维护了一个ZygoteProcess类的实例,ZygoteProcess“用于保持与Zygote进程的通信状态。”

参数:
String processClass:ActivityThread类的全限定名。
String niceName:进程名。默认的话就是App的包名。
int uid:进程的uid。
int gid:进程组id。
int[] gids:待补充。。。
int debugFlags:存储了App进程是否可被debug的信息。
int mountExternal:待补充。。。
int targetSdkVersion:在Manifest文件中声明的targetSdk版本号。
String seInfo:待补充。。。
String abi:待补充。。。
String instructionSet:
String appDataDir:为存储App信息的内部存储目录(Sp文件、数据库就存在这里)。
String invokeWith:此值为null。
String[] extraArgs:此值为null。

源码

    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 invokeWith,
                                  String[] zygoteArgs) {
        //见小节[1.9]
        return zygoteProcess.start(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
    }

1.9.ZygoteProcess.start()
源码

    public final Process.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 invokeWith,
                                                  String[] zygoteArgs) {
        try {
            return startViaZygote(processClass, niceName, uid, gid, gids,
                    debugFlags, mountExternal, targetSdkVersion, seInfo,
                    abi, instructionSet, appDataDir, invokeWith, zygoteArgs);
        } catch (ZygoteStartFailedEx ex) {
            ......
        }
    }

1.10.ZygoteProcess.startViaZygote()

    private Process.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 invokeWith,
                                                      String[] extraArgs)
                                                      throws ZygoteStartFailedEx {
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // 设置一些运行时参数,这些参数就是根据传递给该方法的参数来设置的。
        //例如设置把uid,gid这些信息都封装到argsForZygote 这个列表中。
       ......
        synchronized(mLock) {
            //见[小节1.11]与[小节1.12]
            return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
        }
    }

1.11.ZygoteProcess.openZygoteSocketIfNeeded()
总结:

1:该方法内部会通过ZygoteState.connect(),打开与Zygote进程之间的Socket连接.
2:ZygoteState:该类为ZygoteProcess的内部类。表示一次与Zygote进程建立的Socket通信过程。其内部维护了LocalSocket与Zygote进程进行通信。


1.12.ZygoteProcess.zygoteSendArgsAndGetResult()
总结

1:用于将请求参数列表发送到zygote进程,并接收Zygote进程启动子进程的响应结果。
2:Zygote会把fork子进程的pid返回给AMS 。(通过openZygoteSocketIfNeeded()建立好连接之后就需要向Zygote发送请求数据,以及响应 Zygote发回的响应数据。该方法就是用来做发送、接受上述事情的。)

源码

    private static Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            // 检查参数列表
            int sz = args.size();
            for (int i = 0; i < sz; i++) {
                if (args.get(i).indexOf('\n') >= 0) {
                    throw new ZygoteStartFailedEx("embedded newlines not allowed");
                }
            }

            final BufferedWriter writer = zygoteState.writer;
            final DataInputStream inputStream = zygoteState.inputStream;
            
            //向Zygote进程写数据
            writer.write(Integer.toString(args.size()));
            writer.newLine();

            for (int i = 0; i < sz; i++) {
                String arg = args.get(i);
                writer.write(arg);
                writer.newLine();
            }

            writer.flush();
            
            //等Zygote进程处理完毕后,读取Zygote进程的处理结果
            result.pid = inputStream.readInt();
            result.usingWrapper = inputStream.readBoolean();
            
             //pid小于0则表示创建子进程失败的话,会抛出异常。
            if (result.pid < 0) {
                throw new ZygoteStartFailedEx("fork() failed");
            }
            return result;
        } catch (IOException ex) {
            zygoteState.close();
            throw new ZygoteStartFailedEx(ex);
        }
    }

第二部分:Zygote接收到AMS请求fork子进程过程

前提:

Zygote进程被init进程拉起后,会通过反射调用ZygotInit的main()进行初始化操作。这些初始化操作主要包括:
1:初始化ZygoteServer并创建服务端Socket用于接收、执行其它进程向Zygote进程发起的请求。
2:启动SystemServer进程。
3:最后调用runSelectLoop()开始循环接收其它进程发起的请求。

关于Zygote进程的初始化操作,请参看<<Zygote进程启动过程学习与理解>>

接下来从Zygote接收来自运行在system_server进程的AMS发送的启动App进程请求的地方说起。

2.1.ZygoteServer.runSelectLoop():开启死循环接收来自其他进程发起的Socket请求。
源码

void runSelectLoop(String abiList) throws Zygote.MethodAndArgsCaller {
       ......
        ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
       ......
        //开启死循环接收来自其他进程发起的Socket请求
        while (true) {
            ......
            try {
                Os.poll(pollFds, -1);
            } catch (ErrnoException ex) {
                throw new RuntimeException("poll failed", ex);
            }
            for (int i = pollFds.length - 1; i >= 0; --i) {
               ......
                if (i == 0) {
                    ZygoteConnection newPeer = acceptCommandPeer(abiList);
                    peers.add(newPeer);
                    fds.add(newPeer.getFileDesciptor());
                } else {
                    //如果接收到来自其他进程的Socket请求,则会走执行ZygoteConnection.run()
                    //见小节[2.2]
                    boolean done = peers.get(i).runOnce(this);
                    if (done) {
                        peers.remove(i);
                        fds.remove(i);
                    }
                }
            }
        }
    }

2.2.ZygoteConnection.runOnce():
总结:

1:fork函数,调用一次返回2次,在父进程返回子进程的实际pid,而在子进程中则返回0。这样做是为了“能够正确区分程序是运行在父进程还是子进程。”
2:调用Zygote.forkAndSpecialize()通过native方法创建子进程。
2:子进程启动完毕后,继续调用ZygoteConnection.handleChildProc()对子进程进行初始化。

源码

boolean runOnce(ZygoteServer zygoteServer) throws Zygote.MethodAndArgsCaller {
        ......
        //pid默认为-1。
        //AMS通过ZygoteProcess.zygoteSendArgsAndGetResult()向Zygote进程发送启动App进程的请求后,也会在该方法中进程的pid做检查,如果小于0,则会抛出“ZygoteStartFailedEx”提示创建进程失败。
        int pid = -1;
        ......
            //见小节[2.3]
            pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                    parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                    parsedArgs.niceName, fdsToClose, fdsToIgnore, parsedArgs.instructionSet,
                    parsedArgs.appDataDir);
        } 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 {
            //1:fork会“调用一次,返回两次”。分别在父进程、子进程返回。
            //2:在父进程返回子进程的实际pid,而在子进程返回的pid为0。这样做是为了“能够正确区分程序是运行在父进程还是子进程。”
            if (pid == 0) {
                // 这是程序运行在新创建的子进程中
                //fork()操作出的子进程是父进程的一个副本。父进程具备的他都用。自进程的虚拟地址空间与父进程一样,代码等都一致。那么Zygote进程内部开启了一个用于接收AMS发起的创建子进程的操作,该方法就是用来关闭“启动的用于接收AMS发起的Socket服务”。
                zygoteServer.closeServerSocket();
                IoUtils.closeQuietly(serverPipeFd);
                serverPipeFd = null;
                //见小节[2.4]
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                return true;
            } else {
                //这是运行在父进程
                IoUtils.closeQuietly(childPipeFd);
                childPipeFd = null;
                return handleParentProc(pid, descriptors, serverPipeFd, parsedArgs);
            }
        } finally {
            ......
        }
    }

2.3.Zygote.forkAndSpecialize()
源码

public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
          int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
          int[] fdsToIgnore, String instructionSet, String appDataDir) {
        ......
        int pid = nativeForkAndSpecialize(
                  uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                  fdsToIgnore, instructionSet, appDataDir);
       ......
        if (pid == 0) {
            //采用trace记录fork子进程的后,执行“handleChildProc()”花费的时间
            Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "PostFork");
        }
        ......
        return pid;
    }

2.4.ZygoteConnection.handleChildProc()(handle child process)

总结:

该方法在fork进程完毕后执行,用于关闭与Zygote进程的Socket连接, 执行ZygoteInit.zygoteInit()。

源码

private void handleChildProc(Arguments parsedArgs,
            FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
            throws Zygote.MethodAndArgsCaller {
          //关闭与Zygote建立的Socket连接
          closeSocket();
         //结束对该方法的记录
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
        //这个invokeWidth从AMS向Zygote发起请求时指定的值就是null。
        //不会走这里
        if (parsedArgs.invokeWith != null) {
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(),
                    pipeFd, parsedArgs.remainingArgs);
        } else {
            //见小节[2.5]
            ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion,
                    parsedArgs.remainingArgs, null /* classLoader */);
        }
    }

2.5.ZygoteInit.zygoteInit()
总结:

1:通过RuntimeInit.commonInit()对一些运行时的公共数据进行初始化操作(eg:设置异常捕获程序(Thread.setDefaultUncaughtExceptionHandler())、设置默认的UA(user agent等等)。
2:通过ZygoteInit.nativeZygoteInit(),启动App进程的Binder线程池。

源码

public static final void zygoteInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) throws Zygote.MethodAndArgsCaller {
        if (RuntimeInit.DEBUG) {
            Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
        }

        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
        RuntimeInit.redirectLogStreams();
        
        //一些公共数据的初始化
        //eg:设置异常捕获程序(Thread.setDefaultUncaughtExceptionHandler())、设置默认的UA(user agent等等)
        RuntimeInit.commonInit();
        //初始化App进程的Binder线程池
        ZygoteInit.nativeZygoteInit();
        //见小节[2.6]
        RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
    }

2.6.ZygoteInit.applicationInit()
源码

protected static void applicationInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
            throws Zygote.MethodAndArgsCaller {
        
        //设置虚拟机参数        
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);

        // 反射执行ActivityThread.main()
        //见小节[2.7]
        invokeStaticMain(args.startClass, args.startArgs, classLoader);
    }

2.7.RuntimeInit.invokeStaticMain():反射执行ActivityThread.main(),对main线程进行初始化。
源码

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
            throws Zygote.MethodAndArgsCaller {
        Class<?> cl;

        try {
            cl = Class.forName(className, true, classLoader);
        } catch (ClassNotFoundException ex) {
           ......
        }

        Method m;
        try {
            m = cl.getMethod("main", new Class[] { String[].class });
        } catch (NoSuchMethodException ex) {
            .......
        } catch (SecurityException ex) {
            ......
        }
        ......
        //见小节[2.8]
        throw new Zygote.MethodAndArgsCaller(m, argv);
    }

2.8.MethodAndArgsCaller .run():
总结

1:MethodAndArgsCaller是一个Runnable也是一个异常。该异常会在ZygiteInit.()中被捕获,捕获之后就会执行其run()。
2:在run()中,就是通过反射来执行ActivityThread.main()来对主线程进程初始化。

源码

public static class MethodAndArgsCaller extends Exception
            implements Runnable {
       ......
        public void run() {
            try {
                mMethod.invoke(null, new Object[] { mArgs });
            } catch (IllegalAccessException ex) {
               ......
            } catch (InvocationTargetException ex) {
                .....
            }
        }
    }

问题:

1:AMS.mProcessesReady属性是什么意思?systemReady()方法又是干什么的?
此属性用于表示“一些初始化的流程是否准备完毕”。如果该值为 false,那么在创建进程时,可能“先不会走实际创建进程的操作”。为 true,则才会走继续通知Zygote进程fork子进程。
system_server被Zygote进程拉起后,会执行SystemServer.main()对system_server进程做初始化操作。其中像AMS、WMS 就是在其中初始化的,当初始化AMS后则会执行其systemReady()去做“一些准备工作”,等其内部相应准备工作准备好后,则会更新该值为 true。**

2:操作系统提供的fork()函数大概是怎么工作的?
1:fork()会“调用一次,返回两次”。分别在父进程、子进程返回。
2:在父进程返回子进程的实际pid,而在子进程返回的pid为0。这样做是为了“能够正确区分程序是运行在父进程还是子进程。


重要类说明

1:ProcessRecord:用于记录app进程信息。
2:Process:用于管理操作系统进程的工具。
该类中定义了一些进程的uid。例如:系统基础讷航uid包括 电话,wifi等进程。应用程序进程uid的取值范围(
FIRST_APPLICATION_UID与
LAST_APPLICATION_UID之间,也就是[10000,19999])。
提供了获取进程uid(用户id),gid(组id),pid(进程id),ppid(父进程id)等信息的工具方法。
该类内部维护了一个ZygoteProcess,用于通过ZygoteProcess.start()通知Zygote进程来启动app进程。

3:ZygoteProcess:用于保持与Zygote进程的通信状态。
4:ZygoteState:该类为ZygoteProcess的内部类。表示一次与Zygote进程建立的Socket通信过程。其内部维护了LocalSocket与Zygote进程进行通信。
5:ZygoteInit:init进程启动完Zygote 进程之后,会执行该类的main()去做一些其它事情。这些事情包括:
1:创建ZygoteServer用于接受AMS发起的创建应用进程请求。
2:启动SystemServer进程。
3:执行ZygoteServer.runSelectLoop()开始循环接收其它进程发起的请求。

ZygoteServer:为Zygote服务,用于接收并执行来自AMS向其发送的Socket请求。
ZygoteConnection:该类表示AMS向Zygote发起的一起Socket连接请求。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,560评论 4 361
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,104评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,297评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,869评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,275评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,563评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,833评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,543评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,245评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,512评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,011评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,359评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,006评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,062评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,825评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,590评论 2 273
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,501评论 2 268

推荐阅读更多精彩内容

  • 理解Android进程创建流程理解Android进程启动之全过程 站在GITYUAN大神的肩膀上学习,用一张神图表...
    小编阅读 5,155评论 0 18
  • 在上一节Activity的启动流程中,当app进程不存在(第一次启动)时,会先去创建进程。这里我们通过源码来解读a...
    第八区阅读 510评论 0 0
  • 应用启动流程 Android系统是基于Linux的,所以它的所有应用也是基于Linux的Init进程创建出来的,首...
    SillyMonkey阅读 2,642评论 0 51
  • 我们不要相逢太晚 这样 我才会有姣好的容颜 与你在一棵开花的树下长谈 最好是在一个阳光明媚的日子里 满世界都为我们...
    安清尘阅读 75评论 0 0
  • 写出了我期待的故事。 这是某个人对我写的短篇小说的评价。 我用某个人期待的写法写出了他期待的故事但事实并不是这样。...
    净心先生阅读 126评论 0 0