diff --git a/src/main/scala/com/github/shadowsocks/BaseService.scala b/src/main/scala/com/github/shadowsocks/BaseService.scala index 6bc36598..e5976fb6 100644 --- a/src/main/scala/com/github/shadowsocks/BaseService.scala +++ b/src/main/scala/com/github/shadowsocks/BaseService.scala @@ -43,10 +43,12 @@ import java.util.{Timer, TimerTask} import android.app.Service import android.content.{BroadcastReceiver, Context, Intent, IntentFilter} +import android.net.ConnectivityManager import android.os.{Handler, RemoteCallbackList} import android.text.TextUtils import android.util.Log import android.widget.Toast + import com.github.kevinsawicki.http.HttpRequest import com.github.shadowsocks.aidl.{IShadowsocksService, IShadowsocksServiceCallback} import com.github.shadowsocks.utils._ @@ -71,6 +73,16 @@ trait BaseService extends Service { } var closeReceiverRegistered: Boolean = _ + var kcptunProcess: GuardedProcess = _ + private val networkReceiver: BroadcastReceiver = (context: Context, intent: Intent) => { + val cm = context.getSystemService(Context.CONNECTIVITY_SERVICE).asInstanceOf[ConnectivityManager] + val activeNetwork = cm.getActiveNetworkInfo() + val isConnected = activeNetwork != null && activeNetwork.isConnected() + + if (isConnected && profile.kcp && kcptunProcess != null) kcptunProcess.restart() + } + var networkReceiverRegistered: Boolean = _ + val binder = new IShadowsocksService.Stub { override def getState: Int = { state @@ -162,6 +174,14 @@ trait BaseService extends Service { closeReceiverRegistered = true } + if (!networkReceiverRegistered) { + // register network change receiver + val filter = new IntentFilter() + filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION) + registerReceiver(networkReceiver, filter) + networkReceiverRegistered = true + } + app.track(getClass.getSimpleName, "start") changeState(State.CONNECTING) @@ -177,6 +197,10 @@ trait BaseService extends Service { unregisterReceiver(closeReceiver) closeReceiverRegistered = false } + if (networkReceiverRegistered) { + unregisterReceiver(networkReceiver) + networkReceiverRegistered = false + } // Make sure update total traffic when stopping the runner updateTrafficTotal(TrafficMonitor.txTotal, TrafficMonitor.rxTotal) diff --git a/src/main/scala/com/github/shadowsocks/GuardedProcess.scala b/src/main/scala/com/github/shadowsocks/GuardedProcess.scala index 024c1b79..c3eec7dc 100644 --- a/src/main/scala/com/github/shadowsocks/GuardedProcess.scala +++ b/src/main/scala/com/github/shadowsocks/GuardedProcess.scala @@ -56,6 +56,7 @@ class GuardedProcess(cmd: Seq[String]) extends Process { @volatile private var guardThread: Thread = _ @volatile private var isDestroyed: Boolean = _ @volatile private var process: Process = _ + @volatile private var isRestart = false def start(onRestartCallback: () => Unit = null): GuardedProcess = { val semaphore = new Semaphore(1) @@ -76,9 +77,13 @@ class GuardedProcess(cmd: Seq[String]) extends Process { semaphore.release process.waitFor - if (currentTimeMillis - startTime < 1000) { - Log.w(TAG, "process exit too fast, stop guard: " + cmd) - isDestroyed = true + if (isRestart) { + isRestart = false + } else { + if (currentTimeMillis - startTime < 1000) { + Log.w(TAG, "process exit too fast, stop guard: " + cmd) + isDestroyed = true + } } } } catch { @@ -108,6 +113,11 @@ class GuardedProcess(cmd: Seq[String]) extends Process { } } + def restart() { + isRestart = true + process.destroy() + } + def exitValue: Int = throw new UnsupportedOperationException def getErrorStream: InputStream = throw new UnsupportedOperationException def getInputStream: InputStream = throw new UnsupportedOperationException diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala index cbb69975..a9b00af3 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksNatService.scala @@ -65,7 +65,6 @@ class ShadowsocksNatService extends BaseService { private var notification: ShadowsocksNotification = _ val myUid = android.os.Process.myUid() - var kcptunProcess: Process = _ var sslocalProcess: Process = _ var sstunnelProcess: Process = _ var redsocksProcess: Process = _ diff --git a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala index dbb254e0..c3404000 100644 --- a/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala +++ b/src/main/scala/com/github/shadowsocks/ShadowsocksVpnService.scala @@ -63,7 +63,6 @@ class ShadowsocksVpnService extends VpnService with BaseService { var vpnThread: ShadowsocksVpnThread = _ private var notification: ShadowsocksNotification = _ - var kcptunProcess: Process = _ var sslocalProcess: Process = _ var sstunnelProcess: Process = _ var pdnsdProcess: Process = _