likes
comments
collection
share

Activity启动过程简析

作者站长头像
站长
· 阅读数 18

本文主要内容

  • Activity启动流程
  • 进程启动过程
  • 总结

Android应用可被多种方式启动,包括启动服务、activity,接收广播,ContentProvider被查询也会启动应用。如果应用是persitant应用,系统则会自动地去启动它。

Activity启动过程简析

本文主要阐述activity的启动,最后是一些总结性的东西。

Activity启动流程

先来看一张流程图:

Activity启动过程简析

activity启动的流程非常非常的多,代码阅读比较困难,我们不一一读了,可以跟着这条线,细细推敲,我们只讲几个重点。

其实activity启动的逻辑主要是这几个部分:

  • 权限控制
  • activity启动模式导致的不同activity stack策略
  • 进程启动
  • IPC通信启动activity

权限控制以及启动模式相关内容,本文不深入探讨,进程启动我们下个小节再讲,这里主要阐述下IPC通信启动activity。

如果我们以桌面上启动音乐为例,桌面和音乐分别属于不同的进程,而ams也是跑在系统进程当中的,三个不同进程之间是如何通信的?

Activity启动过程简析

桌面调用ContextImpl的startActivity方法,最后将通过ActivityManagerNative.getDefault(),获取AMS的IPC代理,实现与AMS通信。而AMS最后要来启动音乐,则会收到音乐的ApplicationThread的实例,ApplicationThread其实是一个binder对象,AMS就是通过它才能与音乐进程进行通信,最终创建音乐进程,并启动activity。

进程启动

Android中所有apk的进程都是由zygote启动的,zygote中文名为受精卵,它调用linux接口fork,创建进程。

AMS与zygote采用socket进行进程间的通信,实现进程创建。

zygote创建进程的时候,某种程度上是复制,它会创建一个vm实例,其中会包含一些预加载的系统类以及资源,这样能加快或者方便apk调用。

Activity启动过程简析

原理图如上,zygote接收socket通信的指令并读取,然后fork一个VM实例出来,创建新进程并执行这个进程。

既然是socket通信,必然会有一个服务端,android中这个服务端是ZygoteInit,我们来看它的main方法:

public static void main(String argv[]) {
    try {
        // Start profiling the zygote initialization.
        SamplingProfilerIntegration.start();

        boolean startSystemServer = false;
        //注意,zygote这是服务端的名字,类似于java上socket中的端口号,接下来会用到
        String socketName = "zygote";
        String abiList = null;
        for (int i = 1; i < argv.length; i++) {
            if ("start-system-server".equals(argv[i])) {
                startSystemServer = true;
            } else if (argv[i].startsWith(ABI_LIST_ARG)) {
                abiList = argv[i].substring(ABI_LIST_ARG.length());
            } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
                socketName = argv[i].substring(SOCKET_NAME_ARG.length());
            } else {
                throw new RuntimeException("Unknown command line argument: " + argv[i]);
            }
        }

        if (abiList == null) {
            throw new RuntimeException("No ABI list supplied.");
        }
        //使用socket名字,来创建socket服务端
        registerZygoteSocket(socketName);
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
            SystemClock.uptimeMillis());
        preload();
        EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_END,
            SystemClock.uptimeMillis());

        // Finish profiling the zygote initialization.
        SamplingProfilerIntegration.writeZygoteSnapshot();

        // Do an initial gc to clean up after startup
        gcAndFinalize();

        // Disable tracing so that forked processes do not inherit stale tracing tags from
        // Zygote.
        Trace.setTracingEnabled(false);

        if (startSystemServer) {
            startSystemServer(abiList, socketName);
        }

        Log.i(TAG, "Accepting command socket connections");
        //runSelectLoop方法中是一个死循环,不停地接收指令并fock进程
        runSelectLoop(abiList);

        closeServerSocket();
    } catch (MethodAndArgsCaller caller) {
        caller.run();
    } catch (RuntimeException ex) {
        Log.e(TAG, "Zygote died with exception", ex);
        closeServerSocket();
        throw ex;
    }
}

由代码可知,和java类似,声明socket服务端的端口号并且采用死循环,读取客户端指令并执行。

AMS在startProcessLocked方法中调用Process.start方法,来启动进程,具体流程如下所示:

Activity启动过程简析

注意:Process类作为客户端,而ZygoteInit作为服务端,ZygoteInit中的runSelectLoop方法一直死循环,当接到Process创建进程指令时,就会去调用ZygoteConnection的runOnce方法,完成进程创建。

比较有意思的是:

entryPoint = "android.app.ActivityThread";
Process.start(entryPoint ....
public static final ProcessStartResult start(final String processClass,

可以看到Process启动进程的processClass为ActivityThread,而Java语言是在进程启动时执行main方法,所以当apk的进程创建后,第一个被执行的方法就是ActivityThread的main方法。

总结

  • activity的onCreate方法

activity在ActivityThread当中被启动后,由Instrumentation的newActivity方法完成实例创建:

java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
public Activity newActivity(ClassLoader cl, String className,
        Intent intent)
        throws InstantiationException, IllegalAccessException,
        ClassNotFoundException {
    return (Activity)cl.loadClass(className).newInstance();
}

因为activity类名未知,所以最后创建实例的必是反射创建,而且还要使用正确的ClassLoader。 cl由LoadApk类获取,查看其源码即知,这个ClassLoader是正确的,有点类似于动态加载中指定apk路径构建ClassLoader,它能正确加载到activity。

  • 设计思路

回想activity的创建流程,如果这个工作由我们来做,我们应该要怎么设计它?android为了更为简单易用,将复杂的IPC通信以及其它的都封装得很完美,用户只要声明activity即可,这实在是完美的作品。

其实我们学习过很多的设计模式,但事到临头总是用不出来,有时想想这些常见的流程、机制,都有很多值得我们学习的地方

转载自:https://juejin.cn/post/7225094324526989373
评论
请登录