1. 程式人生 > >20. Gradle編譯其他應用代碼流程(七) - 守護進程編譯

20. Gradle編譯其他應用代碼流程(七) - 守護進程編譯

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"





本文出自 “www.bogo.com” 博客,請務必保留此出處http://483181.blog.51cto.com/473181/1931190

20. Gradle編譯其他應用代碼流程(七) - 守護進程編譯