From a85acbf2d0b5bb4d4455db88d87b09d1125a5b4a Mon Sep 17 00:00:00 2001 From: Akash Yadav Date: Sat, 27 May 2023 00:05:08 +0530 Subject: [PATCH] fix: avoid potential memory leaks in build service --- .../services/builder/GradleBuildService.java | 6 +++ .../services/builder/ToolingServerRunner.kt | 39 +++++++------------ 2 files changed, 21 insertions(+), 24 deletions(-) diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.java b/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.java index 92a7f0ce7..5e8c562c2 100644 --- a/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.java +++ b/app/src/main/java/com/itsaky/androidide/services/builder/GradleBuildService.java @@ -165,6 +165,11 @@ public class GradleBuildService extends Service implements BuildService, IToolin LOG.info("Service is being destroyed.", "Dismissing the shown notification..."); notificationManager.cancel(NOTIFICATION_ID); + + final var lookup = Lookup.getDefault(); + lookup.unregister(GradleBuildService.KEY_BUILD_SERVICE); + lookup.unregister(GradleBuildService.KEY_PROJECT_PROXY); + if (server != null) { server.cancelCurrentBuild(); final var shutdown = server.shutdown(); @@ -181,6 +186,7 @@ public class GradleBuildService extends Service implements BuildService, IToolin } if (toolingServerThread != null) { + toolingServerThread.release(); toolingServerThread.interrupt(); toolingServerThread = null; } diff --git a/app/src/main/java/com/itsaky/androidide/services/builder/ToolingServerRunner.kt b/app/src/main/java/com/itsaky/androidide/services/builder/ToolingServerRunner.kt index ca85e69d4..a00c7d730 100644 --- a/app/src/main/java/com/itsaky/androidide/services/builder/ToolingServerRunner.kt +++ b/app/src/main/java/com/itsaky/androidide/services/builder/ToolingServerRunner.kt @@ -51,12 +51,9 @@ internal class ToolingServerRunner( log.info("Starting tooling API server...") val serverStreams = ProcessStreamsHolder() val executor = CommonProcessExecutor() - executor.execAsync( - serverStreams, - { observer?.onServerExited(it) }, - false, // The 'java' binary executable - Environment.JAVA - .absolutePath, // Allow reflective access to private members of classes in the following + executor.execAsync(serverStreams, { observer?.onServerExited(it) }, false, + Environment.JAVA.absolutePath, // The 'java' binary executable + // Allow reflective access to private members of classes in the following // packages: // - java.lang // - java.io @@ -70,29 +67,19 @@ internal class ToolingServerRunner( // these objects are reflectively accessed by Gson. If we do no specify // '--add-opens' for 'java.io' (for java.io.File) package, JVM will throw an // InaccessibleObjectException. - "--add-opens", - "java.base/java.lang=ALL-UNNAMED", - "--add-opens", - "java.base/java.util=ALL-UNNAMED", - "--add-opens", + "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", + "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.io=ALL-UNNAMED", // The JAR file to run - "-jar", - Environment.TOOLING_API_JAR.absolutePath - ) + "-jar", Environment.TOOLING_API_JAR.absolutePath) - val launcher = - ToolingApiLauncher.newClientLauncher( - observer?.getClient(), - serverStreams.`in`, - serverStreams.out - ) + val launcher = ToolingApiLauncher.newClientLauncher(observer?.getClient(), + serverStreams.`in`, serverStreams.out) val future = launcher.startListening() observer?.onListenerStarted( server = launcher.remoteProxy as IToolingApiServer, projectProxy = launcher.remoteProxy as IProject, - streams = serverStreams - ) + streams = serverStreams) isStarted = true @@ -113,6 +100,7 @@ internal class ToolingServerRunner( is CancellationException, is InterruptedException, -> log.info("ToolingServerThread has been cancelled or interrupted.") + else -> throw err } } @@ -122,8 +110,8 @@ internal class ToolingServerRunner( } override fun interrupt() { - super.interrupt() release() + super.interrupt() } fun release() { @@ -132,17 +120,20 @@ internal class ToolingServerRunner( } interface Observer { + fun onListenerStarted( server: IToolingApiServer, projectProxy: IProject, streams: ProcessStreamsHolder, ) + fun onServerExited(exitCode: Int) fun getClient(): IToolingApiClient } - + /** Callback to listen for Tooling API server start event. */ fun interface OnServerStartListener { + /** Called when the tooling API server has been successfully started. */ fun onServerStarted() }