Zygote接收到AMS消息到启动ActivityThread流程

系统启动过程

启动Zygote进程:
启动过程开始于Zygote进程,当启动一个应用时,Zygote进程会被复用以创建新的应用进程。

这里是ZygoteInit.main的主要作用,它是Zygote进程的入口:

public class ZygoteInit {
    public static void main(String argv[]) {
        // ... 省略的一些前期初始化代码

        // 启动系统服务进程
        if (startSystemServer) {
            startSystemServer(forkedProcesses);
        }

        // 进入Zygote的主循环
        Runnable caller;
        try {
            caller = zygoteServer.runSelectLoop();
        } catch (Throwable ex) {
          // ... 处理异常
        }

        // 运行子进程初始化代码
        if (caller != null) {
            caller.run();
        }
    }
}
1、Zygote连接处理:
Zygote进程在初始化后会进入一个循环,等待来自ActivityManagerService(AMS)的进程启动请求。这是在runSelectLoop中处理的。

ZygoteServer.runSelectLoop 在后台等待连接请求:

public class ZygoteServer {
    Runnable runSelectLoop() {
        while (true) {
            // 等待AMS连接
            ZygoteConnection connection = acceptCommandPeer();
            return connection.processOneCommand(); // 这里实际上是处理一个命令
        }
    }
}
2、处理启动命令:
在接收到启动请求后,ZygoteConnection.processOneCommand 方法负责处理实际启动参数。

public class ZygoteConnection {
    Runnable processOneCommand() {
        // 解析启动参数
        Arguments args = readArgumentList();

        // 调用Zygote来fork新进程
        Zygote.forkAndSpecialize(...);

        if (pid == 0) {
            // 子进程执行到这里
            return handleChildProc(args, descriptors, childPipeFd, newStderr);
        } else {
            // 父进程(Zygote进程)执行到这里
            ...
        }
    }
}
这 就是说,handleChildProc 方法在子进程中被调用,这里新启动的进程会完成初始化:

3. handleChildProc
handleChildProc 负责处理子进程的初始化。

public class ZygoteConnection {
    private Runnable handleChildProc(Arguments parsedArgs) {
        // 初始化子进程
        return RuntimeInit.wrapperInit(parsedArgs);
    }
}
4. RuntimeInit.wrapperInit
RuntimeInit.wrapperInit 是实际启动应用进程的方法。

public class RuntimeInit {
    public static Runnable wrapperInit(Arguments args) {
        return applicationInit(args);
    }
    private static Runnable applicationInit(Arguments args) {
        return invokeStaticMain(args.startClass, args.startArgs, null);
    }
    protected static Runnable invokeStaticMain(String className, String[] argv, ClassLoader classLoader) {
        // 反射调用main方法
        Class<?> cl;
        try {
            cl = Class.forName(className);
            Method m = cl.getMethod("main", new Class[] { String[].class });
            m.invoke(null, new Object[]{argv});
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        return null;
    }
}
5. ActivityThread.main
以上步骤最终会调用到ActivityThread.main方法,这是实际应用进程的入口。

public class ActivityThread {
    public static void main(String[] args) {
        // 主线程初始化
        Looper.prepareMainLooper();
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
        Looper.loop();
    }
}

总结

整个调用链从Zygote接收启动参数到涉及到的主要过程如下:
ZygoteInit.main: 启动进程,并进入等待循环。
ZygoteServer.runSelectLoop: 等待并处理启动请求。
ZygoteConnection.processOneCommand: 解析并fork新的进程。
RuntimeInit.wrapperInit: 完成子进程进一步初始化。
RuntimeInit.applicationInit: 通过反射调用指定类的main方法。
ActivityThread.main: 启动应用主线程。

接下来看看AMS是怎么传输Socket数据给Zygote的

在ActivityManagerService(AMS)中,有关启动应用进程并通过Socket请求发送给Zygote的部分,主要是通过startProcessLocked方法来实现。这个方法会调用Process.start方法,并通过Zygote发送启动请求。在启动参数中传递了android.app.ActivityThread。

具体的流程如下:

1. ActivityManagerService.startProcessLocked
ActivityManagerService的startProcessLocked方法负责启动新进程:

public class ActivityManagerService {
    private boolean startProcessLocked(ProcessRecord app, ...) {
        ...
        // 调用Process.start来启动进程
        Process.ProcessStartResult startResult = Process.start(
                "android.app.ActivityThread", // 这里指定类名
                app.processName, ...);
        ...
    }
}
2. Process.start
Process.start方法负责创建并启动一个新的应用进程:

public class Process {
    public static ProcessStartResult start(
            String processClass, // 这里是传入的 "android.app.ActivityThread"
            String niceName,
            ...
            ) {
        ...
        try {
            return startViaZygote(processClass, niceName, ...);
        } catch (RuntimeException e) {
            ...
        }
    }

    private static ProcessStartResult startViaZygote(
            String processClass,
            String niceName,
            ...
            ) {
        ...
        // 创建启动参数列表
        ArrayList<String> argsForZygote = new ArrayList<String>();

        // 传递启动组件类名
        argsForZygote.add("--runtime-args");
        argsForZygote.add("--setuid=" + uid);
        argsForZygote.add("--setgid=" + gid);
        argsForZygote.add("-classpath");
        argsForZygote.add("--nice-name=" + niceName);
        argsForZygote.add(processClass); // 传入的类名

        // 调用Zygote来启动进程
        ProcessStartResult result = ZygoteProcess.zygoteSendArgsAndGetResult(
                openZygoteSocketIfNeeded(abi), argsForZygote);
        ...
        return result;
    }
}
3. ZygoteProcess.zygoteSendArgsAndGetResult
这个方法通过Socket将启动参数发送给Zygote进程:

public class ZygoteProcess {
    public Process.ProcessStartResult zygoteSendArgsAndGetResult(
            ZygoteState zygoteState, ArrayList<String> args)
            throws ZygoteStartFailedEx {
        try {
            // 获取Zygote进程的Socket连接
            DataOutputStream zygoteWriter = zygoteState.mZygoteOutputWriter;

            // 发送启动参数
            for (String arg : args) {
                zygoteWriter.writeBytes(arg + "\n");
            }

            // 获取启动结果
            ProcessStartResult result = new ProcessStartResult();
            result.pid = zygoteState.mZygoteInputStream.readInt();
            ...
            return result;
        } catch (IOException ex) {
            throw new ZygoteStartFailedEx(ex);
        }
    }
}
传递给Zygote的参数
从上述代码可以看到,Process.start方法最终构建了一个参数列表argsForZygote,其中包括要启动的类名android.app.ActivityThread,并通过ZygoteProcess.zygoteSendArgsAndGetResult发送到Zygote进程。

4. 接受请求并启动进程的Zygote代码
回到之前的细节:

ZygoteServer.runSelectLoop
Zygote进程在启动后,会进入一个循环等待AMS的请求:

public class ZygoteServer {
    Runnable runSelectLoop() {
        while (true) {
            ZygoteConnection connection = acceptCommandPeer();
            return connection.processOneCommand();
        }
    }
}
ZygoteConnection.processOneCommand
在接受到启动请求后,Zygote进程通过processOneCommand方法处理请求:

public class ZygoteConnection {
    Runnable processOneCommand() {
        // 读取并解析参数
        Arguments args = readArgumentList();
        // Fork新的进程
        int pid = Zygote.forkAndSpecialize(args);
        if (pid == 0) {
            // 子进程处理
            return handleChildProc(args);
        } else {
            // 父进程处理
            ...
        }
    }
}

总结
总结来说,关于传递类名android.app.ActivityThread的调用链如下:

ActivityManagerService.startProcessLocked: 调用Process.start方法,传入类名android.app.ActivityThread。
Process.start: 调用startViaZygote,构建参数列表并调用ZygoteProcess.zygoteSendArgsAndGetResult。
ZygoteProcess.zygoteSendArgsAndGetResult: 通过Socket将启动参数发给Zygote进程。
ZygoteServer.runSelectLoop: 接受并处理启动请求。
ZygoteConnection.processOneCommand: 解析启动参数并fork新进程。
handleChildProc: 初始化新进程,最终调用RuntimeInit.zygoteInit,并反射调用ActivityThread.main。

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

推荐阅读更多精彩内容