上一篇博客
<a href="http://483181.blog.51cto.com/473181/1930658" target="_blank">18. Gradle编译其他应用代码流程(六) - 执行Task过程</a>
一. 守护进程的作用
守护进程就是一个用来构建的其他进程。
从前几篇文章我们知道gradle编译的时候会加载各种所需要的Jar,加载这些Jar是需要时间的。
如果我们之前有守护进程编译过其他程序,而这个进程没有被kill掉,那么是可以重用这个守护进程的。
二. 选择守护进程编译
选择守护进程编译的策略是
如果守护进程存在,那么就使用守护进程编译。
否则,如果可以在当前进程编译,那么就在当前进程编译。
否则,启动新的守护进程来编译。
代码如下:
<code>class</code> <code>BuildActionsFactory </code><code>implements</code> <code>CommandLineAction {</code>
<code> </code>
<code> </code><code>public</code> <code>Runnable createAction(CommandLineParser parser, ParsedCommandLine commandLine) {</code>
<code> </code><code>...</code>
<code> </code>
<code> </code><code>if</code> <code>(parameters.getDaemonParameters().isEnabled()) {</code>
<code> </code><code>return</code> <code>runBuildWithDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);</code>
<code> </code><code>}</code>
<code> </code><code>if</code> <code>(canUseCurrentProcess(parameters.getDaemonParameters())) {</code>
<code> </code><code>return</code> <code>runBuildInProcess(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);</code>
<code> </code><code>return</code> <code>runBuildInSingleUseDaemon(parameters.getStartParameter(), parameters.getDaemonParameters(), loggingServices);</code>
<code> </code><code>}</code>
<code>}</code>
三. 启动守护进程的入口
<code>public</code> <code>class</code> <code>DefaultDaemonStarter </code><code>implements</code> <code>DaemonStarter {</code>
<code> </code><code>....</code>
<code> </code><code>public</code> <code>DaemonStartupInfo startDaemon() {</code>
<code> </code><code>String daemonUid = UUID.randomUUID().toString();</code>
<code> </code><code>GradleInstallation gradleInstallation = CurrentGradleInstallation.get();</code>
<code> </code><code>ModuleRegistry registry = </code><code>new</code> <code>DefaultModuleRegistry(gradleInstallation);</code>
<code> </code><code>ClassPath classpath;</code>
<code> </code><code>List<File> searchClassPath;</code>
<code> </code><code>if</code> <code>(gradleInstallation == </code><code>null</code><code>) {</code>
<code> </code><code>// When not running from a Gradle distro, need runtime impl for launcher plus the search path to look for other modules</code>
<code> </code><code>classpath = </code><code>new</code> <code>DefaultClassPath();</code>
<code> </code><code>for</code> <code>(Module module : registry.getModule(</code><code>"gradle-launcher"</code><code>).getAllRequiredModules()) {</code>
<code> </code><code>classpath = classpath.plus(module.getClasspath());</code>
<code> </code><code>}</code>
<code> </code><code>searchClassPath = registry.getAdditionalClassPath().getAsFiles();</code>
<code> </code><code>} </code><code>else</code> <code>{</code>
<code> </code><code>// When running from a Gradle distro, only need launcher jar. The daemon can find everything from there.</code>
<code> </code><code>classpath = registry.getModule(</code><code>"gradle-launcher"</code><code>).getImplementationClasspath();</code>
<code> </code><code>searchClassPath = Collections.emptyList();</code>
<code> </code><code>if</code> <code>(classpath.isEmpty()) {</code>
<code> </code><code>throw</code> <code>new</code> <code>IllegalStateException(</code><code>"Unable to construct a bootstrap classpath when starting the daemon"</code><code>);</code>
<code> </code><code>versionValidator.validate(daemonParameters);</code>
<code> </code><code>List<String> daemonArgs = </code><code>new</code> <code>ArrayList<String>();</code>
<code> </code><code>daemonArgs.add(daemonParameters.getEffectiveJvm().getJavaExecutable().getAbsolutePath());</code>
<code> </code><code>List<String> daemonOpts = daemonParameters.getEffectiveJvmArgs();</code>
<code> </code><code>daemonArgs.addAll(daemonOpts);</code>
<code> </code><code>daemonArgs.add(</code><code>"-cp"</code><code>);</code>
<code> </code><code>daemonArgs.add(CollectionUtils.join(File.pathSeparator, classpath.getAsFiles()));</code>
<code> </code><code>if</code> <code>(Boolean.getBoolean(</code><code>"org.gradle.daemon.debug"</code><code>)) {</code>
<code> </code><code>daemonArgs.add(</code><code>"-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005"</code><code>);</code>
<code> </code><code>daemonArgs.add(GradleDaemon.</code><code>class</code><code>.getName());</code>
<code> </code><code>// Version isn't used, except by a human looking at the output of jps.</code>
<code> </code><code>daemonArgs.add(GradleVersion.current().getVersion());</code>
<code> </code><code>// Serialize configuration to daemon via the process' stdin</code>
<code> </code><code>ByteArrayOutputStream serializedConfig = </code><code>new</code> <code>ByteArrayOutputStream();</code>
<code> </code><code>FlushableEncoder encoder = </code><code>new</code> <code>KryoBackedEncoder(</code><code>new</code> <code>EncodedStream.EncodedOutput(serializedConfig));</code>
<code> </code><code>try</code> <code>{</code>
<code> </code><code>encoder.writeString(daemonParameters.getGradleUserHomeDir().getAbsolutePath());</code>
<code> </code><code>encoder.writeString(daemonDir.getBaseDir().getAbsolutePath());</code>
<code> </code><code>encoder.writeSmallInt(daemonParameters.getIdleTimeout());</code>
<code> </code><code>encoder.writeSmallInt(daemonParameters.getPeriodicCheckInterval());</code>
<code> </code><code>encoder.writeString(daemonUid);</code>
<code> </code><code>encoder.writeSmallInt(daemonOpts.size());</code>
<code> </code><code>for</code> <code>(String daemonOpt : daemonOpts) {</code>
<code> </code><code>encoder.writeString(daemonOpt);</code>
<code> </code><code>encoder.writeSmallInt(searchClassPath.size());</code>
<code> </code><code>for</code> <code>(File file : searchClassPath) {</code>
<code> </code><code>encoder.writeString(file.getAbsolutePath());</code>
<code> </code><code>encoder.flush();</code>
<code> </code><code>} </code><code>catch</code> <code>(IOException e) {</code>
<code> </code><code>throw</code> <code>new</code> <code>UncheckedIOException(e);</code>
<code> </code><code>ByteArrayInputStream stdInput = </code><code>new</code> <code>ByteArrayInputStream(serializedConfig.toByteArray());</code>
<code> </code><code>return</code> <code>startProcess(daemonArgs, daemonDir.getVersionedDir(), stdInput);</code>
四. 守护进程执行入口
<code>public</code> <code>class</code> <code>GradleDaemon {</code>
<code> </code><code>public</code> <code>static</code> <code>void</code> <code>main(String[] args) {</code>
<code> </code><code>new</code> <code>ProcessBootstrap().run(</code><code>"org.gradle.launcher.daemon.bootstrap.DaemonMain"</code><code>, args);</code>
<code>public</code> <code>class</code> <code>DaemonMain </code><code>extends</code> <code>EntryPoint {</code>
<code> </code><code>private</code> <code>static</code> <code>final</code> <code>Logger LOGGER = Logging.getLogger(DaemonMain.</code><code>class</code><code>);</code>
<code> </code><code>private</code> <code>PrintStream originalOut;</code>
<code> </code><code>private</code> <code>PrintStream originalErr;</code>
<code> </code><code>@Override</code>
<code> </code><code>protected</code> <code>void</code> <code>doAction(String[] args, ExecutionListener listener) {</code>
<code> </code><code>KryoBackedDecoder decoder = </code><code>new</code> <code>KryoBackedDecoder(</code><code>new</code> <code>EncodedStream.EncodedInput(System.in));</code>
<code> </code><code>gradleHomeDir = </code><code>new</code> <code>File(decoder.readString());</code>
<code> </code><code>daemonBaseDir = </code><code>new</code> <code>File(decoder.readString());</code>
<code> </code><code>idleTimeoutMs = decoder.readSmallInt();</code>
<code> </code><code>periodicCheckIntervalMs = decoder.readSmallInt();</code>
<code> </code><code>daemonUid = decoder.readString();</code>
<code> </code><code>int</code> <code>argCount = decoder.readSmallInt();</code>
<code> </code><code>startupOpts = </code><code>new</code> <code>ArrayList<String>(argCount);</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i < argCount; i++) {</code>
<code> </code><code>startupOpts.add(decoder.readString());</code>
<code> </code><code>int</code> <code>additionalClassPathLength = decoder.readSmallInt();</code>
<code> </code><code>additionalClassPath = </code><code>new</code> <code>ArrayList<File>(additionalClassPathLength);</code>
<code> </code><code>for</code> <code>(</code><code>int</code> <code>i = </code><code>0</code><code>; i < additionalClassPathLength; i++) {</code>
<code> </code><code>additionalClassPath.add(</code><code>new</code> <code>File(decoder.readString()));</code>
<code> </code><code>} </code><code>catch</code> <code>(EOFException e) {</code>
<code> </code><code>System.out.println(</code><code>"DaemonMain doAction 4"</code><code>);</code>
<code> </code><code>NativeServices.initialize(gradleHomeDir);</code>
<code> </code><code>DaemonServerConfiguration parameters = </code><code>new</code> <code>DefaultDaemonServerConfiguration(daemonUid, daemonBaseDir, idleTimeoutMs, periodicCheckIntervalMs, startupOpts);</code>
<code> </code><code>LoggingServiceRegistry loggingRegistry = LoggingServiceRegistry.newCommandLineProcessLogging();</code>
<code> </code>
<code> </code><code>LoggingManagerInternal loggingManager = loggingRegistry.newInstance(LoggingManagerInternal.</code><code>class</code><code>);</code>
<code> </code><code>TrueTimeProvider timeProvider = </code><code>new</code> <code>TrueTimeProvider();</code>
<code> </code><code>DaemonServices daemonServices = </code><code>new</code> <code>DaemonServices(parameters, loggingRegistry, loggingManager, </code><code>new</code> <code>DefaultClassPath(additionalClassPath), timeProvider.getCurrentTime());</code>
<code> </code><code>File daemonLog = daemonServices.getDaemonLogFile();</code>
<code> </code><code>// Any logging prior to this point will not end up in the daemon log file.</code>
<code> </code><code>initialiseLogging(loggingManager, daemonLog);</code>
<code> </code><code>LOGGER.debug(</code><code>"Assuming the daemon was started with following jvm opts: {}"</code><code>, startupOpts);</code>
<code> </code><code>Daemon daemon = daemonServices.get(Daemon.</code><code>class</code><code>);</code>
<code> </code><code>daemon.start();</code>
<code> </code><code>DaemonContext daemonContext = daemonServices.get(DaemonContext.</code><code>class</code><code>);</code>
<code> </code><code>Long pid = daemonContext.getPid();</code>
<code> </code><code>daemonStarted(pid, daemon.getUid(), daemon.getAddress(), daemonLog);</code>
<code> </code><code>DaemonExpirationStrategy expirationStrategy = daemonServices.get(MasterExpirationStrategy.</code><code>class</code><code>);</code>
<code> </code><code>daemon.stopOnExpiration(expirationStrategy, parameters.getPeriodicCheckIntervalMs());</code>
<code> </code><code>} </code><code>finally</code> <code>{</code>
<code> </code><code>daemon.stop();</code>
五. 守护进程的日志
守护进程的日志没有打印在控制台,而是打印在文件中,通过下面这行代码,进行了日志输出流转向。
<code>// Any logging prior to this point will not end up in the daemon log file.</code>
<code>initialiseLogging(loggingManager, daemonLog);</code>
日志保存的位置在 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"
最后附加自己编译的gradle3.1源代码和编译生成文件
<a href="http://down.51cto.com/data/2313329" target="_blank">gradle3.1源代码</a>
<a href="http://down.51cto.com/data/2313331" target="_blank">gradle3.1源代码编译后文件</a>
本文转自rongwei84n 51CTO博客,原文链接:http://blog.51cto.com/483181/1931190,如需转载请自行联系原作者