美文网首页App启动流程
App启动流程:启动App进程

App启动流程:启动App进程

作者: sjandroid | 来源:发表于2019-04-17 16:58 被阅读16次

    目录

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

    概述

    -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连接请求。

    相关文章

      网友评论

        本文标题:App启动流程:启动App进程

        本文链接:https://www.haomeiwen.com/subject/fcgnwqtx.html