diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/AppChangeReceiver.kt b/app/src/main/java/io/nekohasekai/sfa/bg/AppChangeReceiver.kt index 0aaeb84..8b56301 100644 --- a/app/src/main/java/io/nekohasekai/sfa/bg/AppChangeReceiver.kt +++ b/app/src/main/java/io/nekohasekai/sfa/bg/AppChangeReceiver.kt @@ -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() - 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") } diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/BoxService.kt b/app/src/main/java/io/nekohasekai/sfa/bg/BoxService.kt index c3e9e16..7f8b50f 100644 --- a/app/src/main/java/io/nekohasekai/sfa/bg/BoxService.kt +++ b/app/src/main/java/io/nekohasekai/sfa/bg/BoxService.kt @@ -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()) diff --git a/app/src/main/java/io/nekohasekai/sfa/bg/VPNService.kt b/app/src/main/java/io/nekohasekai/sfa/bg/VPNService.kt index d3374ea..d958184 100644 --- a/app/src/main/java/io/nekohasekai/sfa/bg/VPNService.kt +++ b/app/src/main/java/io/nekohasekai/sfa/bg/VPNService.kt @@ -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) } } } diff --git a/app/src/main/java/io/nekohasekai/sfa/compose/screen/profileoverride/PerAppProxyScreen.kt b/app/src/main/java/io/nekohasekai/sfa/compose/screen/profileoverride/PerAppProxyScreen.kt index 84fd713..e3e9cf1 100644 --- a/app/src/main/java/io/nekohasekai/sfa/compose/screen/profileoverride/PerAppProxyScreen.kt +++ b/app/src/main/java/io/nekohasekai/sfa/compose/screen/profileoverride/PerAppProxyScreen.kt @@ -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 = 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() + 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 } diff --git a/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/ProfileOverrideScreen.kt b/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/ProfileOverrideScreen.kt index 9f1f76c..692714f 100644 --- a/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/ProfileOverrideScreen.kt +++ b/app/src/main/java/io/nekohasekai/sfa/compose/screen/settings/ProfileOverrideScreen.kt @@ -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 = 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() - installedPackages.map { packageInfo -> - async { - if (PerAppProxyScanner.scanChinaPackage(packageInfo)) { - synchronized(chinaApps) { - chinaApps.add(packageInfo.packageName) - } - } - } - }.awaitAll() - - chinaApps.toSet() -} diff --git a/app/src/main/java/io/nekohasekai/sfa/database/Settings.kt b/app/src/main/java/io/nekohasekai/sfa/database/Settings.kt index b79ab58..0d2ed48 100644 --- a/app/src/main/java/io/nekohasekai/sfa/database/Settings.kt +++ b/app/src/main/java/io/nekohasekai/sfa/database/Settings.kt @@ -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 = if (perAppProxyManagedMode) { - perAppProxyList union perAppProxyManagedList + perAppProxyManagedList } else { perAppProxyList }