Fix ANR caused by temp hotspot

Fixes #126.
This commit is contained in:
Mygod
2019-09-19 11:06:41 +08:00
parent 650b06beae
commit e2aeae9e2f
5 changed files with 39 additions and 26 deletions

View File

@@ -138,6 +138,7 @@ Non-public API list:
* (since API 24) [`Landroid/net/ConnectivityManager;->stopTethering(I)V,system-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#123410) * (since API 24) [`Landroid/net/ConnectivityManager;->stopTethering(I)V,system-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#123410)
* (since API 23) [`Landroid/net/wifi/WifiConfiguration;->apBand:I,greylist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#131529) * (since API 23) [`Landroid/net/wifi/WifiConfiguration;->apBand:I,greylist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#131529)
* (since API 23) [`Landroid/net/wifi/WifiConfiguration;->apChannel:I,greylist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#131530) * (since API 23) [`Landroid/net/wifi/WifiConfiguration;->apChannel:I,greylist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#131530)
* (since API 26) [`Landroid/net/wifi/WifiManager;->cancelLocalOnlyHotspotRequest()V,greylist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#132250)
* [`Landroid/net/wifi/WifiManager;->getWifiApConfiguration()Landroid/net/wifi/WifiConfiguration;,system-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#132289) * [`Landroid/net/wifi/WifiManager;->getWifiApConfiguration()Landroid/net/wifi/WifiConfiguration;,system-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#132289)
* [`Landroid/net/wifi/WifiManager;->setWifiApConfiguration(Landroid/net/wifi/WifiConfiguration;)Z,system-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#132358) * [`Landroid/net/wifi/WifiManager;->setWifiApConfiguration(Landroid/net/wifi/WifiConfiguration;)Z,system-api,whitelist`](https://android.googlesource.com/platform/prebuilts/runtime/+/3d07e5c/appcompat/hiddenapi-flags.csv#132358)
* (deprecated since API 26) `Landroid/net/wifi/WifiManager;->setWifiApEnabled(Landroid/net/wifi/WifiConfiguration;Z)Z` * (deprecated since API 26) `Landroid/net/wifi/WifiManager;->setWifiApEnabled(Landroid/net/wifi/WifiConfiguration;Z)Z`

View File

@@ -13,6 +13,7 @@ import be.mygod.vpnhotspot.net.TetheringManager
import be.mygod.vpnhotspot.net.TetheringManager.localOnlyTetheredIfaces import be.mygod.vpnhotspot.net.TetheringManager.localOnlyTetheredIfaces
import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor import be.mygod.vpnhotspot.net.monitor.IpNeighbourMonitor
import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor import be.mygod.vpnhotspot.net.monitor.TetherTimeoutMonitor
import be.mygod.vpnhotspot.net.wifi.WifiApManager
import be.mygod.vpnhotspot.util.StickyEvent1 import be.mygod.vpnhotspot.util.StickyEvent1
import be.mygod.vpnhotspot.util.broadcastReceiver import be.mygod.vpnhotspot.util.broadcastReceiver
import be.mygod.vpnhotspot.widget.SmartSnackbar import be.mygod.vpnhotspot.widget.SmartSnackbar
@@ -38,7 +39,17 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService(), CoroutineScope {
val configuration get() = reservation?.wifiConfiguration val configuration get() = reservation?.wifiConfiguration
fun stop() = reservation?.close() fun stop() = when (iface) {
null -> { } // stopped
"" -> {
WifiApManager.cancelLocalOnlyHotspotRequest()
reservation?.close()
updateNotification()
stopService()
iface = null
}
else -> reservation!!.close()
}
} }
private val binder = Binder() private val binder = Binder()
@@ -59,11 +70,7 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService(), CoroutineScope {
check(ifaces.size <= 1) check(ifaces.size <= 1)
val iface = ifaces.singleOrNull() val iface = ifaces.singleOrNull()
binder.iface = iface binder.iface = iface
if (iface.isNullOrEmpty()) { if (iface.isNullOrEmpty()) stopService() else launch {
unregisterReceiver()
ServiceNotification.stopForeground(this)
stopSelf()
} else launch {
val routingManager = routingManager val routingManager = routingManager
if (routingManager == null) { if (routingManager == null) {
this@LocalOnlyHotspotService.routingManager = RoutingManager.LocalOnly(this@LocalOnlyHotspotService, this@LocalOnlyHotspotService.routingManager = RoutingManager.LocalOnly(this@LocalOnlyHotspotService,
@@ -72,7 +79,7 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService(), CoroutineScope {
} else check(iface == routingManager.downstream) } else check(iface == routingManager.downstream)
} }
} }
override val activeIfaces get() = listOfNotNull(binder.iface) override val activeIfaces get() = binder.iface.let { if (it.isNullOrEmpty()) emptyList() else listOf(it) }
override fun onBind(intent: Intent?) = binder override fun onBind(intent: Intent?) = binder
@@ -80,7 +87,9 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService(), CoroutineScope {
if (binder.iface != null) return START_STICKY if (binder.iface != null) return START_STICKY
binder.iface = "" binder.iface = ""
// show invisible foreground notification on television to avoid being killed // show invisible foreground notification on television to avoid being killed
if (app.uiMode.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION) updateNotification() // or for bug with airplane mode on API 28-: https://issuetracker.google.com/issues/128350148
if (app.uiMode.currentModeType == Configuration.UI_MODE_TYPE_TELEVISION ||
Build.VERSION.SDK_INT < 29) updateNotification()
// throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they // throws IllegalStateException if the caller attempts to start the LocalOnlyHotspot while they
// have an outstanding request. // have an outstanding request.
// https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/53e0284/service/java/com/android/server/wifi/WifiServiceImpl.java#1192 // https://android.googlesource.com/platform/frameworks/opt/net/wifi/+/53e0284/service/java/com/android/server/wifi/WifiServiceImpl.java#1192
@@ -147,6 +156,12 @@ class LocalOnlyHotspotService : IpNeighbourMonitoringService(), CoroutineScope {
super.onDestroy() super.onDestroy()
} }
private fun stopService() {
unregisterReceiver()
ServiceNotification.stopForeground(this)
stopSelf()
}
private fun unregisterReceiver(exit: Boolean = false) { private fun unregisterReceiver(exit: Boolean = false) {
if (receiverRegistered) { if (receiverRegistered) {
unregisterReceiver(receiver) unregisterReceiver(receiver)

View File

@@ -79,7 +79,6 @@ class LocalOnlyHotspotManager(private val parent: TetheringFragment) : Manager()
return lookup[binder?.iface ?: return ""]?.formatAddresses() ?: "" return lookup[binder?.iface ?: return ""]?.formatAddresses() ?: ""
} }
override val active get() = binder?.iface != null override val active get() = binder?.iface != null
override val enabled get() = binder?.iface != ""
override val selectable get() = active override val selectable get() = active
} }

View File

@@ -31,10 +31,10 @@ class LocalOnlyHotspotTileService : KillableTileService() {
override fun onClick() { override fun onClick() {
val binder = binder val binder = binder
if (binder == null) tapPending = true when {
else when (binder.iface) { binder == null -> tapPending = true
null -> ContextCompat.startForegroundService(this, Intent(this, LocalOnlyHotspotService::class.java)) binder.iface == null -> ContextCompat.startForegroundService(this,
"" -> { } // STARTING, ignored Intent(this, LocalOnlyHotspotService::class.java))
else -> binder.stop() else -> binder.stop()
} }
} }
@@ -44,20 +44,13 @@ class LocalOnlyHotspotTileService : KillableTileService() {
service.ifaceChanged[this] = { service.ifaceChanged[this] = {
qsTile?.run { qsTile?.run {
icon = tile icon = tile
when (it) { if (it.isNullOrEmpty()) {
null -> {
state = Tile.STATE_INACTIVE state = Tile.STATE_INACTIVE
label = getText(R.string.tethering_temp_hotspot) label = getText(R.string.tethering_temp_hotspot)
} } else {
"" -> {
state = Tile.STATE_UNAVAILABLE
label = getText(R.string.tethering_temp_hotspot)
}
else -> {
state = Tile.STATE_ACTIVE state = Tile.STATE_ACTIVE
label = service.configuration?.SSID ?: getText(R.string.tethering_temp_hotspot) label = service.configuration?.SSID ?: getText(R.string.tethering_temp_hotspot)
} }
}
updateTile() updateTile()
} }
} }

View File

@@ -17,6 +17,11 @@ object WifiApManager {
} }
} }
private val cancelLocalOnlyHotspotRequest by lazy {
WifiManager::class.java.getDeclaredMethod("cancelLocalOnlyHotspotRequest")
}
fun cancelLocalOnlyHotspotRequest() = cancelLocalOnlyHotspotRequest.invoke(app.wifi)
private val setWifiApEnabled by lazy { private val setWifiApEnabled by lazy {
WifiManager::class.java.getDeclaredMethod("setWifiApEnabled", WifiManager::class.java.getDeclaredMethod("setWifiApEnabled",
WifiConfiguration::class.java, Boolean::class.java) WifiConfiguration::class.java, Boolean::class.java)