Fix crash on Android 7-

This commit is contained in:
Mygod
2018-01-13 19:05:23 +08:00
parent 5fb6f8f347
commit f6a5ed9d64
3 changed files with 37 additions and 25 deletions

View File

@@ -1,19 +1,31 @@
package be.mygod.vpnhotspot
import android.net.ConnectivityManager
import android.os.Build
import android.os.Bundle
import android.support.annotation.RequiresApi
import java.io.File
object NetUtils {
// hidden constants from ConnectivityManager
/**
* This is a sticky broadcast since almost forever.
*
* https://android.googlesource.com/platform/frameworks/base.git/+/2a091d7aa0c174986387e5d56bf97a87fe075bdb%5E%21/services/java/com/android/server/connectivity/Tethering.java
*/
const val ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"
const val EXTRA_ACTIVE_TETHER = "tetherArray"
@Deprecated("No longer used on Android 8+ (API 26+)")
private const val EXTRA_ACTIVE_TETHER_LEGACY = "activeArray"
@RequiresApi(26)
private const val EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray"
@RequiresApi(26)
private const val EXTRA_ACTIVE_TETHER = "tetherArray"
private val spaces = " +".toPattern()
private val mac = "^([0-9a-f]{2}:){5}[0-9a-f]{2}$".toPattern()
private val getTetheredIfaces = ConnectivityManager::class.java.getDeclaredMethod("getTetheredIfaces")
@Suppress("UNCHECKED_CAST")
val ConnectivityManager.tetheredIfaces get() = getTetheredIfaces.invoke(this) as Array<String>
fun getTetheredIfaces(extras: Bundle) = if (Build.VERSION.SDK_INT >= 26)
extras.getStringArrayList(EXTRA_ACTIVE_TETHER).toSet() + extras.getStringArrayList(EXTRA_ACTIVE_LOCAL_ONLY)
else extras.getStringArrayList(EXTRA_ACTIVE_TETHER_LEGACY).toSet()
fun arp(iface: String? = null) = File("/proc/net/arp").bufferedReader().useLines {
// IP address HW type Flags HW address Mask Device

View File

@@ -18,7 +18,6 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.NetUtils.tetheredIfaces
import be.mygod.vpnhotspot.databinding.FragmentTetheringBinding
import be.mygod.vpnhotspot.databinding.ListitemInterfaceBinding
import be.mygod.vpnhotspot.widget.TextViewLinkHandler
@@ -86,7 +85,7 @@ class TetheringFragment : Fragment() {
inner class InterfaceAdapter : RecyclerView.Adapter<InterfaceViewHolder>() {
private val tethered = SortedList(String::class.java, StringSorter)
fun update(data: Set<String> = VpnListener.connectivityManager.tetheredIfaces.toSet()) {
fun update(data: Set<String>) {
val oldEmpty = tethered.size() == 0
tethered.clear()
tethered.addAll(data)
@@ -109,8 +108,7 @@ class TetheringFragment : Fragment() {
private val receiver = broadcastReceiver { _, intent ->
when (intent.action) {
TetheringService.ACTION_ACTIVE_INTERFACES_CHANGED -> adapter.notifyDataSetChanged()
NetUtils.ACTION_TETHER_STATE_CHANGED ->
adapter.update(intent.extras.getStringArrayList(NetUtils.EXTRA_ACTIVE_TETHER).toSet())
NetUtils.ACTION_TETHER_STATE_CHANGED -> adapter.update(NetUtils.getTetheredIfaces(intent.extras).toSet())
}
}
private var receiverRegistered = false
@@ -133,7 +131,6 @@ class TetheringFragment : Fragment() {
override fun onStart() {
super.onStart()
if (!receiverRegistered) {
adapter.update()
val context = context!!
context.registerReceiver(receiver, intentFilter(NetUtils.ACTION_TETHER_STATE_CHANGED))
LocalBroadcastManager.getInstance(context)

View File

@@ -4,7 +4,6 @@ import android.app.Service
import android.content.Intent
import android.support.v4.content.LocalBroadcastManager
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.NetUtils.tetheredIfaces
class TetheringService : Service(), VpnListener.Callback {
companion object {
@@ -25,7 +24,7 @@ class TetheringService : Service(), VpnListener.Callback {
private var upstream: String? = null
private var receiverRegistered = false
private val receiver = broadcastReceiver { _, intent ->
val remove = routings.keys - intent.extras.getStringArrayList(NetUtils.EXTRA_ACTIVE_TETHER).toSet()
val remove = routings.keys - NetUtils.getTetheredIfaces(intent.extras)
if (remove.isEmpty()) return@broadcastReceiver
for (iface in remove) routings.remove(iface)?.stop()
updateRoutings()
@@ -34,12 +33,7 @@ class TetheringService : Service(), VpnListener.Callback {
private fun updateRoutings() {
active = routings.keys
if (routings.isEmpty()) {
if (receiverRegistered) {
unregisterReceiver(receiver)
VpnListener.unregisterCallback(this)
upstream = null
receiverRegistered = false
}
unregisterReceiver()
stopSelf()
} else {
val upstream = upstream
@@ -61,14 +55,9 @@ class TetheringService : Service(), VpnListener.Callback {
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 && VpnListener.connectivityManager.tetheredIfaces.contains(iface))
routings.put(iface, null)
if (iface != null) routings.put(iface, null)
routings.remove(intent.getStringExtra(EXTRA_REMOVE_INTERFACE))?.stop()
} else {
val active = active
if (active.isNotEmpty()) active.intersect(VpnListener.connectivityManager.tetheredIfaces.asIterable())
.forEach { routings.put(it, null) }
}
} else active.forEach { routings.put(it, null) }
updateRoutings()
return START_STICKY
}
@@ -87,4 +76,18 @@ class TetheringService : Service(), VpnListener.Callback {
routings[iface] = null
}
}
override fun onDestroy() {
unregisterReceiver()
super.onDestroy()
}
fun unregisterReceiver() {
if (receiverRegistered) {
unregisterReceiver(receiver)
VpnListener.unregisterCallback(this)
upstream = null
receiverRegistered = false
}
}
}