diff --git a/project/plugins.sbt b/project/plugins.sbt index 1910433d..5bd5e4e2 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,6 +1,6 @@ resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-snapshots"))(Resolver.ivyStylePatterns) -addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.18") +addSbtPlugin("com.hanhuy.sbt" % "android-sdk-plugin" % "1.5.19") resolvers += "Sonatype snapshots" at "https://oss.sonatype.org/content/repositories/snapshots/" diff --git a/src/main/java/com/github/shadowsocks/GuardedProcess.scala b/src/main/scala/com/github/shadowsocks/GuardedProcess.scala similarity index 72% rename from src/main/java/com/github/shadowsocks/GuardedProcess.scala rename to src/main/scala/com/github/shadowsocks/GuardedProcess.scala index ce6c5469..8637739a 100644 --- a/src/main/java/com/github/shadowsocks/GuardedProcess.scala +++ b/src/main/scala/com/github/shadowsocks/GuardedProcess.scala @@ -1,6 +1,6 @@ /* * Shadowsocks - A shadowsocks client for Android - * Copyright (C) 2015 + * Copyright (C) 2016 * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -48,53 +48,45 @@ import java.util.concurrent.atomic.AtomicReference import collection.JavaConversions._ -object GuardedProcess { - private val TAG: String = classOf[GuardedProcess].getSimpleName +/** + * @author ayanamist@gmail.com + */ +class GuardedProcess (cmd: Seq[String], onRestartCallback: Runnable = null) extends Process { - @throws(classOf[IOException]) - private def startProcess(cmd: Seq[String]): Process = { - new ProcessBuilder(cmd).redirectErrorStream(true).start - } -} + private val TAG = classOf[GuardedProcess].getSimpleName -class GuardedProcess extends Process { - private var guardThread: Thread = null - @volatile - private var isDestroyed: Boolean = false - @volatile - private var process: Process = null + @volatile private var guardThread: Thread = null + @volatile private var isDestroyed: Boolean = false + @volatile private var process: Process = null - @throws(classOf[InterruptedException]) - @throws(classOf[IOException]) - def this(cmd: Seq[String], onRestartCallback: Runnable = null) { - this() - initThread(cmd, onRestartCallback) - } + def start(): GuardedProcess = { + + val atomicIoException = new AtomicReference[IOException](null) + val countDownLatch = new CountDownLatch(1) - def initThread(cmd: Seq[String], onRestartCallback: Runnable): Unit = { - val atomicIoException: AtomicReference[IOException] = new AtomicReference[IOException](null) - val countDownLatch: CountDownLatch = new CountDownLatch(1) guardThread = new Thread(new Runnable() { - override def run(): Unit = { + override def run() { try { while (!isDestroyed) { - Log.i(GuardedProcess.TAG, "start process: " + cmd) - val startTime: Long = java.lang.System.currentTimeMillis - process = GuardedProcess.startProcess(cmd) + Log.i(TAG, "start process: " + cmd) + val startTime = java.lang.System.currentTimeMillis + + process = new ProcessBuilder(cmd).redirectErrorStream(true).start if (onRestartCallback != null && countDownLatch.getCount <= 0) { onRestartCallback.run() } + countDownLatch.countDown() process.waitFor + if (java.lang.System.currentTimeMillis - startTime < 1000) { - Log.w(GuardedProcess.TAG, "process exit too fast, stop guard: " + cmd) + Log.w(TAG, "process exit too fast, stop guard: " + cmd) return } } - } - catch { + } catch { case ignored: InterruptedException => - Log.i(GuardedProcess.TAG, "thread interrupt, destroy process: " + cmd) + Log.i(TAG, "thread interrupt, destroy process: " + cmd) process.destroy() case e: IOException => atomicIoException.compareAndSet(null, e) @@ -103,12 +95,16 @@ class GuardedProcess extends Process { } } }, "GuardThread-" + cmd) + guardThread.start() countDownLatch.await() + val ioException: IOException = atomicIoException.get if (ioException != null) { throw ioException } + + this } def destroy() { @@ -144,4 +140,4 @@ class GuardedProcess extends Process { guardThread.join() 0 } -} \ No newline at end of file +} diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index b7d9d308..e16e7e00 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -196,7 +196,7 @@ class ShadowsocksNatService extends BaseService { } if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - sslocalProcess = new GuardedProcess(cmd) + sslocalProcess = new GuardedProcess(cmd).start() } def startTunnel() { @@ -222,7 +222,7 @@ class ShadowsocksNatService extends BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - sstunnelProcess = new GuardedProcess(cmd) + sstunnelProcess = new GuardedProcess(cmd).start() } else { val conf = ConfigUtils @@ -245,7 +245,7 @@ class ShadowsocksNatService extends BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmdBuf.mkString(" ")) - sstunnelProcess = new GuardedProcess(cmdBuf) + sstunnelProcess = new GuardedProcess(cmdBuf).start() } } @@ -268,7 +268,7 @@ class ShadowsocksNatService extends BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd) - pdnsdProcess = new GuardedProcess(cmd.split(" ").toSeq) + pdnsdProcess = new GuardedProcess(cmd.split(" ").toSeq).start() } def getVersionName: String = { @@ -292,7 +292,7 @@ class ShadowsocksNatService extends BaseService { }) if (BuildConfig.DEBUG) Log.d(TAG, cmd) - redsocksProcess = new GuardedProcess(cmd.split(" ").toSeq) + redsocksProcess = new GuardedProcess(cmd.split(" ").toSeq).start() } /** Called when the activity is first created. */ diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index 06639770..dff53174 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -296,7 +296,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - sslocalProcess = new GuardedProcess(cmd) + sslocalProcess = new GuardedProcess(cmd).start() } def startDnsTunnel() = { @@ -321,7 +321,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd.mkString(" ")) - sstunnelProcess = new GuardedProcess(cmd) + sstunnelProcess = new GuardedProcess(cmd).start() } def startDnsDaemon() { @@ -344,7 +344,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { if (BuildConfig.DEBUG) Log.d(TAG, cmd) - pdnsdProcess = new GuardedProcess(cmd.split(" ").toSeq) + pdnsdProcess = new GuardedProcess(cmd.split(" ").toSeq).start() } override def getContext = getBaseContext @@ -438,7 +438,7 @@ class ShadowsocksVpnService extends VpnService with BaseService { override def run(): Unit = { sendFd(fd) } - }) + }).start() fd }