Merge branch 'master' into temp-hotspot-use-system
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package be.mygod.vpnhotspot.root
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.os.Parcelable
|
||||
import android.os.RemoteException
|
||||
import android.provider.Settings
|
||||
@@ -30,18 +29,10 @@ fun ProcessBuilder.fixPath(redirect: Boolean = false) = apply {
|
||||
|
||||
@Parcelize
|
||||
data class Dump(val path: String, val cacheDir: File = app.deviceStorage.codeCacheDir) : RootCommandNoResult {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
override suspend fun execute() = withContext(Dispatchers.IO) {
|
||||
FileOutputStream(path, true).use { out ->
|
||||
val process = ProcessBuilder("sh").fixPath(true).start()
|
||||
process.outputStream.bufferedWriter().use { commands ->
|
||||
// https://android.googlesource.com/platform/external/iptables/+/android-7.0.0_r1/iptables/Android.mk#34
|
||||
val iptablesSave = if (Build.VERSION.SDK_INT < 24) File(cacheDir, "iptables-save").absolutePath.also {
|
||||
commands.appendLine("ln -sf /system/bin/iptables $it")
|
||||
} else "iptables-save"
|
||||
val ip6tablesSave = if (Build.VERSION.SDK_INT < 24) File(cacheDir, "ip6tables-save").absolutePath.also {
|
||||
commands.appendLine("ln -sf /system/bin/ip6tables $it")
|
||||
} else "ip6tables-save"
|
||||
commands.appendLine("""
|
||||
|echo dumpsys ${Context.WIFI_P2P_SERVICE}
|
||||
|dumpsys ${Context.WIFI_P2P_SERVICE}
|
||||
@@ -50,13 +41,13 @@ data class Dump(val path: String, val cacheDir: File = app.deviceStorage.codeCac
|
||||
|dumpsys ${Context.CONNECTIVITY_SERVICE} tethering
|
||||
|echo
|
||||
|echo iptables -t filter
|
||||
|$iptablesSave -t filter
|
||||
|iptables-save -t filter
|
||||
|echo
|
||||
|echo iptables -t nat
|
||||
|$iptablesSave -t nat
|
||||
|iptables-save -t nat
|
||||
|echo
|
||||
|echo ip6tables-save
|
||||
|$ip6tablesSave
|
||||
|ip6tables-save
|
||||
|echo
|
||||
|echo ip rule
|
||||
|$IP rule
|
||||
@@ -125,7 +116,7 @@ class ProcessListener(private val terminateRegex: Regex,
|
||||
parent.join()
|
||||
} finally {
|
||||
parent.cancel()
|
||||
if (Build.VERSION.SDK_INT < 26) process.destroy() else if (process.isAlive) process.destroyForcibly()
|
||||
if (process.isAlive) process.destroyForcibly()
|
||||
parent.join()
|
||||
}
|
||||
}
|
||||
@@ -162,7 +153,6 @@ data class StartTethering(private val type: Int,
|
||||
|
||||
@Deprecated("Old API since API 30")
|
||||
@Parcelize
|
||||
@RequiresApi(24)
|
||||
@Suppress("DEPRECATION")
|
||||
data class StartTetheringLegacy(private val cacheDir: File, private val type: Int,
|
||||
private val showProvisioningUi: Boolean) : RootCommand<ParcelableBoolean> {
|
||||
@@ -184,7 +174,6 @@ data class StartTetheringLegacy(private val cacheDir: File, private val type: In
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
@RequiresApi(24)
|
||||
data class StopTethering(private val type: Int) : RootCommandNoResult {
|
||||
override suspend fun execute(): Parcelable? {
|
||||
TetheringManager.stopTethering(type)
|
||||
@@ -209,12 +198,11 @@ data class SettingsGlobalPut(val name: String, val value: String) : RootCommandN
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
override suspend fun execute() = withContext(Dispatchers.IO) {
|
||||
val process = ProcessBuilder("settings", "put", "global", name, value).fixPath(true).start()
|
||||
val error = process.inputStream.bufferedReader().readText()
|
||||
check(process.waitFor() == 0)
|
||||
if (error.isNotEmpty()) throw RemoteException(error)
|
||||
val exit = process.waitFor()
|
||||
if (exit != 0 || error.isNotEmpty()) throw RemoteException("Process exited with $exit: $error")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package be.mygod.vpnhotspot.root
|
||||
|
||||
import android.net.MacAddress
|
||||
import android.net.wifi.ScanResult
|
||||
import android.net.wifi.p2p.WifiP2pManager
|
||||
import android.os.Looper
|
||||
import android.os.Parcelable
|
||||
@@ -11,6 +13,7 @@ import be.mygod.librootkotlinx.*
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.deletePersistentGroup
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestDeviceAddress
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.requestPersistentGroupInfo
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setVendorElements
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiP2pManagerHelper.setWifiP2pChannels
|
||||
import be.mygod.vpnhotspot.util.Services
|
||||
import kotlinx.parcelize.Parcelize
|
||||
@@ -35,10 +38,8 @@ object RepeaterCommands {
|
||||
|
||||
@Parcelize
|
||||
@RequiresApi(29)
|
||||
class RequestDeviceAddress : RootCommand<ParcelableLong?> {
|
||||
override suspend fun execute() = Services.p2p!!.run {
|
||||
requestDeviceAddress(obtainChannel())?.let { ParcelableLong(it.addr) }
|
||||
}
|
||||
class RequestDeviceAddress : RootCommand<MacAddress?> {
|
||||
override suspend fun execute() = Services.p2p!!.run { requestDeviceAddress(obtainChannel()) }
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
@@ -55,6 +56,14 @@ object RepeaterCommands {
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
@RequiresApi(33)
|
||||
data class SetVendorElements(private val ve: List<ScanResult.InformationElement>) : RootCommand<ParcelableInt?> {
|
||||
override suspend fun execute() = Services.p2p!!.run {
|
||||
setVendorElements(obtainChannel(), ve)?.let { ParcelableInt(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class WriteP2pConfig(val data: String, val legacy: Boolean) : RootCommandNoResult {
|
||||
override suspend fun execute(): Parcelable? {
|
||||
|
||||
@@ -6,6 +6,8 @@ import android.util.Log
|
||||
import be.mygod.librootkotlinx.*
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.util.Services
|
||||
import be.mygod.vpnhotspot.util.UnblockCentral
|
||||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
|
||||
@@ -31,6 +33,7 @@ object RootManager : RootSession(), Logger {
|
||||
})
|
||||
Logger.me = RootManager
|
||||
Services.init { systemContext }
|
||||
UnblockCentral.needInit = false
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -42,7 +45,10 @@ object RootManager : RootSession(), Logger {
|
||||
|
||||
override suspend fun initServer(server: RootServer) {
|
||||
Logger.me = this
|
||||
server.init(app.deviceStorage)
|
||||
AppProcess.shouldRelocateHeuristics.let {
|
||||
FirebaseCrashlytics.getInstance().setCustomKey("RootManager.relocateEnabled", it)
|
||||
server.init(app.deviceStorage, it)
|
||||
}
|
||||
server.execute(RootInit())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package be.mygod.vpnhotspot.root
|
||||
|
||||
import android.os.Parcelable
|
||||
import be.mygod.librootkotlinx.RootCommand
|
||||
import be.mygod.librootkotlinx.RootCommandOneWay
|
||||
import be.mygod.librootkotlinx.RootCommandNoResult
|
||||
import be.mygod.vpnhotspot.net.Routing
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
@@ -13,8 +13,7 @@ import timber.log.Timber
|
||||
|
||||
object RoutingCommands {
|
||||
@Parcelize
|
||||
class Clean : RootCommandOneWay {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
class Clean : RootCommandNoResult {
|
||||
override suspend fun execute() = withContext(Dispatchers.IO) {
|
||||
val process = ProcessBuilder("sh").fixPath(true).start()
|
||||
process.outputStream.bufferedWriter().use(Routing.Companion::appendCleanCommands)
|
||||
@@ -23,6 +22,7 @@ object RoutingCommands {
|
||||
else -> Timber.w("Unexpected exit code $code")
|
||||
}
|
||||
check(process.waitFor() == 0)
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,19 @@
|
||||
package be.mygod.vpnhotspot.root
|
||||
|
||||
import android.annotation.TargetApi
|
||||
import android.content.ClipData
|
||||
import android.net.wifi.SoftApConfiguration
|
||||
import android.net.wifi.WifiManager
|
||||
import android.os.Build
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.RequiresApi
|
||||
import be.mygod.librootkotlinx.ParcelableBoolean
|
||||
import be.mygod.librootkotlinx.RootCommand
|
||||
import be.mygod.librootkotlinx.RootCommandChannel
|
||||
import be.mygod.vpnhotspot.net.wifi.SoftApConfigurationCompat
|
||||
import be.mygod.vpnhotspot.App.Companion.app
|
||||
import be.mygod.vpnhotspot.R
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiApManager
|
||||
import be.mygod.vpnhotspot.net.wifi.WifiClient
|
||||
import be.mygod.vpnhotspot.widget.SmartSnackbar
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.*
|
||||
@@ -15,7 +21,6 @@ import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
|
||||
object WifiApCommands {
|
||||
@RequiresApi(28)
|
||||
sealed class SoftApCallbackParcel : Parcelable {
|
||||
abstract fun dispatch(callback: WifiApManager.SoftApCallbackCompat)
|
||||
|
||||
@@ -55,7 +60,6 @@ object WifiApCommands {
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
@RequiresApi(28)
|
||||
class RegisterSoftApCallback : RootCommandChannel<SoftApCallbackParcel> {
|
||||
override fun create(scope: CoroutineScope) = scope.produce(capacity = capacity) {
|
||||
val finish = CompletableDeferred<Unit>()
|
||||
@@ -111,7 +115,6 @@ object WifiApCommands {
|
||||
private val callbacks = mutableSetOf<WifiApManager.SoftApCallbackCompat>()
|
||||
private val lastCallback = AutoFiringCallbacks()
|
||||
private var rootCallbackJob: Job? = null
|
||||
@RequiresApi(28)
|
||||
private suspend fun handleChannel(channel: ReceiveChannel<SoftApCallbackParcel>) = channel.consumeEach { parcel ->
|
||||
when (parcel) {
|
||||
is SoftApCallbackParcel.OnStateChanged -> synchronized(callbacks) { lastCallback.state = parcel }
|
||||
@@ -121,10 +124,22 @@ object WifiApCommands {
|
||||
}
|
||||
is SoftApCallbackParcel.OnInfoChanged -> synchronized(callbacks) { lastCallback.info = parcel }
|
||||
is SoftApCallbackParcel.OnCapabilityChanged -> synchronized(callbacks) { lastCallback.capability = parcel }
|
||||
is SoftApCallbackParcel.OnBlockedClientConnecting -> @TargetApi(30) { // passively consume events
|
||||
val client = WifiClient(parcel.client)
|
||||
val macAddress = client.macAddress
|
||||
var name = macAddress.toString()
|
||||
if (Build.VERSION.SDK_INT >= 31) client.apInstanceIdentifier?.let { name += "%$it" }
|
||||
val reason = WifiApManager.clientBlockLookup(parcel.blockedReason, true)
|
||||
Timber.i("$name blocked from connecting: $reason (${parcel.blockedReason})")
|
||||
SmartSnackbar.make(app.getString(R.string.tethering_manage_wifi_client_blocked, name, reason)).apply {
|
||||
action(R.string.tethering_manage_wifi_copy_mac) {
|
||||
app.clipboard.setPrimaryClip(ClipData.newPlainText(null, macAddress.toString()))
|
||||
}
|
||||
}.show()
|
||||
}
|
||||
}
|
||||
for (callback in synchronized(callbacks) { callbacks.toList() }) parcel.dispatch(callback)
|
||||
}
|
||||
@RequiresApi(28)
|
||||
fun registerSoftApCallback(callback: WifiApManager.SoftApCallbackCompat) = synchronized(callbacks) {
|
||||
val wasEmpty = callbacks.isEmpty()
|
||||
callbacks.add(callback)
|
||||
@@ -141,7 +156,6 @@ object WifiApCommands {
|
||||
null
|
||||
} else lastCallback
|
||||
}?.toSequence()?.forEach { it?.dispatch(callback) }
|
||||
@RequiresApi(28)
|
||||
fun unregisterSoftApCallback(callback: WifiApManager.SoftApCallbackCompat) = synchronized(callbacks) {
|
||||
if (callbacks.remove(callback) && callbacks.isEmpty()) {
|
||||
rootCallbackJob!!.cancel()
|
||||
@@ -150,13 +164,29 @@ object WifiApCommands {
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
class GetConfiguration : RootCommand<SoftApConfigurationCompat> {
|
||||
override suspend fun execute() = WifiApManager.configurationCompat
|
||||
@Deprecated("Use GetConfiguration instead", ReplaceWith("GetConfiguration"))
|
||||
@Suppress("DEPRECATION")
|
||||
class GetConfigurationLegacy : RootCommand<android.net.wifi.WifiConfiguration?> {
|
||||
override suspend fun execute() = WifiApManager.configurationLegacy
|
||||
}
|
||||
@Parcelize
|
||||
@RequiresApi(30)
|
||||
class GetConfiguration : RootCommand<SoftApConfiguration> {
|
||||
override suspend fun execute() = WifiApManager.configuration
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class SetConfiguration(val configuration: SoftApConfigurationCompat) : RootCommand<ParcelableBoolean> {
|
||||
override suspend fun execute() = ParcelableBoolean(WifiApManager.setConfigurationCompat(configuration))
|
||||
@Deprecated("Use SetConfiguration instead", ReplaceWith("SetConfiguration"))
|
||||
@Suppress("DEPRECATION")
|
||||
data class SetConfigurationLegacy(
|
||||
val configuration: android.net.wifi.WifiConfiguration?,
|
||||
) : RootCommand<ParcelableBoolean> {
|
||||
override suspend fun execute() = ParcelableBoolean(WifiApManager.setConfiguration(configuration))
|
||||
}
|
||||
@Parcelize
|
||||
@RequiresApi(30)
|
||||
data class SetConfiguration(val configuration: SoftApConfiguration) : RootCommand<ParcelableBoolean> {
|
||||
override suspend fun execute() = ParcelableBoolean(WifiApManager.setConfiguration(configuration))
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
|
||||
Reference in New Issue
Block a user