Fix tethering stability issues

This commit is contained in:
Mygod
2018-01-21 03:07:26 -08:00
parent e2455cdd84
commit 7f93b1e62b
7 changed files with 105 additions and 63 deletions

View File

@@ -1,34 +1,33 @@
package be.mygod.vpnhotspot
import android.app.Notification
import android.app.PendingIntent
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.support.v4.app.NotificationCompat
import android.support.v4.content.ContextCompat
import android.support.v4.content.LocalBroadcastManager
import android.widget.Toast
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.NetUtils
import be.mygod.vpnhotspot.net.Routing
import be.mygod.vpnhotspot.net.VpnMonitor
import be.mygod.vpnhotspot.net.*
class TetheringService : Service(), VpnMonitor.Callback {
class TetheringService : Service(), VpnMonitor.Callback, IpNeighbourMonitor.Callback {
companion object {
const val ACTION_ACTIVE_INTERFACES_CHANGED = "be.mygod.vpnhotspot.TetheringService.ACTIVE_INTERFACES_CHANGED"
const val CHANNEL = "tethering"
const val CHANNEL_ID = 2
const val EXTRA_ADD_INTERFACE = "interface.add"
const val EXTRA_REMOVE_INTERFACE = "interface.remove"
private const val KEY_ACTIVE = "persist.service.tether.active"
private var alive = false
var active: Set<String>
get() = if (alive) app.pref.getStringSet(KEY_ACTIVE, null) ?: emptySet() else {
app.pref.edit().remove(KEY_ACTIVE).apply()
emptySet()
}
private set(value) {
app.pref.edit().putStringSet(KEY_ACTIVE, value).apply()
LocalBroadcastManager.getInstance(app).sendBroadcast(Intent(ACTION_ACTIVE_INTERFACES_CHANGED))
}
}
inner class TetheringBinder : Binder() {
val active get() = routings.keys
var fragment: TetheringFragment? = null
}
private val binder = TetheringBinder()
private val routings = HashMap<String, Routing?>()
private var neighbours = emptyList<IpNeighbour>()
private var upstream: String? = null
private var receiverRegistered = false
private val receiver = broadcastReceiver { _, intent ->
@@ -47,6 +46,7 @@ class TetheringService : Service(), VpnMonitor.Callback {
private fun updateRoutings() {
if (routings.isEmpty()) {
unregisterReceiver()
stopForeground(true)
stopSelf()
} else {
val upstream = upstream
@@ -65,29 +65,24 @@ class TetheringService : Service(), VpnMonitor.Callback {
registerReceiver(receiver, intentFilter(NetUtils.ACTION_TETHER_STATE_CHANGED))
LocalBroadcastManager.getInstance(this)
.registerReceiver(receiver, intentFilter(App.ACTION_CLEAN_ROUTINGS))
IpNeighbourMonitor.registerCallback(this)
VpnMonitor.registerCallback(this)
receiverRegistered = true
}
}
active = routings.keys
postIpNeighbourAvailable()
app.handler.post { binder.fragment?.adapter?.notifyDataSetChanged() }
}
override fun onCreate() {
super.onCreate()
alive = true
}
override fun onBind(intent: Intent?) = binder
override fun onBind(intent: Intent?) = null
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
if (intent != null) { // otw service is recreated after being killed
val iface = intent.getStringExtra(EXTRA_ADD_INTERFACE)
if (iface != null) routings.put(iface, null)
if (routings.remove(intent.getStringExtra(EXTRA_REMOVE_INTERFACE))?.stop() == false)
Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
} else active.forEach { routings.put(it, null) }
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
val iface = intent.getStringExtra(EXTRA_ADD_INTERFACE)
if (iface != null) routings[iface] = null
if (routings.remove(intent.getStringExtra(EXTRA_REMOVE_INTERFACE))?.stop() == false)
Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
updateRoutings()
return START_STICKY
return START_NOT_STICKY
}
override fun onAvailable(ifname: String) {
@@ -107,9 +102,31 @@ class TetheringService : Service(), VpnMonitor.Callback {
if (failed) Toast.makeText(this, getText(R.string.noisy_su_failure), Toast.LENGTH_SHORT).show()
}
override fun onIpNeighbourAvailable(neighbours: Map<String, IpNeighbour>) {
this.neighbours = neighbours.values.toList()
}
override fun postIpNeighbourAvailable() {
val builder = NotificationCompat.Builder(this, CHANNEL)
.setWhen(0)
.setColor(ContextCompat.getColor(this, R.color.colorPrimary))
.setContentTitle("VPN tethering active")
.setSmallIcon(R.drawable.ic_device_wifi_tethering)
.setContentIntent(PendingIntent.getActivity(this, 0,
Intent(this, MainActivity::class.java), PendingIntent.FLAG_UPDATE_CURRENT))
.setVisibility(Notification.VISIBILITY_PUBLIC)
val content = neighbours.groupBy { it.dev }
.filter { (dev, _) -> routings.contains(dev) }
.mapValues { (_, neighbours) -> neighbours.size }
.toList()
.joinToString(", ") { (dev, size) ->
resources.getQuantityString(R.plurals.notification_connected_devices, size, size, dev)
}
if (content.isNotEmpty()) builder.setContentText(content)
startForeground(CHANNEL_ID, builder.build())
}
override fun onDestroy() {
unregisterReceiver()
alive = false
super.onDestroy()
}