Fix crashes
This commit is contained in:
@@ -193,13 +193,14 @@ class RootServer @JvmOverloads constructor(private val warnLogger: (String) -> U
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
callbackSpin()
|
callbackSpin()
|
||||||
|
if (active) throw RemoteException("Root process exited unexpectedly")
|
||||||
} catch (e: Throwable) {
|
} catch (e: Throwable) {
|
||||||
process.destroy()
|
process.destroy()
|
||||||
throw e
|
throw e
|
||||||
} finally {
|
} finally {
|
||||||
if (DEBUG) Log.d(TAG, "Waiting for exit")
|
if (DEBUG) Log.d(TAG, "Waiting for exit")
|
||||||
process.waitFor()
|
process.waitFor()
|
||||||
closeInternal(true)
|
withContext(NonCancellable) { closeInternal(true) }
|
||||||
}
|
}
|
||||||
check(process.errorStream.available() == 0) // stderr should not be used
|
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 {
|
private suspend fun closeInternal(fromWorker: Boolean = false) = mutex.withLock {
|
||||||
if (active) {
|
if (active) {
|
||||||
active = false
|
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 {
|
try {
|
||||||
sendLocked(Shutdown())
|
sendLocked(Shutdown())
|
||||||
output.close()
|
output.close()
|
||||||
|
|||||||
@@ -42,8 +42,9 @@ abstract class RootSession {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun closeLocked() {
|
private suspend fun closeLocked() {
|
||||||
|
val server = server
|
||||||
|
this.server = null
|
||||||
server?.close()
|
server?.close()
|
||||||
server = null
|
|
||||||
}
|
}
|
||||||
private fun startTimeoutLocked() {
|
private fun startTimeoutLocked() {
|
||||||
check(timeoutJob == null)
|
check(timeoutJob == null)
|
||||||
@@ -51,8 +52,8 @@ abstract class RootSession {
|
|||||||
delay(timeout)
|
delay(timeout)
|
||||||
mutex.withLock {
|
mutex.withLock {
|
||||||
check(usersCount == 0L)
|
check(usersCount == 0L)
|
||||||
closeLocked()
|
|
||||||
timeoutJob = null
|
timeoutJob = null
|
||||||
|
closeLocked()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,14 +76,14 @@ abstract class RootSession {
|
|||||||
when {
|
when {
|
||||||
!server.active -> {
|
!server.active -> {
|
||||||
usersCount = 0
|
usersCount = 0
|
||||||
closeLocked()
|
|
||||||
closePending = false
|
closePending = false
|
||||||
|
closeLocked()
|
||||||
return@withLock
|
return@withLock
|
||||||
}
|
}
|
||||||
--usersCount > 0L -> return@withLock
|
--usersCount > 0L -> return@withLock
|
||||||
closePending -> {
|
closePending -> {
|
||||||
closeLocked()
|
|
||||||
closePending = false
|
closePending = false
|
||||||
|
closeLocked()
|
||||||
}
|
}
|
||||||
else -> startTimeoutLocked()
|
else -> startTimeoutLocked()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ interface RootCommandChannel<T : Parcelable?> : Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
internal class CancelCommand(val index: Long) : RootCommandOneWay {
|
internal data class CancelCommand(val index: Long) : RootCommandOneWay {
|
||||||
override suspend fun execute() = error("Internal implementation")
|
override suspend fun execute() = error("Internal implementation")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ class App : Application() {
|
|||||||
} else {
|
} else {
|
||||||
if (priority >= Log.WARN || priority == Log.DEBUG) {
|
if (priority >= Log.WARN || priority == Log.DEBUG) {
|
||||||
Log.println(priority, tag, message)
|
Log.println(priority, tag, message)
|
||||||
Log.d(tag, message, t)
|
Log.w(tag, message, t)
|
||||||
}
|
}
|
||||||
if (priority >= Log.INFO && t !is NoShellException) {
|
if (priority >= Log.INFO && t !is NoShellException) {
|
||||||
FirebaseCrashlytics.getInstance().recordException(t)
|
FirebaseCrashlytics.getInstance().recordException(t)
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
set(value) = app.pref.edit { putString(KEY_PASSPHRASE, value) }
|
set(value) = app.pref.edit { putString(KEY_PASSPHRASE, value) }
|
||||||
var operatingBand: Int
|
var operatingBand: Int
|
||||||
@SuppressLint("InlinedApi")
|
@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) }
|
set(value) = app.pref.edit { putInt(KEY_OPERATING_BAND, value) }
|
||||||
var operatingChannel: Int
|
var operatingChannel: Int
|
||||||
get() {
|
get() {
|
||||||
@@ -366,11 +366,11 @@ class RepeaterService : Service(), CoroutineScope, WifiP2pManager.ChannelListene
|
|||||||
setNetworkName(PLACEHOLDER_NETWORK_NAME)
|
setNetworkName(PLACEHOLDER_NETWORK_NAME)
|
||||||
setPassphrase(passphrase)
|
setPassphrase(passphrase)
|
||||||
operatingChannel.let { oc ->
|
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_ANY -> WifiP2pConfig.GROUP_OWNER_BAND_AUTO
|
||||||
SoftApConfigurationCompat.BAND_2GHZ -> WifiP2pConfig.GROUP_OWNER_BAND_2GHZ
|
SoftApConfigurationCompat.BAND_2GHZ -> WifiP2pConfig.GROUP_OWNER_BAND_2GHZ
|
||||||
SoftApConfigurationCompat.BAND_5GHZ -> WifiP2pConfig.GROUP_OWNER_BAND_5GHZ
|
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))
|
else setGroupOperatingFrequency(SoftApConfigurationCompat.channelToFrequency(operatingBand, oc))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,7 +67,7 @@ enum class TetherType(@DrawableRes val icon: Int) {
|
|||||||
@RequiresApi(30)
|
@RequiresApi(30)
|
||||||
override fun onTetherableInterfaceRegexpsChanged(args: Array<out Any?>?) = synchronized(this) {
|
override fun onTetherableInterfaceRegexpsChanged(args: Array<out Any?>?) = synchronized(this) {
|
||||||
if (requiresUpdate) return@synchronized
|
if (requiresUpdate) return@synchronized
|
||||||
Timber.i("onTetherableInterfaceRegexpsChanged: ${args?.contentToString()}")
|
Timber.i("onTetherableInterfaceRegexpsChanged: ${args?.contentDeepToString()}")
|
||||||
TetheringManager.unregisterTetheringEventCallback(this)
|
TetheringManager.unregisterTetheringEventCallback(this)
|
||||||
requiresUpdate = true
|
requiresUpdate = true
|
||||||
listener()
|
listener()
|
||||||
|
|||||||
@@ -605,12 +605,12 @@ object TetheringManager {
|
|||||||
*/
|
*/
|
||||||
fun getLastTetherError(iface: String): Int = getLastTetherError(Services.connectivity, iface) as Int
|
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_NO_ERROR", "TETHER_ERROR_UNKNOWN_IFACE", "TETHER_ERROR_SERVICE_UNAVAIL",
|
||||||
"TETHER_ERROR_UNSUPPORTED", "TETHER_ERROR_UNAVAIL_IFACE", "TETHER_ERROR_MASTER_ERROR",
|
"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_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_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(
|
val Intent.tetheredIfaces get() = getStringArrayListExtra(
|
||||||
if (Build.VERSION.SDK_INT >= 26) EXTRA_ACTIVE_TETHER else EXTRA_ACTIVE_TETHER_LEGACY)
|
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 getFrequency by lazy { classSoftApInfo.getDeclaredMethod("getFrequency") }
|
||||||
private val getBandwidth by lazy { classSoftApInfo.getDeclaredMethod("getBandwidth") }
|
private val getBandwidth by lazy { classSoftApInfo.getDeclaredMethod("getBandwidth") }
|
||||||
@RequiresApi(30)
|
@RequiresApi(30)
|
||||||
val channelWidthLookup = ConstantLookup(classSoftApInfo, "CHANNEL_WIDTH_")
|
val channelWidthLookup = ConstantLookup("CHANNEL_WIDTH_") { classSoftApInfo }
|
||||||
const val CHANNEL_WIDTH_INVALID = 0
|
const val CHANNEL_WIDTH_INVALID = 0
|
||||||
|
|
||||||
private val classSoftApCapability by lazy { Class.forName("android.net.wifi.SoftApCapability") }
|
private val classSoftApCapability by lazy { Class.forName("android.net.wifi.SoftApCapability") }
|
||||||
@@ -125,15 +125,16 @@ object WifiApManager {
|
|||||||
private val areFeaturesSupported by lazy {
|
private val areFeaturesSupported by lazy {
|
||||||
classSoftApCapability.getDeclaredMethod("areFeaturesSupported", Long::class.java)
|
classSoftApCapability.getDeclaredMethod("areFeaturesSupported", Long::class.java)
|
||||||
}
|
}
|
||||||
@RequiresApi(30)
|
@get:RequiresApi(30)
|
||||||
val featureLookup = LongConstantLookup(classSoftApCapability, "SOFTAP_FEATURE_")
|
val featureLookup by lazy { LongConstantLookup(classSoftApCapability, "SOFTAP_FEATURE_") }
|
||||||
|
|
||||||
|
private val methods29 = setOf("onStateChanged", "onNumClientsChanged")
|
||||||
@RequiresApi(28)
|
@RequiresApi(28)
|
||||||
fun registerSoftApCallback(callback: SoftApCallbackCompat, executor: Executor): Any {
|
fun registerSoftApCallback(callback: SoftApCallbackCompat, executor: Executor): Any {
|
||||||
val proxy = Proxy.newProxyInstance(interfaceSoftApCallback.classLoader,
|
val proxy = Proxy.newProxyInstance(interfaceSoftApCallback.classLoader,
|
||||||
arrayOf(interfaceSoftApCallback), object : InvocationHandler {
|
arrayOf(interfaceSoftApCallback), object : InvocationHandler {
|
||||||
override fun invoke(proxy: Any, method: Method, args: Array<out Any?>?): Any? {
|
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) }
|
executor.execute { invokeActual(proxy, method, args) }
|
||||||
null // no return value as of API 30
|
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 be.mygod.vpnhotspot.R
|
||||||
import timber.log.Timber
|
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 {
|
private val lookup by lazy {
|
||||||
SparseArrayCompat<String>().apply {
|
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)
|
if (field.name.startsWith(prefix)) put(field.getInt(null), field.name)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.w(e)
|
Timber.w(e)
|
||||||
@@ -30,10 +31,11 @@ class ConstantLookup(private val clazz: Class<*>, private val prefix: String, pr
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("FunctionName")
|
@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")
|
@Suppress("FunctionName")
|
||||||
inline fun <reified T> ConstantLookup(prefix: String, vararg lookup29: String) =
|
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) {
|
class LongConstantLookup(private val clazz: Class<*>, private val prefix: String) {
|
||||||
private val lookup = LongSparseArray<String>().apply {
|
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.App.Companion.app
|
||||||
import be.mygod.vpnhotspot.net.MacAddressCompat
|
import be.mygod.vpnhotspot.net.MacAddressCompat
|
||||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||||
|
import timber.log.Timber
|
||||||
import java.lang.invoke.MethodHandles
|
import java.lang.invoke.MethodHandles
|
||||||
import java.lang.reflect.InvocationHandler
|
import java.lang.reflect.InvocationHandler
|
||||||
import java.lang.reflect.InvocationTargetException
|
import java.lang.reflect.InvocationTargetException
|
||||||
@@ -134,12 +135,15 @@ private val newLookup by lazy @TargetApi(26) {
|
|||||||
*
|
*
|
||||||
* See also: https://stackoverflow.com/a/49532463/2245107
|
* See also: https://stackoverflow.com/a/49532463/2245107
|
||||||
*/
|
*/
|
||||||
fun InvocationHandler.callSuper(interfaceClass: Class<*>, proxy: Any, method: Method, args: Array<out Any?>?) = when {
|
fun InvocationHandler.callSuper(interfaceClass: Class<*>, proxy: Any, method: Method, args: Array<out Any?>?): Any? {
|
||||||
Build.VERSION.SDK_INT >= 26 -> newLookup.newInstance(interfaceClass, 0xf) // ALL_MODES
|
return if (Build.VERSION.SDK_INT >= 26 && method.isDefault) newLookup.newInstance(interfaceClass, 0xf) // ALL_MODES
|
||||||
.`in`(interfaceClass).unreflectSpecial(method, interfaceClass).bindTo(proxy).run {
|
.`in`(interfaceClass).unreflectSpecial(method, interfaceClass).bindTo(proxy).run {
|
||||||
if (args == null) invokeWithArguments() else invokeWithArguments(*args)
|
if (args == null) invokeWithArguments() else invokeWithArguments(*args)
|
||||||
}
|
} else if (method.declaringClass === Object::class.java) {
|
||||||
// only Java 8+ has default interface methods; otherwise, we just redispatch it to InvocationHandler
|
// otherwise, we just redispatch it to InvocationHandler
|
||||||
args == null -> method(this)
|
if (args == null) method(this) else method(this, *args)
|
||||||
else -> method(this, *args)
|
} else {
|
||||||
|
Timber.w("Unhandled method: $method(${args?.contentDeepToString()})")
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user