Commit fcdcbd14 authored by Mygod's avatar Mygod

Refactor ShadowsocksConnection

parent 2ca6737f
...@@ -20,7 +20,6 @@ ...@@ -20,7 +20,6 @@
package com.github.shadowsocks package com.github.shadowsocks
import android.app.Fragment
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
...@@ -32,45 +31,30 @@ import com.github.shadowsocks.aidl.IShadowsocksService ...@@ -32,45 +31,30 @@ import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.aidl.IShadowsocksServiceCallback import com.github.shadowsocks.aidl.IShadowsocksServiceCallback
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.utils.Action import com.github.shadowsocks.utils.Action
import java.util.*
class ShadowsocksConnection(private val instance: Interface) : ServiceConnection { class ShadowsocksConnection(private val callback: Callback, private var listenForDeath: Boolean = false) :
companion object { ServiceConnection, IBinder.DeathRecipient {
private val connections = WeakHashMap<Interface, ShadowsocksConnection>() interface Callback {
}
interface Interface : IBinder.DeathRecipient {
val serviceCallback: IShadowsocksServiceCallback? get() = null val serviceCallback: IShadowsocksServiceCallback? get() = null
val connection: ShadowsocksConnection
get() = connections.getOrPut(this) { ShadowsocksConnection(this) }
val listenForDeath get() = false
fun onServiceConnected(service: IShadowsocksService) { } fun onServiceConnected(service: IShadowsocksService)
/** /**
* Different from Android framework, this method will be called even when you call `detachService`. * Different from Android framework, this method will be called even when you call `detachService`.
*/ */
fun onServiceDisconnected() { } fun onServiceDisconnected() { }
override fun binderDied() { fun onBinderDied() { }
connection.service = null
}
} }
private var connectionActive = false private var connectionActive = false
private var callbackRegistered = false private var callbackRegistered = false
private var binder: IBinder? = null private var binder: IBinder? = null
private val context by lazy {
when (instance) {
is Fragment -> instance.activity
else -> instance as Context
}
}
var listeningForBandwidth = false var listeningForBandwidth = false
set(value) { set(value) {
val service = service val service = service
if (listeningForBandwidth != value && service != null && instance.serviceCallback != null) if (listeningForBandwidth != value && service != null && callback.serviceCallback != null)
if (value) service.startListeningForBandwidth(instance.serviceCallback) else try { if (value) service.startListeningForBandwidth(callback.serviceCallback) else try {
service.stopListeningForBandwidth(instance.serviceCallback) service.stopListeningForBandwidth(callback.serviceCallback)
} catch (_: DeadObjectException) { } } catch (_: DeadObjectException) { }
field = value field = value
} }
...@@ -78,50 +62,54 @@ class ShadowsocksConnection(private val instance: Interface) : ServiceConnection ...@@ -78,50 +62,54 @@ class ShadowsocksConnection(private val instance: Interface) : ServiceConnection
override fun onServiceConnected(name: ComponentName?, binder: IBinder) { override fun onServiceConnected(name: ComponentName?, binder: IBinder) {
this.binder = binder this.binder = binder
if (instance.listenForDeath) binder.linkToDeath(instance, 0) if (listenForDeath) binder.linkToDeath(this, 0)
val service = IShadowsocksService.Stub.asInterface(binder)!! val service = IShadowsocksService.Stub.asInterface(binder)!!
this.service = service this.service = service
if (instance.serviceCallback != null && !callbackRegistered) try { if (callback.serviceCallback != null && !callbackRegistered) try {
service.registerCallback(instance.serviceCallback) service.registerCallback(callback.serviceCallback)
callbackRegistered = true callbackRegistered = true
if (listeningForBandwidth) service.startListeningForBandwidth(instance.serviceCallback) if (listeningForBandwidth) service.startListeningForBandwidth(callback.serviceCallback)
} catch (_: RemoteException) { } } catch (_: RemoteException) { }
instance.onServiceConnected(service) callback.onServiceConnected(service)
} }
override fun onServiceDisconnected(name: ComponentName?) { override fun onServiceDisconnected(name: ComponentName?) {
unregisterCallback() unregisterCallback()
instance.onServiceDisconnected() callback.onServiceDisconnected()
service = null service = null
binder = null binder = null
} }
override fun binderDied() {
service = null
callback.onBinderDied()
}
private fun unregisterCallback() { private fun unregisterCallback() {
val service = service val service = service
if (service != null && instance.serviceCallback != null && callbackRegistered) try { if (service != null && callback.serviceCallback != null && callbackRegistered) try {
service.unregisterCallback(instance.serviceCallback) service.unregisterCallback(callback.serviceCallback)
} catch (_: RemoteException) { } } catch (_: RemoteException) { }
callbackRegistered = false callbackRegistered = false
} }
fun connect() { fun connect(context: Context) {
if (connectionActive) return if (connectionActive) return
connectionActive = true connectionActive = true
val intent = Intent(context, BaseService.serviceClass.java).setAction(Action.SERVICE) val intent = Intent(context, BaseService.serviceClass.java).setAction(Action.SERVICE)
context.bindService(intent, this, Context.BIND_AUTO_CREATE) context.bindService(intent, this, Context.BIND_AUTO_CREATE)
} }
fun disconnect() { fun disconnect(context: Context) {
unregisterCallback() unregisterCallback()
instance.onServiceDisconnected() callback.onServiceDisconnected()
if (connectionActive) try { if (connectionActive) try {
context.unbindService(this) context.unbindService(this)
} catch (_: IllegalArgumentException) { } // ignore } catch (_: IllegalArgumentException) { } // ignore
connectionActive = false connectionActive = false
if (instance.listenForDeath) binder?.unlinkToDeath(instance, 0) if (listenForDeath) binder?.unlinkToDeath(this, 0)
binder = null binder = null
if (instance.serviceCallback != null) if (callback.serviceCallback != null) service?.stopListeningForBandwidth(callback.serviceCallback)
service?.stopListeningForBandwidth(instance.serviceCallback)
service = null service = null
} }
} }
...@@ -36,12 +36,13 @@ import com.github.shadowsocks.bg.BaseService ...@@ -36,12 +36,13 @@ import com.github.shadowsocks.bg.BaseService
import com.github.shadowsocks.core.R import com.github.shadowsocks.core.R
import com.github.shadowsocks.utils.broadcastReceiver import com.github.shadowsocks.utils.broadcastReceiver
class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface { class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Callback {
companion object { companion object {
private const val TAG = "VpnRequestActivity" private const val TAG = "VpnRequestActivity"
private const val REQUEST_CONNECT = 1 private const val REQUEST_CONNECT = 1
} }
private val connection = ShadowsocksConnection(this)
private var receiver: BroadcastReceiver? = null private var receiver: BroadcastReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
...@@ -51,9 +52,9 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface ...@@ -51,9 +52,9 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface
return return
} }
if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) { if (getSystemService<KeyguardManager>()!!.isKeyguardLocked) {
receiver = broadcastReceiver { _, _ -> connection.connect() } receiver = broadcastReceiver { _, _ -> connection.connect(this) }
registerReceiver(receiver, IntentFilter(Intent.ACTION_USER_PRESENT)) registerReceiver(receiver, IntentFilter(Intent.ACTION_USER_PRESENT))
} else connection.connect() } else connection.connect(this)
} }
override fun onServiceConnected(service: IShadowsocksService) { override fun onServiceConnected(service: IShadowsocksService) {
...@@ -72,7 +73,7 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface ...@@ -72,7 +73,7 @@ class VpnRequestActivity : AppCompatActivity(), ShadowsocksConnection.Interface
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
connection.disconnect() connection.disconnect(this)
if (receiver != null) unregisterReceiver(receiver) if (receiver != null) unregisterReceiver(receiver)
} }
} }
...@@ -59,7 +59,7 @@ import com.github.shadowsocks.widget.StatsBar ...@@ -59,7 +59,7 @@ import com.github.shadowsocks.widget.StatsBar
import com.google.android.material.navigation.NavigationView import com.google.android.material.navigation.NavigationView
import com.google.android.material.snackbar.Snackbar import com.google.android.material.snackbar.Snackbar
class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPreferenceDataStoreChangeListener, class MainActivity : AppCompatActivity(), ShadowsocksConnection.Callback, OnPreferenceDataStoreChangeListener,
NavigationView.OnNavigationItemSelectedListener { NavigationView.OnNavigationItemSelectedListener {
companion object { companion object {
private const val TAG = "ShadowsocksMainActivity" private const val TAG = "ShadowsocksMainActivity"
...@@ -130,19 +130,18 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre ...@@ -130,19 +130,18 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
else -> Core.startService() else -> Core.startService()
} }
override val listenForDeath: Boolean get() = true private val connection = ShadowsocksConnection(this, true)
override fun onServiceConnected(service: IShadowsocksService) = changeState(try { override fun onServiceConnected(service: IShadowsocksService) = changeState(try {
service.state service.state
} catch (_: DeadObjectException) { } catch (_: DeadObjectException) {
BaseService.IDLE BaseService.IDLE
}) })
override fun onServiceDisconnected() = changeState(BaseService.IDLE) override fun onServiceDisconnected() = changeState(BaseService.IDLE)
override fun binderDied() { override fun onBinderDied() {
super.binderDied()
Core.handler.post { Core.handler.post {
connection.disconnect() connection.disconnect(this)
Executable.killAll() Executable.killAll()
connection.connect() connection.connect(this)
} }
} }
...@@ -174,7 +173,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre ...@@ -174,7 +173,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
fab.setOnClickListener { toggle() } fab.setOnClickListener { toggle() }
changeState(BaseService.IDLE) // reset everything to init state changeState(BaseService.IDLE) // reset everything to init state
Core.handler.post { connection.connect() } Core.handler.post { connection.connect(this) }
DataStore.publicStore.registerChangeListener(this) DataStore.publicStore.registerChangeListener(this)
val intent = this.intent val intent = this.intent
...@@ -213,8 +212,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre ...@@ -213,8 +212,8 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) {
when (key) { when (key) {
Key.serviceMode -> Core.handler.post { Key.serviceMode -> Core.handler.post {
connection.disconnect() connection.disconnect(this)
connection.connect() connection.connect(this)
} }
} }
} }
...@@ -285,7 +284,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre ...@@ -285,7 +284,7 @@ class MainActivity : AppCompatActivity(), ShadowsocksConnection.Interface, OnPre
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
DataStore.publicStore.unregisterChangeListener(this) DataStore.publicStore.unregisterChangeListener(this)
connection.disconnect() connection.disconnect(this)
BackupManager(this).dataChanged() BackupManager(this).dataChanged()
Core.handler.removeCallbacksAndMessages(null) Core.handler.removeCallbacksAndMessages(null)
} }
......
...@@ -32,7 +32,9 @@ import androidx.core.graphics.drawable.IconCompat ...@@ -32,7 +32,9 @@ import androidx.core.graphics.drawable.IconCompat
import com.github.shadowsocks.aidl.IShadowsocksService import com.github.shadowsocks.aidl.IShadowsocksService
import com.github.shadowsocks.bg.BaseService import com.github.shadowsocks.bg.BaseService
class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface { class QuickToggleShortcut : Activity(), ShadowsocksConnection.Callback {
private val connection = ShadowsocksConnection(this)
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
if (intent.action == Intent.ACTION_CREATE_SHORTCUT) { if (intent.action == Intent.ACTION_CREATE_SHORTCUT) {
...@@ -44,7 +46,7 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface { ...@@ -44,7 +46,7 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface {
.build())) .build()))
finish() finish()
} else { } else {
connection.connect() connection.connect(this)
if (Build.VERSION.SDK_INT >= 25) getSystemService<ShortcutManager>()!!.reportShortcutUsed("toggle") if (Build.VERSION.SDK_INT >= 25) getSystemService<ShortcutManager>()!!.reportShortcutUsed("toggle")
} }
} }
...@@ -58,7 +60,7 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface { ...@@ -58,7 +60,7 @@ class QuickToggleShortcut : Activity(), ShadowsocksConnection.Interface {
} }
override fun onDestroy() { override fun onDestroy() {
connection.disconnect() connection.disconnect(this)
super.onDestroy() super.onDestroy()
} }
} }
...@@ -35,13 +35,14 @@ import com.github.shadowsocks.aidl.TrafficStats ...@@ -35,13 +35,14 @@ import com.github.shadowsocks.aidl.TrafficStats
import com.github.shadowsocks.preference.DataStore import com.github.shadowsocks.preference.DataStore
@RequiresApi(24) @RequiresApi(24)
class TileService : BaseTileService(), ShadowsocksConnection.Interface { class TileService : BaseTileService(), ShadowsocksConnection.Callback {
private val iconIdle by lazy { Icon.createWithResource(this, R.drawable.ic_service_idle) } private val iconIdle by lazy { Icon.createWithResource(this, R.drawable.ic_service_idle) }
private val iconBusy by lazy { Icon.createWithResource(this, R.drawable.ic_service_busy) } private val iconBusy by lazy { Icon.createWithResource(this, R.drawable.ic_service_busy) }
private val iconConnected by lazy { Icon.createWithResource(this, R.drawable.ic_service_active) } private val iconConnected by lazy { Icon.createWithResource(this, R.drawable.ic_service_active) }
private val keyguard by lazy { getSystemService<KeyguardManager>()!! } private val keyguard by lazy { getSystemService<KeyguardManager>()!! }
private var tapPending = false private var tapPending = false
private val connection = ShadowsocksConnection(this)
override val serviceCallback = object : IShadowsocksServiceCallback.Stub() { override val serviceCallback = object : IShadowsocksServiceCallback.Stub() {
override fun stateChanged(state: Int, profileName: String?, msg: String?) { override fun stateChanged(state: Int, profileName: String?, msg: String?) {
val tile = qsTile ?: return val tile = qsTile ?: return
...@@ -78,10 +79,10 @@ class TileService : BaseTileService(), ShadowsocksConnection.Interface { ...@@ -78,10 +79,10 @@ class TileService : BaseTileService(), ShadowsocksConnection.Interface {
override fun onStartListening() { override fun onStartListening() {
super.onStartListening() super.onStartListening()
connection.connect() connection.connect(this)
} }
override fun onStopListening() { override fun onStopListening() {
connection.disconnect() connection.disconnect(this)
super.onStopListening() super.onStopListening()
} }
......
...@@ -55,7 +55,7 @@ import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener ...@@ -55,7 +55,7 @@ import com.github.shadowsocks.preference.OnPreferenceDataStoreChangeListener
import com.github.shadowsocks.utils.* import com.github.shadowsocks.utils.*
import org.json.JSONArray import org.json.JSONArray
class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnection.Interface, class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnection.Callback,
OnPreferenceDataStoreChangeListener { OnPreferenceDataStoreChangeListener {
companion object { companion object {
private const val REQUEST_CONNECT = 1 private const val REQUEST_CONNECT = 1
...@@ -141,19 +141,18 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti ...@@ -141,19 +141,18 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
} }
} }
override val listenForDeath: Boolean get() = true private val connection = ShadowsocksConnection(this, true)
override fun onServiceConnected(service: IShadowsocksService) = changeState(try { override fun onServiceConnected(service: IShadowsocksService) = changeState(try {
service.state service.state
} catch (_: DeadObjectException) { } catch (_: DeadObjectException) {
BaseService.IDLE BaseService.IDLE
}) })
override fun onServiceDisconnected() = changeState(BaseService.IDLE) override fun onServiceDisconnected() = changeState(BaseService.IDLE)
override fun binderDied() { override fun onBinderDied() {
super.binderDied()
Core.handler.post { Core.handler.post {
connection.disconnect() connection.disconnect(activity)
Executable.killAll() Executable.killAll()
connection.connect() connection.connect(activity)
} }
} }
...@@ -203,7 +202,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti ...@@ -203,7 +202,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
tester = ViewModelProviders.of(activity as FragmentActivity).get() tester = ViewModelProviders.of(activity as FragmentActivity).get()
changeState(BaseService.IDLE) // reset everything to init state changeState(BaseService.IDLE) // reset everything to init state
connection.connect() connection.connect(activity)
DataStore.publicStore.registerChangeListener(this) DataStore.publicStore.registerChangeListener(this)
} }
...@@ -240,8 +239,8 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti ...@@ -240,8 +239,8 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) { override fun onPreferenceDataStoreChanged(store: PreferenceDataStore, key: String?) {
when (key) { when (key) {
Key.serviceMode -> Core.handler.post { Key.serviceMode -> Core.handler.post {
connection.disconnect() connection.disconnect(activity)
connection.connect() connection.connect(activity)
} }
} }
} }
...@@ -334,7 +333,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti ...@@ -334,7 +333,7 @@ class MainPreferenceFragment : LeanbackPreferenceFragment(), ShadowsocksConnecti
override fun onDestroy() { override fun onDestroy() {
super.onDestroy() super.onDestroy()
DataStore.publicStore.unregisterChangeListener(this) DataStore.publicStore.unregisterChangeListener(this)
connection.disconnect() connection.disconnect(activity)
BackupManager(activity).dataChanged() BackupManager(activity).dataChanged()
} }
} }
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