注意:学习本章知识需要安卓8 Zygote源码分析笔记这篇文章的知识作为铺垫。
前文回顾:
Android8 Zygote源码分析学习笔记(二)-CSDN博客文章浏览阅读575次,点赞16次,收藏15次。本文分析了Android系统中Zygote服务的核心流程,重点包括:1)Zygote通过init.zygote32.rc配置文件启动,由app_process程序运行;2)ZygoteInit类的main方法创建ZygoteServer并注册监听socket;3)预加载系统资源(类、库等);4)关键forkSystemServer方法创建系统服务进程的过程,涉及权限设置、资源限制配置等;5)runSelectLoop方法实现多路复用监听fork请求。源码分析揭示了Zygote作为"孵化器" https://blog.csdn.net/g_i_a_o_giao/article/details/150764611?spm=1011.2124.3001.6209Android8 Zygote源码分析学习笔记(一)-CSDN博客文章浏览阅读110次,点赞3次,收藏2次。本文分析了Android系统Zygote服务的启动流程。Zygote通过init.zygote32.rc配置文件启动,由app_process程序以root权限运行,参数中包含"--zygote"和"--start-system-server"标志。源码分析从app_main.cpp的main函数开始,解析参数后创建AppRuntime对象并调用其start方法,最终通过JNI调用ZygoteInit类的main方法。关键步骤包括参数解析、虚拟机启动、JNI方法注册, https://blog.csdn.net/g_i_a_o_giao/article/details/150613561?spm=1011.2124.3001.6209接之前文章的分析,当SystemServer的进程被fork出来以后,会调用handleSystemServerProcess方法来返回一个Runnable对象。

 try {
            /* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.debugFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }

        /* For child process */
        if (pid == 0) {
            if (hasSecondZygote(abiList)) {
                waitForSecondaryZygote(socketName);
            }

            zygoteServer.closeServerSocket();
            return handleSystemServerProcess(parsedArgs);
        }

那么来看看这个handleSystemServerProcess方法。在这个方法中,首先是获取系统服务类路径的环境变量,然后进行优化和性能分析(这里不是重点就不分析了),然后就是创建系统服务的类加载器。最后就是调用ZygoteInit的zygoteInit方法。

/**
 * Finish remaining work for the newly forked system server process.
 */
private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
    // 设置umask为0077,确保新创建的文件和目录默认只有所有者有权限(组和其他用户无权限)
    Os.umask(S_IRWXG | S_IRWXO);

    // 如果指定了进程的友好名称,设置进程名称
    if (parsedArgs.niceName != null) {
        Process.setArgV0(parsedArgs.niceName);
    }

    // 获取系统服务类路径环境变量(重要)
    final String systemServerClasspath = Os.getenv("SYSTEMSERVERCLASSPATH");
    if (systemServerClasspath != null) {
        // 对系统服务类路径中的Dex文件执行优化
        performSystemServerDexOpt(systemServerClasspath);
        
        // 仅在调试或工程版本中支持性能分析捕获,因为SELinux通常会阻止此操作
        boolean profileSystemServer = SystemProperties.getBoolean(
                "dalvik.vm.profilesystemserver", false);
        if (profileSystemServer && (Build.IS_USERDEBUG || Build.IS_ENG)) {
            try {
                // 创建性能分析文件目录
                File profileDir = Environment.getDataProfilesDePackageDirectory(
                        Process.SYSTEM_UID, "system_server");
                File profile = new File(profileDir, "primary.prof");
                profile.getParentFile().mkdirs();
                profile.createNewFile();
                
                // 将类路径拆分为数组
                String[] codePaths = systemServerClasspath.split(":");
                // 向运行时注册应用信息以启用性能分析
                VMRuntime.registerAppInfo(profile.getPath(), codePaths);
            } catch (Exception e) {
                Log.wtf(TAG, "Failed to set up system server profile", e);
            }
        }
    }

    // 如果指定了调用包装器(如使用wrap.sh脚本)
    if (parsedArgs.invokeWith != null) {
        String[] args = parsedArgs.remainingArgs;
        
        // 如果有系统服务类路径,需要复制现有参数并追加类路径
        if (systemServerClasspath != null) {
            String[] amendedArgs = new String[args.length + 2];
            amendedArgs[0] = "-cp";
            amendedArgs[1] = systemServerClasspath;
            System.arraycopy(args, 0, amendedArgs, 2, args.length);
            args = amendedArgs;
        }

        // 使用包装器执行应用
        WrapperInit.execApplication(parsedArgs.invokeWith,
                parsedArgs.niceName, parsedArgs.targetSdkVersion,
                VMRuntime.getCurrentInstructionSet(), null, args);

        // 正常情况下不会执行到此,因为execApplication会替换当前进程
        throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
    } else {
        // 没有使用调用包装器的正常路径
        ClassLoader cl = null;
        if (systemServerClasspath != null) {
            // 为系统服务创建路径类加载器
            cl = createPathClassLoader(systemServerClasspath, parsedArgs.targetSdkVersion);
            // 设置当前线程的上下文类加载器
            Thread.currentThread().setContextClassLoader(cl);
        }

        /*
         * 将剩余参数传递给SystemServer
         */
        return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
    }
}

打开模拟器后运行adb shell env命令可以看到SYSTEMSERVERCLASSPATH的变量值为:

SYSTEMSERVERCLASSPATH=/system/framework/services.jar:/system/framework/ethernet-service.jar:/system/framework/wifi-service.jar:/system/framework/com.android.location.provider.jar

那么再来看看zygoteInit方法。在这个方法中,主要的还是调用RuntimeInit.commonInit方法以及RuntimeInit的applicationInit方法。

/**
 * 当通过zygote进程启动时调用的主要函数。如果nativeFinishInit()中的本地代码与Zygote启动
 * 合理化,这个函数可以与main()统一。
 *
 * 当前识别的参数:
 * <ul>
 *   <li> <code> [--] &lt;start class name&gt;  &lt;args&gt;
 * </ul>
 *
 * @param targetSdkVersion 目标SDK版本
 * @param argv 参数字符串数组
 * @param classLoader 类加载器
 * @return 可运行对象,通常是调用主类的main方法
 */
public static final Runnable zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader) {
    // 调试模式下记录日志
    if (RuntimeInit.DEBUG) {
        Slog.d(RuntimeInit.TAG, "RuntimeInit: Starting application from zygote");
    }

    // 开始性能跟踪,标记为ActivityManager相关
    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ZygoteInit");
    
    // 重定向标准输出和标准错误流到Android日志系统
    RuntimeInit.redirectLogStreams();

    // 执行通用的运行时初始化
    RuntimeInit.commonInit();
    
    // 执行本地层的Zygote初始化(启动Binder线程池等)
    ZygoteInit.nativeZygoteInit();
    
    // 执行应用特定的初始化并返回Runnable对象
    return RuntimeInit.applicationInit(targetSdkVersion, argv, classLoader);
}

很明显我们又要去到RuntiimeInit这个类中去查看applicationInit方法。在这个方法中,还是进行了一系列的设置,然后解析参数,最后我们又看到了熟悉的findStaticMain方法,看这个名字就知道又要去找对应类的静态main方法了。

protected static Runnable applicationInit(int targetSdkVersion, String[] argv,
            ClassLoader classLoader) {
        // If the application calls System.exit(), terminate the process
        // immediately without running any shutdown hooks.  It is not possible to
        // shutdown an Android application gracefully.  Among other things, the
        // Android runtime shutdown hooks close the Binder driver, which can cause
        // leftover running threads to crash before the process actually exits.
        // 设置原生退出标志,使System.exit()立即终止进程而不运行关闭钩子
        // 这是因为Android应用无法优雅关闭,运行时关闭钩子会关闭Binder驱动,
        // 可能导致残留的运行线程在进程实际退出前崩溃
        nativeSetExitWithoutCleanup(true);

        // We want to be fairly aggressive about heap utilization, to avoid
        // holding on to a lot of memory that isn't needed.
        / 设置堆内存利用率为0.75,表示垃圾回收器会在堆内存使用达到75%时尝试回收内存
        // 这是一种相对激进的内存管理策略,避免持有大量不需要的内存
        VMRuntime.getRuntime().setTargetHeapUtilization(0.75f);
        // 设置应用程序的目标SDK版本,这会影响虚拟机的兼容性行为
        VMRuntime.getRuntime().setTargetSdkVersion(targetSdkVersion);
       
        // 解析命令行参数,提取启动类和启动参数
        final Arguments args = new Arguments(argv);

        // The end of of the RuntimeInit event (see #zygoteInit).
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

        // Remaining arguments are passed to the start class's static main
        // 查找并返回启动类的静态main方法包装器
        // 剩余的参数将传递给启动类的静态main方法
        return findStaticMain(args.startClass, args.startArgs, classLoader);
    }

然后继续分析findStaticMain方法。在这个类中主要是通过类加载器反射获取指定类的main函数以及它的修饰符,最后创建了一个MethodAndArgsCaller对象并且返回。然后我自己在这个方法中添加了一句Slog.d(RuntimeInit.TAG, "Finding static main for class: " + className);来看看加载了哪些类的静态方法,主要有ActivityThread和SystemServer等类。

/**
 * 调用类"className"上的静态"main(argv[])"方法。
 * 将各种失败异常转换为RuntimeException,假定这会导致VM实例退出。
 *
 * @param className 完全限定的类名
 * @param argv 传递给main()方法的参数数组
 * @param classLoader 用于加载{@className}的类加载器
 * @return 一个Runnable对象,当运行时将调用类的静态main方法
 */
private static Runnable findStaticMain(String className, String[] argv,
        ClassLoader classLoader) {
    Class<?> cl;
    // 打印一下看看加载了哪些类
    Slog.d(RuntimeInit.TAG, "Finding static main for class: " + className);
    try {
        // 使用提供的类加载器加载指定类
        // 第二个参数true表示在加载时进行初始化(执行静态代码块)
        cl = Class.forName(className, true, classLoader);
    } catch (ClassNotFoundException ex) {
        // 如果类不存在,抛出运行时异常
        throw new RuntimeException(
                "Missing class when invoking static main " + className,
                ex);
    }

    Method m;
    try {
        // 获取类的main方法,它应该有一个String[]类型的参数
        m = cl.getMethod("main", new Class[] { String[].class });
    } catch (NoSuchMethodException ex) {
        // 如果没有找到main方法,抛出运行时异常
        throw new RuntimeException(
                "Missing static main on " + className, ex);
    } catch (SecurityException ex) {
        // 如果没有访问方法的权限,抛出运行时异常
        throw new RuntimeException(
                "Problem getting static main on " + className, ex);
    }

    // 获取方法的修饰符(public、static等)
    int modifiers = m.getModifiers();
    
    // 检查方法是否是public和static的
    if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) {
        throw new RuntimeException(
                "Main method is not public and static on " + className);
    }

    /*
     * 这个throw会在ZygoteInit.main()中被捕获,该函数通过调用异常的run()方法来响应。
     * 这种安排清除了设置进程所需的所有堆栈帧。
     */
    return new MethodAndArgsCaller(m, argv);
}

08-26 23:08:05.145  1547  1547 D AndroidRuntime: Finding static main for class: com.android.server.SystemServer
08-26 23:08:08.669  1893  1893 D AndroidRuntime: Finding static main for class: android.app.ActivityThread
08-26 23:08:08.675  1904  1904 D AndroidRuntime: Finding static main for class: android.app.ActivityThread
08-26 23:08:08.727  1985  1985 D AndroidRuntime: Finding static main for class: android.webkit.WebViewLibraryLoader$RelroFileCreator
08-26 23:08:08.731  1993  1993 D AndroidRuntime: Finding static main for class: android.webkit.WebViewLibraryLoader$RelroFileCreator
08-26 23:08:08.993  2089  2089 D AndroidRuntime: Finding static main for class: android.app.ActivityThread
08-26 23:08:08.997  2102  2102 D AndroidRuntime: Finding static main for class: android.app.ActivityThread
08-26 23:07:53.255  2159  2159 D AndroidRuntime: Finding static main for class: android.app.ActivityThread
08-26 23:07:53.611  2196  2196 D AndroidRuntime: Finding static main for class: android.app.ActivityThread
08-26 23:07:53.795  2223  2223 D AndroidRuntime: Finding static main for class: 
..................省略..................

继续分析MethodAndArgsCaller这个内部类。在这个类继承自Runnable类,在它的run方法中会通过反射调用各个类的静态main方法。可以将这个类理解为一个跳板,将各个类的main函数封装到Runnable中。

/**
 * 辅助类,用于保存方法和参数并能够调用它们。
 * 这部分用作蹦床(trampoline)的一部分,以消除初始进程设置堆栈帧。
 */
static class MethodAndArgsCaller implements Runnable {
    /** 要调用的方法 */
    private final Method mMethod;

    /** 参数数组 */
    private final String[] mArgs;

    /**
     * 构造函数
     * @param method 要调用的方法(通常是main方法)
     * @param args 传递给方法的参数数组
     */
    public MethodAndArgsCaller(Method method, String[] args) {
        mMethod = method;
        mArgs = args;
    }

    /**
     * 执行方法调用
     * 当这个Runnable运行时,它会通过反射调用存储的方法
     */
    public void run() {
        try {
            // 调用静态方法(第一个参数为null),传递参数数组
            mMethod.invoke(null, new Object[] { mArgs });
        } catch (IllegalAccessException ex) {
            // 如果方法不可访问,抛出运行时异常
            throw new RuntimeException(ex);
        } catch (InvocationTargetException ex) {
            // 如果被调用的方法抛出异常,提取根本原因并适当处理
            Throwable cause = ex.getCause();
            if (cause instanceof RuntimeException) {
                // 如果是运行时异常,直接抛出
                throw (RuntimeException) cause;
            } else if (cause instanceof Error) {
                // 如果是错误,直接抛出
                throw (Error) cause;
            }
            // 其他类型的异常包装为运行时异常
            throw new RuntimeException(ex);
        }
    }
}

这个跳板会一步一步的被返回,从findStaticMain->applicationInit->zygoteInit->handleSystemServerProcess->forkSystemServer。

回顾之前ZygoteInit类中的main函数,在调用forkSystemServer之后返回的正是runnable对象,然后就调用了run方法,也就是说这个跳板被使用了,最终执行到了对应服务类中的静态main函数。

ZygoteInit中的main函数:
if (startSystemServer) {
                Runnable r = forkSystemServer(abiList, socketName, zygoteServer);

                // {@code r == null} in the parent (zygote) process, and {@code r != null} in the
                // child (system_server) process.
                if (r != null) {
                    // 重要
                    r.run();
                    return;
                }
            }

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐