20. Gradle编译其他应用代码流程(七) - 守护进程编译

上一篇博客

18. Gradle编译其他应用代码流程(六) - 执行Task过程

一. 守护进程的作用

守护进程就是一个用来构建的其他进程。

从前几篇文章我们知道gradle编译的时候会加载各种所需要的Jar,加载这些Jar是需要时间的。

如果我们之前有守护进程编译过其他程序,而这个进程没有被kill掉,那么是可以重用这个守护进程的。

二. 选择守护进程编译

选择守护进程编译的策略是

  1. 如果守护进程存在,那么就使用守护进程编译。
  2. 否则,如果可以在当前进程编译,那么就在当前进程编译。
  3. 否则,启动新的守护进程来编译。

代码如下:

class BuildActionsFactory implements CommandLineAction {
    
    public Runnable createAction(CommandLineParser parser, ParsedCommandLine commandLine) {
        ...
        
        if (parameters.getDaemonParameters().isEnabled()) {
            return runBuildWithDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
        }
        if (canUseCurrentProcess(parameters.getDaemonParameters())) {
            return runBuildInProcess(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
        }

        return runBuildInSingleUseDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);
    }
}

三. 启动守护进程的入口


public class DefaultDaemonStarter implements DaemonStarter {
    ....

    public DaemonStartupInfo startDaemon() {
        String daemonUid = UUID.randomUUID().toString();

        GradleInstallation gradleInstallation = CurrentGradleInstallation.get();
        ModuleRegistry registry = new DefaultModuleRegistry(gradleInstallation);
        ClassPath classpath;
        List<File> searchClassPath;
        if (gradleInstallation == null) {
            // When not running from a Gradle distro, need runtime impl for launcher plus the search path to look for other modules
            classpath = new DefaultClassPath();
            for (Module module : registry.getModule("gradle-launcher").getAllRequiredModules()) {
                classpath = classpath.plus(module.getClasspath());
            }
            searchClassPath = registry.getAdditionalClassPath().getAsFiles();
        } else {
            // When running from a Gradle distro, only need launcher jar. The daemon can find everything from there.
            classpath = registry.getModule("gradle-launcher").getImplementationClasspath();
            searchClassPath = Collections.emptyList();
        }
        if (classpath.isEmpty()) {
            throw new IllegalStateException("Unable to construct a bootstrap classpath when starting the daemon");
        }

        versionValidator.validate(daemonParameters);

        List<String> daemonArgs = new ArrayList<String>();
        daemonArgs.add(daemonParameters.getEffectiveJvm().getJavaExecutable().getAbsolutePath());

        List<String> daemonOpts = daemonParameters.getEffectiveJvmArgs();
        daemonArgs.addAll(daemonOpts);
        daemonArgs.add("-cp");
        daemonArgs.add(CollectionUtils.join(File.pathSeparator, classpath.getAsFiles()));

        if (Boolean.getBoolean("org.gradle.daemon.debug")) {
            daemonArgs.add("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005");
        }
        
        daemonArgs.add(GradleDaemon.class.getName());
        // Version isn‘t used, except by a human looking at the output of jps.
        daemonArgs.add(GradleVersion.current().getVersion());

        // Serialize configuration to daemon via the process‘ stdin
        ByteArrayOutputStream serializedConfig = new ByteArrayOutputStream();
        FlushableEncoder encoder = new KryoBackedEncoder(new EncodedStream.EncodedOutput(serializedConfig));
        try {
            encoder.writeString(daemonParameters.getGradleUserHomeDir().getAbsolutePath());
            encoder.writeString(daemonDir.getBaseDir().getAbsolutePath());
            encoder.writeSmallInt(daemonParameters.getIdleTimeout());
            encoder.writeSmallInt(daemonParameters.getPeriodicCheckInterval());
            encoder.writeString(daemonUid);
            encoder.writeSmallInt(daemonOpts.size());
            for (String daemonOpt : daemonOpts) {
                encoder.writeString(daemonOpt);
            }
            encoder.writeSmallInt(searchClassPath.size());
            for (File file : searchClassPath) {
                encoder.writeString(file.getAbsolutePath());
            }
            encoder.flush();
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
        ByteArrayInputStream stdInput = new ByteArrayInputStream(serializedConfig.toByteArray());

        return startProcess(daemonArgs, daemonDir.getVersionedDir(), stdInput);
    }

四. 守护进程执行入口

public class GradleDaemon {
    public static void main(String[] args) {
        new ProcessBootstrap().run("org.gradle.launcher.daemon.bootstrap.DaemonMain", args);
    }
}

public class DaemonMain extends EntryPoint {

    private static final Logger LOGGER = Logging.getLogger(DaemonMain.class);

    private PrintStream originalOut;
    private PrintStream originalErr;

    @Override
    protected void doAction(String[] args, ExecutionListener listener) {
    	...

        KryoBackedDecoder decoder = new KryoBackedDecoder(new EncodedStream.EncodedInput(System.in));
        try {
            gradleHomeDir = new File(decoder.readString());
            daemonBaseDir = new File(decoder.readString());
            idleTimeoutMs = decoder.readSmallInt();
            periodicCheckIntervalMs = decoder.readSmallInt();
            daemonUid = decoder.readString();
            int argCount = decoder.readSmallInt();
            startupOpts = new ArrayList<String>(argCount);
            for (int i = 0; i < argCount; i++) {
                startupOpts.add(decoder.readString());
            }
            int additionalClassPathLength = decoder.readSmallInt();
            additionalClassPath = new ArrayList<File>(additionalClassPathLength);
            for (int i = 0; i < additionalClassPathLength; i++) {
                additionalClassPath.add(new File(decoder.readString()));
            }
        } catch (EOFException e) {
        	System.out.println("DaemonMain doAction 4");
            throw new UncheckedIOException(e);
        }

        NativeServices.initialize(gradleHomeDir);
        
        DaemonServerConfiguration parameters = new DefaultDaemonServerConfiguration(daemonUid, daemonBaseDir, idleTimeoutMs, periodicCheckIntervalMs, startupOpts);
        
        LoggingServiceRegistry loggingRegistry = LoggingServiceRegistry.newCommandLineProcessLogging();
       
        LoggingManagerInternal loggingManager = loggingRegistry.newInstance(LoggingManagerInternal.class);
        
        TrueTimeProvider timeProvider = new TrueTimeProvider();
        
        DaemonServices daemonServices = new DaemonServices(parameters, loggingRegistry, loggingManager, new DefaultClassPath(additionalClassPath), timeProvider.getCurrentTime());
        
        File daemonLog = daemonServices.getDaemonLogFile();
        
        // Any logging prior to this point will not end up in the daemon log file.
        initialiseLogging(loggingManager, daemonLog);

        LOGGER.debug("Assuming the daemon was started with following jvm opts: {}", startupOpts);
        
        Daemon daemon = daemonServices.get(Daemon.class);
        daemon.start();

        try {
            DaemonContext daemonContext = daemonServices.get(DaemonContext.class);
            Long pid = daemonContext.getPid();
            daemonStarted(pid, daemon.getUid(), daemon.getAddress(), daemonLog);
            DaemonExpirationStrategy expirationStrategy = daemonServices.get(MasterExpirationStrategy.class);
            daemon.stopOnExpiration(expirationStrategy, parameters.getPeriodicCheckIntervalMs());
        } finally {
            daemon.stop();
        }
    }
}

五. 守护进程的日志

守护进程的日志没有打印在控制台,而是打印在文件中,通过下面这行代码,进行了日志输出流转向。

// Any logging prior to this point will not end up in the daemon log file.
initialiseLogging(loggingManager, daemonLog);

日志保存的位置在 GRADLE_USER_HOME/daemon/版本号/daemon-进程号.out.log

如果没有配置GRADLE_USER_HOME,那就在根目录。windows的话在‘c:\Users\rongwei.huang\.gradle\‘

我自己的日志目录是:"d:\gradle_jar_cache\daemon\3.1-snapshot-1\daemon-10972.out.log"

时间: 2024-10-12 08:06:14

20. Gradle编译其他应用代码流程(七) - 守护进程编译的相关文章

17. Gradle编译其他应用代码流程(五) - 设置Task过程

接上一篇 15. Gradle编译其他应用代码流程(四) - Configure过程 继续分析 一. task选择 到了这个阶段,gradle开始计算task入口是哪个? 选择的逻辑是这样: 如果用户收入了task,比如这样的指令'gradle pmd',那么就执行pmd这个task 如果用户没有输入task,比如直接输入'gradle',那么看有没有默认的task 如果没有默认的task,那就执行help这个task.大家可以试下直接输入gradle,看看输出什么内容. 接下来看源代码. 文件

rsync服务配置流程-守护进程

rsync服务配置流程rsync守护进程服务部署流程: #第一步:检查软件服务是否安装[[email protected] ~]# rpm -qa|grep rsyncrsync-3.0.6-12.el6.x86_64如果rsync软件不存在yum install -y rsync #第二步:编写rsync的配置文件/etc/rsyncd.conf*****rsyncd.conf是rsync服务默认配置文件,但是默认不存在vim /etc/rsyncd.conf#rsync_config #cr

u-boot移植(三)---修改前工作:代码流程分析3---代码重定位

一.重定位 1.以前版本的重定位 2.新版本 我们的程序不只涉及一个变量和函数,我们若想访问程序里面的地址,则必须使用SDRAM处的新地址,即我们的程序里面的变量和函数必须修改地址.我们要修改地址,则必须知道程序的地址,就需要在链接的时候加上PIE选项: 加上PIE选项后,链接时候的地址就会生成,然后存储在段里面,如下段(u-boot.lds): 然后我们根据这些地址的信息来修改代码,程序就可以复制到SDRAM的任何地方去. 二.代码流程 start.S中执行到了 bl _main,跳转到_ma

Gradle中的buildScript代码块

在编写Gradle脚本的时候,在build.gradle文件中经常看到这样的代码: build.gradle 1 2 3 4 5 6 7 8 9 buildScript { repositories { mavenCentral() } } repositories { mavenCentral() } 这样子很容易让人奇怪,为什么repositories要声明两次哪?buildscript代码块中的声明与下半部分声明有什么不同? 其实答案非常简单.buildscript中的声明是gradle脚

Ant编译打包Android工程流程

一.Ant编译打包android工程步骤 二.Ant apk签名 1.keystore签名    定义自己的签名文件 生成keystore文件:keytool -genkey -alias android.keystore -keyalg RSA - validity 20000 -keystore android.keystore 对应的java命令:jarsigner -verbose -keystore android.keystore -signedjar android_signed.

u-boot移植(三)---修改前工作:代码流程分析2

一.vectors.S 1.1 代码地址 vectors.S (arch\arm\lib) 1.2 流程跳转 跳转符号 B 为 start.S 中的 reset 执行代码,暂且先不看,先看看 vector.S 中的执行. 1.3 代码分析 ldr{条件} 目的寄存器 <存储器地址> 1 _start: 2 3 #ifdef CONFIG_SYS_DV_NOR_BOOT_CFG 4 .word CONFIG_SYS_DV_NOR_BOOT_CFG 5 #endif 6 /* LDR{条件} 目的

[转] Gradle中的buildScript代码块

PS: 在build script中的task apply plugin: 'spring-boot' 需要 classpath("org.springframework.boot:spring-boot-gradle-plugin:1.2.3.RELEASE") apply plugin: 'com.moowork.gulp' 需要classpath 'com.moowork.gradle:gradle-gulp-plugin:0.10' 在编写Gradle脚本的时候,在build.

nova boot代码流程分析(五):VM启动从neutron-dhcp-agent获取IP与MAC

1.   network和subnet创建代码流程 [[email protected] ~(keystone_user1)]# neutron net-create demo-net [[email protected] ~(keystone_user1)]# neutron subnet-create  demo-net 1.1.1.0/24 --name demo-subnet --gateway 1.1.1.1 --enable_dhcp true 这里,我们主要分析上面两个命令的代码流

Keil-MDK编译完成后代码大小

Code 代表执行的代码,程序中所有的函数都位于此处. RO-data 代表只读数据,程序中所定义的全局常量数据和字符串都位于此处. RW-data 代表已初始化的读写数据,程序中定义并且初始化的全局变量和静态变量位于此处. ZI-data 代表未初始化的读写数据,程序中定义了但没有初始化的全局变量和静态变量位于此处. KEIL RVMDK编译后的信息 Program Size: Code=86496 RO-data=9064 RW-data=1452 ZI-data=16116 这些参数的单位