Commit 32aa8007 authored by Mygod's avatar Mygod

Fix memory leaks caused by writeStrongBinder

parent fcdcbd14
......@@ -6,8 +6,8 @@ interface IShadowsocksService {
int getState();
String getProfileName();
oneway void registerCallback(IShadowsocksServiceCallback cb);
oneway void startListeningForBandwidth(IShadowsocksServiceCallback cb);
oneway void stopListeningForBandwidth(IShadowsocksServiceCallback cb);
oneway void unregisterCallback(IShadowsocksServiceCallback cb);
void registerCallback(in IShadowsocksServiceCallback cb);
void startListeningForBandwidth(in IShadowsocksServiceCallback cb);
oneway void stopListeningForBandwidth(in IShadowsocksServiceCallback cb);
oneway void unregisterCallback(in IShadowsocksServiceCallback cb);
}
......@@ -2,9 +2,9 @@ package com.github.shadowsocks.aidl;
import com.github.shadowsocks.aidl.TrafficStats;
interface IShadowsocksServiceCallback {
oneway void stateChanged(int state, String profileName, String msg);
oneway void trafficUpdated(long profileId, in TrafficStats stats);
oneway interface IShadowsocksServiceCallback {
void stateChanged(int state, String profileName, String msg);
void trafficUpdated(long profileId, in TrafficStats stats);
// Traffic data has persisted to database, listener should refetch their data from database
oneway void trafficPersisted(long profileId);
void trafficPersisted(long profileId);
}
......@@ -42,6 +42,7 @@ import androidx.work.Configuration
import androidx.work.WorkManager
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.aidl.ShadowsocksConnection
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.core.R
import com.github.shadowsocks.database.Profile
......@@ -140,7 +141,7 @@ object Core {
if (Build.VERSION.SDK_INT >= 28) PackageManager.GET_SIGNING_CERTIFICATES
else @Suppress("DEPRECATION") PackageManager.GET_SIGNATURES)!!
fun startService() = ContextCompat.startForegroundService(app, Intent(app, BaseService.serviceClass.java))
fun startService() = ContextCompat.startForegroundService(app, Intent(app, ShadowsocksConnection.serviceClass))
fun reloadService() = app.sendBroadcast(Intent(Action.RELOAD))
fun stopService() = app.sendBroadcast(Intent(Action.CLOSE))
......
......@@ -31,33 +31,32 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.core.R
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.utils.broadcastReceiver
class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Callback {
class VpnRequestActivity : AppCompatActivity() {
companion object {
private const val TAG = "VpnRequestActivity"
private const val REQUEST_CONNECT = 1
}
private val connection = ShadowsocksConnection(this)
private var receiver: BroadcastReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (!BaseService.usingVpnMode) {
if (DataStore.serviceMode != Key.modeVpn) {
finish()
return
}
if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) {
receiver = broadcastReceiver { _, _ -> connection.connect(this) }
receiver = broadcastReceiver { _, _ -> request() }
registerReceiver(receiver, IntentFilter(Intent.ACTION_USER_PRESENT))
} else connection.connect(this)
} else request()
}
override fun onServiceConnected(service: IShadowsocksService) {
private fun request() {
val intent = VpnService.prepare(this)
if (intent == null) onActivityResult(REQUEST_CONNECT, RESULT_OK, null)
else startActivityForResult(intent, REQUEST_CONNECT)
......@@ -73,7 +72,6 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Callback {
override fun onDestroy() {
super.onDestroy()
connection.disconnect(this)
if (receiver != null) unregisterReceiver(receiver)
}
}
......@@ -18,7 +18,7 @@
* *
*******************************************************************************/
package com.github.shadowsocks
package com.github.shadowsocks.aidl
import android.content.ComponentName
import android.content.Context
......@@ -27,15 +27,31 @@ import android.content.ServiceConnection
import android.os.DeadObjectException
import android.os.IBinder
import android.os.RemoteException
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.Core
import com.github.shadowsocks.bg.ProxyService
import com.github.shadowsocks.bg.TransproxyService
import com.github.shadowsocks.bg.VpnService
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Action
import com.github.shadowsocks.utils.Key
/**
* This object should be compact as it will not get GC-ed.
*/
class ShadowsocksConnection(private var listenForDeath: Boolean = false) : ServiceConnection, IBinder.DeathRecipient {
companion object {
val serviceClass get() = when (DataStore.serviceMode) {
Key.modeProxy -> ProxyService::class
Key.modeVpn -> VpnService::class
Key.modeTransproxy -> TransproxyService::class
else -> throw UnknownError()
}.java
}
class ShadowsocksConnection(private val callback: Callback, private var listenForDeath: Boolean = false) :
ServiceConnection, IBinder.DeathRecipient {
interface Callback {
val serviceCallback: IShadowsocksServiceCallback? get() = null
fun stateChanged(state: Int, profileName: String?, msg: String?)
fun trafficUpdated(profileId: Long, stats: TrafficStats) { }
fun trafficPersisted(profileId: Long) { }
fun onServiceConnected(service: IShadowsocksService)
/**
......@@ -47,14 +63,26 @@ class ShadowsocksConnection(private val callback: Callback, private var listenFo
private var connectionActive = false
private var callbackRegistered = false
private var callback: Callback? = null
private val serviceCallback = object : IShadowsocksServiceCallback.Stub() {
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
Core.handler.post { callback!!.stateChanged(state, profileName, msg) }
}
override fun trafficUpdated(profileId: Long, stats: TrafficStats) {
Core.handler.post { callback!!.trafficUpdated(profileId, stats) }
}
override fun trafficPersisted(profileId: Long) {
Core.handler.post { callback!!.trafficPersisted(profileId) }
}
}
private var binder: IBinder? = null
var listeningForBandwidth = false
set(value) {
val service = service
if (listeningForBandwidth != value && service != null && callback.serviceCallback != null)
if (value) service.startListeningForBandwidth(callback.serviceCallback) else try {
service.stopListeningForBandwidth(callback.serviceCallback)
if (listeningForBandwidth != value && service != null)
if (value) service.startListeningForBandwidth(serviceCallback) else try {
service.stopListeningForBandwidth(serviceCallback)
} catch (_: DeadObjectException) { }
field = value
}
......@@ -65,51 +93,53 @@ class ShadowsocksConnection(private val callback: Callback, private var listenFo
if (listenForDeath) binder.linkToDeath(this, 0)
val service = IShadowsocksService.Stub.asInterface(binder)!!
this.service = service
if (callback.serviceCallback != null && !callbackRegistered) try {
service.registerCallback(callback.serviceCallback)
if (!callbackRegistered) try {
service.registerCallback(serviceCallback)
callbackRegistered = true
if (listeningForBandwidth) service.startListeningForBandwidth(callback.serviceCallback)
if (listeningForBandwidth) service.startListeningForBandwidth(serviceCallback)
} catch (_: RemoteException) { }
callback.onServiceConnected(service)
callback!!.onServiceConnected(service)
}
override fun onServiceDisconnected(name: ComponentName?) {
unregisterCallback()
callback.onServiceDisconnected()
callback!!.onServiceDisconnected()
service = null
binder = null
}
override fun binderDied() {
service = null
callback.onBinderDied()
callback!!.onBinderDied()
}
private fun unregisterCallback() {
val service = service
if (service != null && callback.serviceCallback != null && callbackRegistered) try {
service.unregisterCallback(callback.serviceCallback)
if (service != null && callbackRegistered) try {
service.unregisterCallback(serviceCallback)
} catch (_: RemoteException) { }
callbackRegistered = false
}
fun connect(context: Context) {
fun connect(context: Context, callback: Callback) {
if (connectionActive) return
connectionActive = true
val intent = Intent(context, BaseService.serviceClass.java).setAction(Action.SERVICE)
check(this.callback == null)
this.callback = callback
val intent = Intent(context, serviceClass).setAction(Action.SERVICE)
context.bindService(intent, this, Context.BIND_AUTO_CREATE)
}
fun disconnect(context: Context) {
unregisterCallback()
callback.onServiceDisconnected()
if (connectionActive) try {
context.unbindService(this)
} catch (_: IllegalArgumentException) { } // ignore
connectionActive = false
if (listenForDeath) binder?.unlinkToDeath(this, 0)
binder = null
if (callback.serviceCallback != null) service?.stopListeningForBandwidth(callback.serviceCallback)
service?.stopListeningForBandwidth(serviceCallback)
service = null
callback = null
}
}
......@@ -59,7 +59,7 @@ object BaseService {
const val CONFIG_FILE = "shadowsocks.conf"
const val CONFIG_FILE_UDP = "shadowsocks-udp.conf"
class Data internal constructor(private val service: Interface) {
class Data internal constructor(private val service: Interface): AutoCloseable {
@Volatile var state = STOPPED
val processes = GuardedProcessPool()
@Volatile var proxy: ProxyInstance? = null
......@@ -160,6 +160,8 @@ object BaseService {
}
state = s
}
override fun close() = callbacks.kill()
}
interface Interface {
val tag: String
......@@ -317,6 +319,10 @@ object BaseService {
}
return Service.START_NOT_STICKY
}
fun onDestroy() {
data.close()
}
}
private val instances = WeakHashMap<Interface, Data>()
......@@ -324,12 +330,4 @@ object BaseService {
instances[instance] = Data(instance)
RemoteConfig.fetch()
}
val usingVpnMode: Boolean get() = DataStore.serviceMode == Key.modeVpn
val serviceClass get() = when (DataStore.serviceMode) {
Key.modeProxy -> ProxyService::class
Key.modeVpn -> VpnService::class
Key.modeTransproxy -> TransproxyService::class
else -> throw UnknownError()
}
}
......@@ -38,4 +38,8 @@ class ProxyService : Service(), BaseService.Interface {
override fun onBind(intent: Intent) = super.onBind(intent)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int =
super<BaseService.Interface>.onStartCommand(intent, flags, startId)
override fun onDestroy() {
super<Service>.onDestroy()
super<BaseService.Interface>.onDestroy()
}
}
......@@ -77,4 +77,9 @@ redsocks {
super.startNativeProcesses()
if (data.proxy!!.profile.udpdns) startDNSTunnel()
}
override fun onDestroy() {
super<Service>.onDestroy()
super<LocalDnsService.Interface>.onDestroy()
}
}
......@@ -35,6 +35,7 @@ import com.github.shadowsocks.VpnRequestActivity
import com.github.shadowsocks.acl.Acl
import com.github.shadowsocks.core.R
import com.github.shadowsocks.preference.DataStore
import com.github.shadowsocks.utils.Key
import com.github.shadowsocks.utils.Subnet
import com.github.shadowsocks.utils.parseNumericAddress
import com.github.shadowsocks.utils.printLog
......@@ -160,7 +161,7 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (BaseService.usingVpnMode)
if (DataStore.serviceMode == Key.modeVpn)
if (BaseVpnService.prepare(this) != null)
startActivity(Intent(this, VpnRequestActivity::class.java)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
......@@ -279,4 +280,9 @@ class VpnService : BaseVpnService(), LocalDnsService.Interface {
tries += 1
}
}
override fun onDestroy() {
super<BaseVpnService>.onDestroy()
super<LocalDnsService.Interface>.onDestroy()
}
}
......@@ -84,7 +84,7 @@ class HttpsTest : ViewModel() {
Acl.CHINALIST -> "www.qualcomm.cn"
else -> "www.google.com"
}, "/generate_204")
val conn = (if (BaseService.usingVpnMode) url.openConnection() else
val conn = (if (DataStore.serviceMode == Key.modeVpn) url.openConnection() else
url.openConnection(Proxy(Proxy.Type.SOCKS, InetSocketAddress("127.0.0.1", DataStore.portProxy))))
as HttpURLConnection
conn.setRequestProperty("Connection", "close")
......
......@@ -45,7 +45,7 @@ import androidx.preference.PreferenceDataStore
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.acl.CustomRulesFragment
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.aidl.ShadowsocksConnection
import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.bg.Executable
......@@ -92,12 +92,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
// service
var state = BaseService.IDLE
override val serviceCallback = object : IShadowsocksServiceCallback.Stub() {
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
Core.handler.post { changeState(state, msg, true) }
}
override fun stateChanged(state: Int, profileName: String?, msg: String?) = changeState(state, msg, true)
override fun trafficUpdated(profileId: Long, stats: TrafficStats) {
Core.handler.post {
if (profileId == 0L) this@MainActivity.stats.updateTraffic(
stats.txRate, stats.rxRate, stats.txTotal, stats.rxTotal)
if (state != BaseService.STOPPING) {
......@@ -105,10 +101,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
?.onTrafficUpdated(profileId, stats)
}
}
}
override fun trafficPersisted(profileId: Long) {
Core.handler.post { ProfilesFragment.instance?.onTrafficPersisted(profileId) }
}
ProfilesFragment.instance?.onTrafficPersisted(profileId)
}
private fun changeState(state: Int, msg: String? = null, animate: Boolean = false) {
......@@ -122,7 +116,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
private fun toggle() = when {
state == BaseService.CONNECTED -> Core.stopService()
BaseService.usingVpnMode -> {
DataStore.serviceMode == Key.modeVpn -> {
val intent = VpnService.prepare(this)
if (intent != null) startActivityForResult(intent, REQUEST_CONNECT)
else onActivityResult(REQUEST_CONNECT, Activity.RESULT_OK, null)
......@@ -130,7 +124,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
else -> Core.startService()
}
private val connection = ShadowsocksConnection(this, true)
private val connection = ShadowsocksConnection(true)
override fun onServiceConnected(service: IShadowsocksService) = changeState(try {
service.state
} catch (_: DeadObjectException) {
......@@ -141,7 +135,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
Core.handler.post {
connection.disconnect(this)
Executable.killAll()
connection.connect(this)
connection.connect(this, this)
}
}
......@@ -173,7 +167,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
fab.setOnClickListener { toggle() }
changeState(BaseService.IDLE) // reset everything to init state
Core.handler.post { connection.connect(this) }
Core.handler.post { connection.connect(this, this) }
DataStore.publicStore.registerChangeListener(this)
val intent = this.intent
......@@ -213,7 +207,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPref
when (key) {
Key.serviceMode -> Core.handler.post {
connection.disconnect(this)
connection.connect(this)
connection.connect(this, this)
}
}
}
......
......@@ -30,10 +30,13 @@ import androidx.core.content.pm.ShortcutInfoCompat
import androidx.core.content.pm.ShortcutManagerCompat
import androidx.core.graphics.drawable.IconCompat
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.ShadowsocksConnection
import com.github.shadowsocks.bg.BaseService
@Suppress("DEPRECATION")
@Deprecated("This shortcut is inefficient and should be superseded by TileService for API 24+.")
class QuickToggleShortcut : Activity(), ShadowsocksConnection.Callback {
private val connection = ShadowsocksConnection(this)
private val connection = ShadowsocksConnection()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
......@@ -46,7 +49,7 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Callback {
.build()))
finish()
} else {
connection.connect(this)
connection.connect(this, this)
if (Build.VERSION.SDK_INT >= 25) getSystemService<ShortcutManager>()!!.reportShortcutUsed("toggle")
}
}
......@@ -59,6 +62,8 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Callback {
finish()
}
override fun stateChanged(state: Int, profileName: String?, msg: String?) { }
override fun onDestroy() {
connection.disconnect(this)
super.onDestroy()
......
......@@ -23,16 +23,14 @@ package com.github.shadowsocks.bg
import android.app.KeyguardManager
import android.graphics.drawable.Icon
import android.service.quicksettings.Tile
import android.service.quicksettings.TileService as BaseTileService
import androidx.annotation.RequiresApi
import androidx.core.content.getSystemService
import com.github.shadowsocks.Core
import com.github.shadowsocks.R
import com.github.shadowsocks.ShadowsocksConnection
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.aidl.ShadowsocksConnection
import com.github.shadowsocks.preference.DataStore
import android.service.quicksettings.TileService as BaseTileService
@RequiresApi(24)
class TileService : BaseTileService(), ShadowsocksConnection.Callback {
......@@ -42,35 +40,10 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
private val keyguard by lazy { getSystemService<KeyguardManager>()!! }
private var tapPending = false
private val connection = ShadowsocksConnection(this)
override val serviceCallback = object : IShadowsocksServiceCallback.Stub() {
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
val tile = qsTile ?: return
var label: String? = null
when (state) {
BaseService.STOPPED -> {
tile.icon = iconIdle
tile.state = Tile.STATE_INACTIVE
}
BaseService.CONNECTED -> {
tile.icon = iconConnected
if (!keyguard.isDeviceLocked) label = profileName
tile.state = Tile.STATE_ACTIVE
}
else -> {
tile.icon = iconBusy
tile.state = Tile.STATE_UNAVAILABLE
}
}
tile.label = label ?: getString(R.string.app_name)
tile.updateTile()
}
override fun trafficUpdated(profileId: Long, stats: TrafficStats) { }
override fun trafficPersisted(profileId: Long) { }
}
private val connection = ShadowsocksConnection()
override fun stateChanged(state: Int, profileName: String?, msg: String?) = updateTile(state) { profileName }
override fun onServiceConnected(service: IShadowsocksService) {
serviceCallback.stateChanged(service.state, service.profileName, null)
updateTile(service.state) { service.profileName }
if (tapPending) {
tapPending = false
onClick()
......@@ -79,7 +52,7 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
override fun onStartListening() {
super.onStartListening()
connection.connect(this)
connection.connect(this, this)
}
override fun onStopListening() {
connection.disconnect(this)
......@@ -90,6 +63,29 @@ class TileService : BaseTileService(), ShadowsocksConnection.Callback {
if (isLocked && !DataStore.canToggleLocked) unlockAndRun(this::toggle) else toggle()
}
private fun updateTile(serviceState: Int, profileName: () -> String?) {
qsTile?.apply {
label = null
when (serviceState) {
BaseService.STOPPED -> {
icon = iconIdle
state = Tile.STATE_INACTIVE
}
BaseService.CONNECTED -> {
icon = iconConnected
if (!keyguard.isDeviceLocked) label = profileName()
state = Tile.STATE_ACTIVE
}
else -> {
icon = iconBusy
state = Tile.STATE_UNAVAILABLE
}
}
label = label ?: getString(R.string.app_name)
updateTile()
}
}
private fun toggle() {
val service = connection.service
if (service == null) tapPending = true else when (service.state) {
......
......@@ -42,9 +42,8 @@ import androidx.preference.SwitchPreference
import com.crashlytics.android.Crashlytics
import com.github.shadowsocks.BootReceiver
import com.github.shadowsocks.Core
import com.github.shadowsocks.ShadowsocksConnection
import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.aidl.ShadowsocksConnection
import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.bg.Executable
......@@ -89,10 +88,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
// service
var state = BaseService.IDLE
private set
override val serviceCallback = object : IShadowsocksServiceCallback.Stub() {
override fun stateChanged(state: Int, profileName: String?, msg: String?) {
Core.handler.post { changeState(state, msg) }
}
override fun stateChanged(state: Int, profileName: String?, msg: String?) = changeState(state, msg)
override fun trafficUpdated(profileId: Long, stats: TrafficStats) {
if (profileId == 0L) this@MainPreferenceFragment.stats.summary = getString(R.string.stat_summary,
getString(R.string.speed, Formatter.formatFileSize(activity, stats.txRate)),
......@@ -100,8 +96,6 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
Formatter.formatFileSize(activity, stats.txTotal),
Formatter.formatFileSize(activity, stats.rxTotal))
}
override fun trafficPersisted(profileId: Long) { }
}
private fun changeState(state: Int, msg: String? = null) {
fab.isEnabled = state == BaseService.STOPPED || state == BaseService.CONNECTED
......@@ -115,7 +109,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
stats.isVisible = state == BaseService.CONNECTED
val owner = activity as FragmentActivity // TODO: change to this when refactored to androidx
if (state != BaseService.CONNECTED) {
serviceCallback.trafficUpdated(0, TrafficStats())
trafficUpdated(0, TrafficStats())
tester.status.removeObservers(owner)
if (state != BaseService.IDLE) tester.invalidate()
} else tester.status.observe(owner, Observer {
......@@ -141,7 +135,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
}
}
private val connection = ShadowsocksConnection(this, true)
private val connection = ShadowsocksConnection(true)
override fun onServiceConnected(service: IShadowsocksService) = changeState(try {
service.state
} catch (_: DeadObjectException) {
......@@ -152,7 +146,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
Core.handler.post {
connection.disconnect(activity)
Executable.killAll()
connection.connect(activity)
connection.connect(activity, this)
}
}
......@@ -202,7 +196,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
tester = ViewModelProviders.of(activity as FragmentActivity).get()
changeState(BaseService.IDLE) // reset everything to init state
connection.connect(activity)
connection.connect(activity, this)
DataStore.publicStore.registerChangeListener(this)
}
......@@ -227,7 +221,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
fun startService() {
when {
state != BaseService.STOPPED -> return
BaseService.usingVpnMode -> {
DataStore.serviceMode == Key.modeVpn -> {
val intent = VpnService.prepare(activity)
if (intent != null) startActivityForResult(intent, REQUEST_CONNECT)
else onActivityResult(REQUEST_CONNECT, Activity.RESULT_OK, null)
......@@ -240,7 +234,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
when (key) {
Key.serviceMode -> Core.handler.post {
connection.disconnect(activity)
connection.connect(activity)
connection.connect(activity, this)
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment