美文网首页
源码分析->应用进程启动过程

源码分析->应用进程启动过程

作者: 杨0612 | 来源:发表于2020-06-09 14:56 被阅读0次

    分析从fork进程到Application onCreate执行的过程。

    源码分析基于Android 23

    1.大体过程

    1.1 在Launch点击按钮启动A应用, Launch应用与AMS之间是binder通信;
    1.2 AMS向Zygote进程请求创建A应用进程,AMS与Zygote之间是Socket通信;
    1.3 Zygote通过fork创建A应用进程,并调用ActivityThread.main方法;
    1.4 ActivityThread.main()中创建ApplicationThread并注册到AMS,A应用与AMS之间是binder通信;
    1.5 AMS请求A应用执行Application onCreate方法,AMS与A应用之间是binder通信。

    大致流程.png
    2.源码分析
    我们知道,在Launch点击按键启动A应用,将触发Activity.startActivity,中间经过很多调用,我们关注最终会调到ActivityStackSupervisor.startSpecificActivityLocked

    该方法是启动进程的入口,主要工作:
    (1)getProcessRecordLocked,通过进程名获取ProcessRecord;
    (2)如果进程启动,则if (app != null && app.thread != null)条件成立,realStartActivityLocked通过跨进程调用启动A应用;
    (3)如果进程没有启动,则mService.startProcessLocked,请求AMS启动进程,我们跟进mService.startProcessLocked方法;

        void startSpecificActivityLocked(ActivityRecord r,
                boolean andResume, boolean checkConfig) {
            // Is this activity's application already running?
            ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                    r.info.applicationInfo.uid, true);
    
            r.task.stack.setLaunchTime(r);
    
            if (app != null && app.thread != null) {//进程启动了
                try {
                    ......
                    realStartActivityLocked(r, app, andResume, checkConfig);
                    return;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting activity "
                            + r.intent.getComponent().flattenToShortString(), e);
                }
            }
            //进程没有启动
            mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,
                    "activity", r.intent.getComponent(), false, false, true);
        }
    
    上述的startProcessLocked最终会调到
    ActivityManagerService.startProcessLocked

    主要工作:
    (1) entryPoint赋值为android.app.ActivityThread,这里就相当熟悉了,后面会通过反射来调用它的main方法;
    (2) 调用Process.start来创建进程,返回结果为startResult ,我们跟进去这个方法看看;

    private final void startProcessLocked(ProcessRecord app, String hostingType,
                String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {
               ......
                if (entryPoint == null) entryPoint = "android.app.ActivityThread";
                 ......
                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);
                 ......
        }
    
    Process.start->Process.startViaZygote

    主要工作:
    (1)配置虚拟机的参数,包括ActivityThread的全类名;
    (2)openZygoteSocketIfNeeded会调用ZygoteState.connect与Zygote进程建立Socket连接;
    (3)zygoteSendArgsAndGetResult,socket连接成功,则发送数据。

     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<String> argsForZygote = new ArrayList<String>();
    
                // --runtime-args, --setuid=, --setgid=,
                // and --setgroups= must go first
                argsForZygote.add("--runtime-args");
                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_JIT) != 0) {
                    argsForZygote.add("--enable-jit");
                }
                if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
                    argsForZygote.add("--generate-debug-info");
                }
                if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
                    argsForZygote.add("--enable-assert");
                }
                if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
                    argsForZygote.add("--mount-external-default");
                } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
                    argsForZygote.add("--mount-external-read");
                } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
                    argsForZygote.add("--mount-external-write");
                }
                argsForZygote.add("--target-sdk-version=" + targetSdkVersion);
                 ......
                argsForZygote.add(processClass);//ActivityThread的全类名
               ......
                zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi),             argsForZygote);
               ......
                return ;
    
            }
        }
    
    Socket的服务端在ZygoteInit类中,

    (1)runSelectLoop,接收请求由ZygoteConnection.runOnce来处理,我们跟进去看看;
    (2)巧妙地利用异常来反射调用ActivityThread.main,MethodAndArgsCaller 异常是封装了反射调用ActivityThread.main。

    public static void main(String argv[]) {
                ......
                runSelectLoop(abiList); 
                ......
            } catch (MethodAndArgsCaller caller) {
                caller.run();  //巧妙的利用异常处理,来反射执行ActivityThread.main()
            } 
            ......
        }
    
    ZygoteConnection.runOnce->ZygoteConnection.forkAndSpecialize

    主要工作:
    (1)Zygote.forkAndSpecialize,内部通过native方法fork进程;
    (2)handleChildProc,内部调用RuntimeInit.zygoteInit,我们跟进去看看;

     boolean runOnce() throws ZygoteInit.MethodAndArgsCaller {
                ......
                pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
                        parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
                        parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet,
                        parsedArgs.appDataDir);
                ......
                handleChildProc(parsedArgs, descriptors, childPipeFd, newStderr);
                ......
      }
    
    RuntimeInit.zygoteInit

    主要工作:
    (1)nativeZygoteInit,启动binder机制:打开binder驱动,映射内存,注册binder线程,进入binder looper;
    (2)applicationInit,内部调用RuntimeInit.invokeStaticMain;

       public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
                throws ZygoteInit.MethodAndArgsCaller {
            ......
            commonInit();
            nativeZygoteInit();
            applicationInit(targetSdkVersion, argv, classLoader);
        }
    
    RuntimeInit.invokeStaticMain

    主要的工作:
    (1)反射方法的校验,类是否存在、方法是否存在、方法是否静态以及public;
    (2)最后抛出一个异常ZygoteInit.MethodAndArgsCaller,回到上述的ZygoteInit.main。

    private static void invokeStaticMain(String className, String[] argv, ClassLoader classLoader)
                throws ZygoteInit.MethodAndArgsCaller {
            Class<?> cl;
    
            try {
                cl = Class.forName(className, true, classLoader);
            } catch (ClassNotFoundException ex) {
                throw new RuntimeException(
                        "Missing class when invoking static main " + className,
                        ex);
            }
    
            Method m;
            try {
                m = cl.getMethod("main", new Class[] { String[].class });
            } catch (NoSuchMethodException ex) {
                throw new RuntimeException(
                        "Missing static main on " + className, ex);
            } catch (SecurityException ex) {
                throw new RuntimeException(
                        "Problem getting static main on " + className, ex);
            }
    
            int modifiers = m.getModifiers();
            if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
                throw new RuntimeException(
                        "Main method is not public and static on " + className);
            }
            throw new ZygoteInit.MethodAndArgsCaller(m, argv);
        }
    
    ZygoteInit.MethodAndArgsCaller.run

    主要工作:
    通过反射来调用ActivityThread.main;

    public void run() {
          ......
         mMethod.invoke(null, new Object[] { mArgs });
          ......
    }
    

    至此,启动工作转到了ActivityThread.main。

    ActivityThread.main()

    主要工作:
    (1) Looper.prepareMainLooper(),初始化主线程消息队列;
    (2)构造ActivityThread,调用attach方法,其中包括把ApplicationThread注册到AMS;
    (3)Looper.loop(),启动消息队列;

    public static void main(String[] args) {
            ......
            Looper.prepareMainLooper();
            ActivityThread thread = new ActivityThread();
            thread.attach(false);
            ......
            Looper.loop();
            ......
        }
    }
    
    ActivityThread.attach()

    主要工作:
    mgr.attachApplication(mAppThread),告知AMS,App启动完成。mAppThread是一个Binder对象,是AMS与App通信的入口;

    private void attach(boolean system) {
                ......
                final IActivityManager mgr = ActivityManagerNative.getDefault();
                try {
                    mgr.attachApplication(mAppThread);
                } catch (RemoteException ex) {
                    // Ignore
                }
                ......
        }
    
    ActivityManagerService.attachApplication->ActivityManagerService.attachApplicationLocked

    主要工作:
    跨进程调用 thread.bindApplication,thread是ApplicationThread类型;

    private final boolean attachApplicationLocked(IApplicationThread thread,
                int pid) {
                ......
                thread.bindApplication(processName, appInfo, providers, app.instrumentationClass,
                        profilerInfo, app.instrumentationArguments, app.instrumentationWatcher,
                        app.instrumentationUiAutomationConnection, testMode, enableOpenGlTrace,
                        isRestrictedBackupMode || !normalMode, app.persistent,
                        new Configuration(mConfiguration), app.compat,
                        getCommonServicesLocked(app.isolated),
                        mCoreSettingsObserver.getCoreSettingsLocked());
                ......
                if (mStackSupervisor.attachApplicationLocked(app)) {
                        didSomething = true;
                    }
                ......
        }
    
    ApplicationThread.bindApplication

    主要工作:
    sendMessage(H.BIND_APPLICATION, data),将任务转到主线程,会调到handleBindApplication方法。

            public final void bindApplication(String processName, ApplicationInfo appInfo,
                    List<ProviderInfo> providers, ComponentName instrumentationName,
                    ProfilerInfo profilerInfo, Bundle instrumentationArgs,
                    IInstrumentationWatcher instrumentationWatcher,
                    IUiAutomationConnection instrumentationUiConnection, int debugMode,
                    boolean enableOpenGlTrace, boolean isRestrictedBackupMode, boolean persistent,
                    Configuration config, CompatibilityInfo compatInfo, Map<String, IBinder> services,
                    Bundle coreSettings) {
                ......
                AppBindData data = new AppBindData();
                ......
                sendMessage(H.BIND_APPLICATION, data);
            }
    
    ActivityThread.handleBindApplication

    主要工作:
    (1)cl.loadClass(data.instrumentationName.getClassName()).newInstance(),通过反射实例化Instrumentation,这是进程单例;
    (2)data.info是LoadeApk类型,对应着一个apk文件,通过makeApplication来构建Application实例,并且会创建ContextImpl通过attachBaseContext赋值给mBase;
    (3)callApplicationOnCreate,通过mInstrumentation来调用Application onCreate方法。

     private void handleBindApplication(AppBindData data) {
                ......
            if (data.appInfo.targetSdkVersion <= android.os.Build.VERSION_CODES.HONEYCOMB_MR1) {
                AsyncTask.setDefaultExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
            }//这段代码比较有意思,如果版本是3.1,AsyncTask使用多线程的线程池,包括3.1,否则使用单线程的线程池
                ......
                    java.lang.ClassLoader cl = instrContext.getClassLoader();
                    mInstrumentation = (Instrumentation)
                        cl.loadClass(data.instrumentationName.getClassName()).newInstance();
                ......
                Application app = data.info.makeApplication(data.restrictedBackupMode, null);
                mInitialApplication = app;
                ......
                mInstrumentation.callApplicationOnCreate(app);
    }
    

    至此,B应用的Application onCreate方法被调用。

    进程启动流程1.png
    进程启动流程2.png

    3.总结

    (1)ActivityStackSupervisor.startSpecificActivityLocked是fork应用进程的入口,如果ProcessRecord以及ApplicationThread都为空则需要fork进程;
    (2)Process.start与Zygote进行Socket连接,请求fork进程;
    (3)Zygote接收到请求,调用ZygoteConnection.runOnce方法处理for请求;
    (4)进程启动以后,把反射调用ActivityThread.main方法封装一个MethodAndArgsCaller异常对象抛出,ZygoteInit捕获异常并执行;
    (5)ActivityThread.main启动主线程Looper、构建ActivityThread、进入Looper循环;
    (6)ActivityThread.attch向AMS注册ApplicationThread;
    (7)AMS跨进程调用ApplicationThread.bindApplication;
    (8)ApplicationThread发消息到主线程,ActivityThread创建Application对象,给成员变量mBase赋值,最后调用其onCreate方法。

    常见面试题:
    1.谈谈你对Application的理解

    (1)作用
    Application生命周期很长,注意持有短生命对象,导致内存泄漏;
    可以在onCreate方法中做一些初始化的工作,但要考虑进程启动速度;
    提供全局的上下文,不用担心内存泄漏问题;
    多进程应用,就有多个Application实例;
    (2)继承关系
    继承ContextWrapper,最终是继承Context,有一个mBase全局变量。
    (3)调用顺序
    构造函数、attachBaseContext、onCreate。

    2.进程启动完成的标志

    ProcessRecord、ApplicationThread不为空,并且已经向ams注册了ApplicationThread;
    、,

    3.应用binder机制是什么时候启动的

    RuntimeInit.zygoteInit会调用nativeZygoteInit,启动binder机制:打开binder驱动,映射内存,注册binder线程,进入binder looper;

    4.为什么采用fork的方式
    为了资源复用和加快启动速度,因为Zygote已经preLoad过一些常用的资源(常用类、常用库、常用资源),应用进程无需再加载。

    以上分析有不对的地方,请指出,互相学习,谢谢哦!

    相关文章

      网友评论

          本文标题:源码分析->应用进程启动过程

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