Fix per-app proxy managed mode
This commit is contained in:
@@ -3,14 +3,11 @@ package io.nekohasekai.sfa.bg
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import io.nekohasekai.sfa.R
|
||||
import io.nekohasekai.sfa.compose.screen.profileoverride.PerAppProxyScanner
|
||||
import io.nekohasekai.sfa.database.Settings
|
||||
import io.nekohasekai.sfa.vendor.PackageQueryManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -48,29 +45,7 @@ class AppChangeReceiver : BroadcastReceiver() {
|
||||
|
||||
private suspend fun rescanAllApps() {
|
||||
Log.d(TAG, "rescanning all apps")
|
||||
val packageManagerFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES or
|
||||
PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or
|
||||
PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES or
|
||||
PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or
|
||||
PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
|
||||
}
|
||||
val retryFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES or PackageManager.GET_PERMISSIONS
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES or PackageManager.GET_PERMISSIONS
|
||||
}
|
||||
val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags, retryFlags)
|
||||
val chinaApps = mutableSetOf<String>()
|
||||
for (packageInfo in installedPackages) {
|
||||
if (PerAppProxyScanner.scanChinaPackage(packageInfo)) {
|
||||
chinaApps.add(packageInfo.packageName)
|
||||
}
|
||||
}
|
||||
val chinaApps = PerAppProxyScanner.scanAllChinaApps()
|
||||
Settings.perAppProxyManagedList = chinaApps
|
||||
Log.d(TAG, "rescan complete, found ${chinaApps.size} china apps")
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ class BoxService(private val service: Service, private val platformInterface: Pl
|
||||
autoRedirect = Settings.autoRedirect
|
||||
if (Vendor.isPerAppProxyAvailable() && Settings.perAppProxyEnabled) {
|
||||
val appList = Settings.getEffectivePerAppProxyList()
|
||||
if (Settings.perAppProxyMode == Settings.PER_APP_PROXY_INCLUDE) {
|
||||
if (Settings.getEffectivePerAppProxyMode() == Settings.PER_APP_PROXY_INCLUDE) {
|
||||
includePackage =
|
||||
PlatformInterfaceWrapper.StringArray(appList.iterator())
|
||||
} else {
|
||||
@@ -223,7 +223,7 @@ class BoxService(private val service: Service, private val platformInterface: Pl
|
||||
autoRedirect = Settings.autoRedirect
|
||||
if (Vendor.isPerAppProxyAvailable() && Settings.perAppProxyEnabled) {
|
||||
val appList = Settings.getEffectivePerAppProxyList()
|
||||
if (Settings.perAppProxyMode == Settings.PER_APP_PROXY_INCLUDE) {
|
||||
if (Settings.getEffectivePerAppProxyMode() == Settings.PER_APP_PROXY_INCLUDE) {
|
||||
includePackage = PlatformInterfaceWrapper.StringArray(appList.iterator())
|
||||
} else {
|
||||
excludePackage = PlatformInterfaceWrapper.StringArray(appList.iterator())
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.net.ProxyInfo
|
||||
import android.net.VpnService
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import io.nekohasekai.libbox.Notification
|
||||
import io.nekohasekai.libbox.TunOptions
|
||||
import io.nekohasekai.sfa.database.Settings
|
||||
@@ -130,8 +131,11 @@ class VPNService :
|
||||
if (includePackage.hasNext()) {
|
||||
while (includePackage.hasNext()) {
|
||||
try {
|
||||
builder.addAllowedApplication(includePackage.next())
|
||||
} catch (_: NameNotFoundException) {
|
||||
val nextPackage = includePackage.next()
|
||||
builder.addAllowedApplication(nextPackage)
|
||||
Log.d("VPNService", "addAllowedApplication: $nextPackage")
|
||||
} catch (e: NameNotFoundException) {
|
||||
Log.e("VPNService", "addAllowedApplication failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -140,8 +144,11 @@ class VPNService :
|
||||
if (excludePackage.hasNext()) {
|
||||
while (excludePackage.hasNext()) {
|
||||
try {
|
||||
builder.addDisallowedApplication(excludePackage.next())
|
||||
} catch (_: NameNotFoundException) {
|
||||
val nextPackage = excludePackage.next()
|
||||
builder.addDisallowedApplication(nextPackage)
|
||||
Log.d("VPNService", "addDisallowedApplication: $nextPackage")
|
||||
} catch (e: NameNotFoundException) {
|
||||
Log.e("VPNService", "addDisallowedApplication failed", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package io.nekohasekai.sfa.compose.screen.profileoverride
|
||||
import android.content.pm.PackageInfo
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import io.nekohasekai.sfa.Application
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
@@ -1275,8 +1276,40 @@ object PerAppProxyScanner {
|
||||
("(" + chinaAppPrefixList.joinToString("|").replace(".", "\\.") + ").*").toRegex()
|
||||
}
|
||||
|
||||
suspend fun scanAllChinaApps(): Set<String> = withContext(Dispatchers.Default) {
|
||||
val packageManagerFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES or
|
||||
PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or
|
||||
PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES or
|
||||
PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or
|
||||
PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
|
||||
}
|
||||
val retryFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES or PackageManager.GET_PERMISSIONS
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES or PackageManager.GET_PERMISSIONS
|
||||
}
|
||||
val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags, retryFlags)
|
||||
val chinaApps = mutableSetOf<String>()
|
||||
installedPackages.map { packageInfo ->
|
||||
async {
|
||||
if (scanChinaPackage(packageInfo)) {
|
||||
synchronized(chinaApps) {
|
||||
chinaApps.add(packageInfo.packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.awaitAll()
|
||||
chinaApps.toSet()
|
||||
}
|
||||
|
||||
fun scanChinaPackage(packageInfo: PackageInfo): Boolean {
|
||||
val packageName = packageInfo.packageName
|
||||
if (packageName == Application.application.packageName) return false
|
||||
skipPrefixList.forEach {
|
||||
if (packageName == it || packageName.startsWith("$it.")) return false
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package io.nekohasekai.sfa.compose.screen.settings
|
||||
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
@@ -64,8 +62,6 @@ import io.nekohasekai.sfa.compose.topbar.OverrideTopBar
|
||||
import io.nekohasekai.sfa.database.Settings
|
||||
import io.nekohasekai.sfa.vendor.PackageQueryManager
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
import kotlinx.coroutines.awaitAll
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
|
||||
@@ -93,6 +89,18 @@ fun ProfileOverrideScreen(navController: NavController) {
|
||||
var perAppProxyEnabled by remember { mutableStateOf(Settings.perAppProxyEnabled) }
|
||||
var managedModeEnabled by remember { mutableStateOf(Settings.perAppProxyManagedMode) }
|
||||
var isScanning by remember { mutableStateOf(false) }
|
||||
|
||||
fun scanAndSaveManagedList() {
|
||||
isScanning = true
|
||||
scope.launch {
|
||||
val chinaApps = PerAppProxyScanner.scanAllChinaApps()
|
||||
withContext(Dispatchers.IO) {
|
||||
Settings.perAppProxyManagedList = chinaApps
|
||||
}
|
||||
isScanning = false
|
||||
}
|
||||
}
|
||||
|
||||
var showShizukuDialog by remember { mutableStateOf(false) }
|
||||
var showRootDialog by remember { mutableStateOf(false) }
|
||||
var showModeDialog by remember { mutableStateOf(false) }
|
||||
@@ -150,12 +158,7 @@ fun ProfileOverrideScreen(navController: NavController) {
|
||||
Settings.perAppProxyEnabled = true
|
||||
}
|
||||
if (managedModeEnabled) {
|
||||
isScanning = true
|
||||
val chinaApps = scanAllChinaApps()
|
||||
withContext(Dispatchers.IO) {
|
||||
Settings.perAppProxyManagedList = chinaApps
|
||||
}
|
||||
isScanning = false
|
||||
scanAndSaveManagedList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -352,14 +355,7 @@ fun ProfileOverrideScreen(navController: NavController) {
|
||||
Settings.perAppProxyEnabled = checked
|
||||
}
|
||||
if (checked && managedModeEnabled) {
|
||||
isScanning = true
|
||||
scope.launch {
|
||||
val chinaApps = scanAllChinaApps()
|
||||
withContext(Dispatchers.IO) {
|
||||
Settings.perAppProxyManagedList = chinaApps
|
||||
}
|
||||
isScanning = false
|
||||
}
|
||||
scanAndSaveManagedList()
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -465,18 +461,10 @@ fun ProfileOverrideScreen(navController: NavController) {
|
||||
onCheckedChange = { checked ->
|
||||
if (checked) {
|
||||
managedModeEnabled = true
|
||||
isScanning = true
|
||||
scope.launch {
|
||||
withContext(Dispatchers.IO) {
|
||||
Settings.perAppProxyManagedMode = true
|
||||
Settings.perAppProxyMode = Settings.PER_APP_PROXY_EXCLUDE
|
||||
}
|
||||
val chinaApps = scanAllChinaApps()
|
||||
withContext(Dispatchers.IO) {
|
||||
Settings.perAppProxyManagedList = chinaApps
|
||||
}
|
||||
isScanning = false
|
||||
scope.launch(Dispatchers.IO) {
|
||||
Settings.perAppProxyManagedMode = true
|
||||
}
|
||||
scanAndSaveManagedList()
|
||||
} else {
|
||||
managedModeEnabled = false
|
||||
scope.launch(Dispatchers.IO) {
|
||||
@@ -518,14 +506,7 @@ fun ProfileOverrideScreen(navController: NavController) {
|
||||
Settings.perAppProxyEnabled = true
|
||||
}
|
||||
if (managedModeEnabled) {
|
||||
isScanning = true
|
||||
scope.launch {
|
||||
val chinaApps = scanAllChinaApps()
|
||||
withContext(Dispatchers.IO) {
|
||||
Settings.perAppProxyManagedList = chinaApps
|
||||
}
|
||||
isScanning = false
|
||||
}
|
||||
scanAndSaveManagedList()
|
||||
}
|
||||
},
|
||||
) {
|
||||
@@ -601,12 +582,7 @@ fun ProfileOverrideScreen(navController: NavController) {
|
||||
Settings.perAppProxyEnabled = true
|
||||
}
|
||||
if (managedModeEnabled) {
|
||||
isScanning = true
|
||||
val chinaApps = scanAllChinaApps()
|
||||
withContext(Dispatchers.IO) {
|
||||
Settings.perAppProxyManagedList = chinaApps
|
||||
}
|
||||
isScanning = false
|
||||
scanAndSaveManagedList()
|
||||
}
|
||||
} else {
|
||||
showRootDialog = false
|
||||
@@ -694,37 +670,3 @@ fun ProfileOverrideScreen(navController: NavController) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun scanAllChinaApps(): Set<String> = withContext(Dispatchers.Default) {
|
||||
val packageManagerFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES or
|
||||
PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or
|
||||
PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES or
|
||||
PackageManager.GET_ACTIVITIES or PackageManager.GET_SERVICES or
|
||||
PackageManager.GET_RECEIVERS or PackageManager.GET_PROVIDERS
|
||||
}
|
||||
val retryFlags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
PackageManager.MATCH_UNINSTALLED_PACKAGES or PackageManager.GET_PERMISSIONS
|
||||
} else {
|
||||
@Suppress("DEPRECATION")
|
||||
PackageManager.GET_UNINSTALLED_PACKAGES or PackageManager.GET_PERMISSIONS
|
||||
}
|
||||
|
||||
val installedPackages = PackageQueryManager.getInstalledPackages(packageManagerFlags, retryFlags)
|
||||
|
||||
val chinaApps = mutableSetOf<String>()
|
||||
installedPackages.map { packageInfo ->
|
||||
async {
|
||||
if (PerAppProxyScanner.scanChinaPackage(packageInfo)) {
|
||||
synchronized(chinaApps) {
|
||||
chinaApps.add(packageInfo.packageName)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.awaitAll()
|
||||
|
||||
chinaApps.toSet()
|
||||
}
|
||||
|
||||
@@ -82,8 +82,14 @@ object Settings {
|
||||
const val PACKAGE_QUERY_MODE_ROOT = "ROOT"
|
||||
var perAppProxyPackageQueryMode by dataStore.string(SettingsKey.PER_APP_PROXY_PACKAGE_QUERY_MODE) { PACKAGE_QUERY_MODE_SHIZUKU }
|
||||
|
||||
fun getEffectivePerAppProxyMode(): Int = if (perAppProxyManagedMode) {
|
||||
PER_APP_PROXY_EXCLUDE
|
||||
} else {
|
||||
perAppProxyMode
|
||||
}
|
||||
|
||||
fun getEffectivePerAppProxyList(): Set<String> = if (perAppProxyManagedMode) {
|
||||
perAppProxyList union perAppProxyManagedList
|
||||
perAppProxyManagedList
|
||||
} else {
|
||||
perAppProxyList
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user