Fix crashes

This commit is contained in:
Mygod
2020-07-03 10:55:21 +08:00
parent 4b1101f41e
commit 05c4ba5b81
10 changed files with 37 additions and 28 deletions

View File

@@ -193,13 +193,14 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
}
try {
callbackSpin()
if (active) throw RemoteException("Root process exited unexpectedly")
} catch (e: Throwable) {
process.destroy()
throw e
} finally {
if (DEBUG) Log.d(TAG, "Waiting for exit")
process.waitFor()
closeInternal(true)
withContext(NonCancellable) { closeInternal(true) }
}
check(process.errorStream.available() == 0) // stderr should not be used
}
@@ -280,7 +281,7 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
private suspend fun closeInternal(fromWorker: Boolean = false) = mutex.withLock {
if (active) {
active = false
if (DEBUG) Log.d(TAG, "Shutting down from client")
if (DEBUG) Log.d(TAG, if (fromWorker) "Shutting down from worker" else "Shutting down from client")
try {
sendLocked(Shutdown())
output.close()

View File

@@ -42,8 +42,9 @@ abstract class RootSession {
}
private suspend fun closeLocked() {
val server = server
this.server = null
server?.close()
server = null
}
private fun startTimeoutLocked() {
check(timeoutJob == null)
@@ -51,8 +52,8 @@ abstract class RootSession {
delay(timeout)
mutex.withLock {
check(usersCount == 0L)
closeLocked()
timeoutJob = null
closeLocked()
}
}
}
@@ -75,14 +76,14 @@ abstract class RootSession {
when {
!server.active -> {
usersCount = 0
closeLocked()
closePending = false
closeLocked()
return@withLock
}
--usersCount > 0L -> return@withLock
closePending -> {
closeLocked()
closePending = false
closeLocked()
}
else -> startTimeoutLocked()
}

View File

@@ -39,7 +39,7 @@ interface RootCommandChannel<T : Parcelable?> : Parcelable {
}
@Parcelize
internal class CancelCommand(val index: Long) : RootCommandOneWay {
internal data class CancelCommand(val index: Long) : RootCommandOneWay {
override suspend fun execute() = error("Internal implementation")
}

View File

@@ -68,7 +68,7 @@ class App : Application() {
} else {
if (priority >= Log.WARN || priority == Log.DEBUG) {
Log.println(priority, tag, message)
Log.d(tag, message, t)
Log.w(tag, message, t)
}
if (priority >= Log.INFO && t !is NoShellException) {
FirebaseCrashlytics.getInstance().recordException(t)

View File

@@ -76,7 +76,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
set(value) = app.pref.edit { putString(KEY_PASSPHRASE, value) }
var operatingBand: Int
@SuppressLint("InlinedApi")
get() = app.pref.getInt(KEY_OPERATING_BAND, WifiP2pConfig.GROUP_OWNER_BAND_AUTO)
get() = app.pref.getInt(KEY_OPERATING_BAND, SoftApConfigurationCompat.BAND_ANY)
set(value) = app.pref.edit { putInt(KEY_OPERATING_BAND, value) }
var operatingChannel: Int
get() {
@@ -366,11 +366,11 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
setNetworkName(PLACEHOLDER_NETWORK_NAME)
setPassphrase(passphrase)
operatingChannel.let { oc ->
if (oc == 0) setGroupOperatingBand(when (operatingBand) {
if (oc == 0) setGroupOperatingBand(when (val band = operatingBand) {
SoftApConfigurationCompat.BAND_ANY -> WifiP2pConfig.GROUP_OWNER_BAND_AUTO
SoftApConfigurationCompat.BAND_2GHZ -> WifiP2pConfig.GROUP_OWNER_BAND_2GHZ
SoftApConfigurationCompat.BAND_5GHZ -> WifiP2pConfig.GROUP_OWNER_BAND_5GHZ
else -> throw IllegalArgumentException("Unknown band")
else -> throw IllegalArgumentException("Unknown band $band")
})
else setGroupOperatingFrequency(SoftApConfigurationCompat.channelToFrequency(operatingBand, oc))
}

View File

@@ -67,7 +67,7 @@ enum class TetherType(@DrawableRes val icon: Int) {
@RequiresApi(30)
override fun onTetherableInterfaceRegexpsChanged(args: Array<out Any?>?) = synchronized(this) {
if (requiresUpdate) return@synchronized
Timber.i("onTetherableInterfaceRegexpsChanged: ${args?.contentToString()}")
Timber.i("onTetherableInterfaceRegexpsChanged: ${args?.contentDeepToString()}")
TetheringManager.unregisterTetheringEventCallback(this)
requiresUpdate = true
listener()

View File

@@ -605,12 +605,12 @@ object TetheringManager {
*/
fun getLastTetherError(iface: String): Int = getLastTetherError(Services.connectivity, iface) as Int
val tetherErrorLookup = ConstantLookup(clazz, "TETHER_ERROR_",
val tetherErrorLookup = ConstantLookup("TETHER_ERROR_",
"TETHER_ERROR_NO_ERROR", "TETHER_ERROR_UNKNOWN_IFACE", "TETHER_ERROR_SERVICE_UNAVAIL",
"TETHER_ERROR_UNSUPPORTED", "TETHER_ERROR_UNAVAIL_IFACE", "TETHER_ERROR_MASTER_ERROR",
"TETHER_ERROR_TETHER_IFACE_ERROR", "TETHER_ERROR_UNTETHER_IFACE_ERROR", "TETHER_ERROR_ENABLE_NAT_ERROR",
"TETHER_ERROR_DISABLE_NAT_ERROR", "TETHER_ERROR_IFACE_CFG_ERROR", "TETHER_ERROR_PROVISION_FAILED",
"TETHER_ERROR_DHCPSERVER_ERROR", "TETHER_ERROR_ENTITLEMENT_UNKNOWN")
"TETHER_ERROR_DHCPSERVER_ERROR", "TETHER_ERROR_ENTITLEMENT_UNKNOWN") { clazz }
val Intent.tetheredIfaces get() = getStringArrayListExtra(
if (Build.VERSION.SDK_INT >= 26) EXTRA_ACTIVE_TETHER else EXTRA_ACTIVE_TETHER_LEGACY)

View File

@@ -117,7 +117,7 @@ object WifiApManager {
private val getFrequency by lazy { classSoftApInfo.getDeclaredMethod("getFrequency") }
private val getBandwidth by lazy { classSoftApInfo.getDeclaredMethod("getBandwidth") }
@RequiresApi(30)
val channelWidthLookup = ConstantLookup(classSoftApInfo, "CHANNEL_WIDTH_")
val channelWidthLookup = ConstantLookup("CHANNEL_WIDTH_") { classSoftApInfo }
const val CHANNEL_WIDTH_INVALID = 0
private val classSoftApCapability by lazy { Class.forName("android.net.wifi.SoftApCapability") }
@@ -125,15 +125,16 @@ object WifiApManager {
private val areFeaturesSupported by lazy {
classSoftApCapability.getDeclaredMethod("areFeaturesSupported", Long::class.java)
}
@RequiresApi(30)
val featureLookup = LongConstantLookup(classSoftApCapability, "SOFTAP_FEATURE_")
@get:RequiresApi(30)
val featureLookup by lazy { LongConstantLookup(classSoftApCapability, "SOFTAP_FEATURE_") }
private val methods29 = setOf("onStateChanged", "onNumClientsChanged")
@RequiresApi(28)
fun registerSoftApCallback(callback: SoftApCallbackCompat, executor: Executor): Any {
val proxy = Proxy.newProxyInstance(interfaceSoftApCallback.classLoader,
arrayOf(interfaceSoftApCallback), object : InvocationHandler {
override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any? {
return if (Build.VERSION.SDK_INT >= 30) invokeActual(proxy, method, args) else {
return if (Build.VERSION.SDK_INT >= 30 || method.name !in methods29) invokeActual(proxy, method, args) else {
executor.execute { invokeActual(proxy, method, args) }
null // no return value as of API 30
}

View File

@@ -7,10 +7,11 @@ import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.R
import timber.log.Timber
class ConstantLookup(private val clazz: Class<*>, private val prefix: String, private val lookup29: Array<out String>) {
class ConstantLookup(private val prefix: String, private val lookup29: Array<out String>,
private val clazz: () -> Class<*>) {
private val lookup by lazy {
SparseArrayCompat<String>().apply {
for (field in clazz.declaredFields) try {
for (field in clazz().declaredFields) try {
if (field.name.startsWith(prefix)) put(field.getInt(null), field.name)
} catch (e: Exception) {
Timber.w(e)
@@ -30,10 +31,11 @@ class ConstantLookup(private val clazz: Class<*>, private val prefix: String, pr
}
@Suppress("FunctionName")
fun ConstantLookup(clazz: Class<*>, prefix: String, vararg lookup29: String) = ConstantLookup(clazz, prefix, lookup29)
fun ConstantLookup(prefix: String, vararg lookup29: String, clazz: () -> Class<*>) =
ConstantLookup(prefix, lookup29, clazz)
@Suppress("FunctionName")
inline fun <reified T> ConstantLookup(prefix: String, vararg lookup29: String) =
ConstantLookup(T::class.java, prefix, lookup29)
ConstantLookup(prefix, lookup29) { T::class.java }
class LongConstantLookup(private val clazz: Class<*>, private val prefix: String) {
private val lookup = LongSparseArray<String>().apply {

View File

@@ -22,6 +22,7 @@ import androidx.fragment.app.FragmentManager
import be.mygod.vpnhotspot.App.Companion.app
import be.mygod.vpnhotspot.net.MacAddressCompat
import be.mygod.vpnhotspot.widget.SmartSnackbar
import timber.log.Timber
import java.lang.invoke.MethodHandles
import java.lang.reflect.InvocationHandler
import java.lang.reflect.InvocationTargetException
@@ -134,12 +135,15 @@ private val newLookup by lazy @TargetApi(26) {
*
* See also: https://stackoverflow.com/a/49532463/2245107
*/
fun InvocationHandler.callSuper(interfaceClass: Class<*>, proxy: Any, method: Method, args: Array<out Any?>?) = when {
Build.VERSION.SDK_INT >= 26 -> newLookup.newInstance(interfaceClass, 0xf) // ALL_MODES
fun InvocationHandler.callSuper(interfaceClass: Class<*>, proxy: Any, method: Method, args: Array<out Any?>?): Any? {
return if (Build.VERSION.SDK_INT >= 26 && method.isDefault) newLookup.newInstance(interfaceClass, 0xf) // ALL_MODES
.`in`(interfaceClass).unreflectSpecial(method, interfaceClass).bindTo(proxy).run {
if (args == null) invokeWithArguments() else invokeWithArguments(*args)
}
// only Java 8+ has default interface methods; otherwise, we just redispatch it to InvocationHandler
args == null -> method(this)
else -> method(this, *args)
} else if (method.declaringClass === Object::class.java) {
// otherwise, we just redispatch it to InvocationHandler
if (args == null) method(this) else method(this, *args)
} else {
Timber.w("Unhandled method: $method(${args?.contentDeepToString()})")
null
}
}