Fix crashes
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user