Fix NetworkCapabilities field access for API compatibility

- mUnderlyingNetworks: Added in Android 13 (not 12), use findFieldIfExists
  for Android 12 (APEX may upgrade), findField for Android 13+
- mOwnerUid: Added in Android 11, add SDK >= R check
- mTransportInfo: Added in Android 10, add SDK >= Q check

Fixes NullPointerException on devices running Android < 13 where
setUnderlyingNetworks method doesn't exist.
This commit is contained in:
世界
2026-01-11 18:05:41 +08:00
parent 99e087e7c1
commit 15daef6ad2
2 changed files with 21 additions and 6 deletions

View File

@@ -3,6 +3,7 @@ package io.nekohasekai.sfa.xposed
import android.net.LinkProperties import android.net.LinkProperties
import android.net.NetworkCapabilities import android.net.NetworkCapabilities
import android.net.NetworkInfo import android.net.NetworkInfo
import android.os.Build
import android.os.Parcel import android.os.Parcel
import android.os.Process import android.os.Process
import de.robv.android.xposed.XposedHelpers import de.robv.android.xposed.XposedHelpers
@@ -81,14 +82,26 @@ object VpnSanitizer {
} }
private fun clearUnderlyingNetworks(caps: NetworkCapabilities) { private fun clearUnderlyingNetworks(caps: NetworkCapabilities) {
XposedHelpers.callMethod(caps, "setUnderlyingNetworks", null) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
val field = XposedHelpers.findField(NetworkCapabilities::class.java, "mUnderlyingNetworks")
field.set(caps, null)
} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
val field = XposedHelpers.findFieldIfExists(NetworkCapabilities::class.java, "mUnderlyingNetworks")
field?.set(caps, null)
}
} }
private fun clearOwnerUid(caps: NetworkCapabilities) { private fun clearOwnerUid(caps: NetworkCapabilities) {
XposedHelpers.callMethod(caps, "setOwnerUid", Process.INVALID_UID) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val field = XposedHelpers.findField(NetworkCapabilities::class.java, "mOwnerUid")
field.setInt(caps, Process.INVALID_UID)
}
} }
private fun clearVpnTransportInfo(caps: NetworkCapabilities) { private fun clearVpnTransportInfo(caps: NetworkCapabilities) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return
}
val field = XposedHelpers.findField(NetworkCapabilities::class.java, "mTransportInfo") val field = XposedHelpers.findField(NetworkCapabilities::class.java, "mTransportInfo")
val info = field.get(caps) ?: return val info = field.get(caps) ?: return
if (info.javaClass.name.contains("VpnTransportInfo")) { if (info.javaClass.name.contains("VpnTransportInfo")) {

View File

@@ -91,11 +91,13 @@ class HookNetworkCapabilitiesWriteToParcel : XHook {
} }
private fun clearUnderlyingNetworks(caps: NetworkCapabilities) { private fun clearUnderlyingNetworks(caps: NetworkCapabilities) {
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.S) { if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) {
return val field = XposedHelpers.findField(NetworkCapabilities::class.java, "mUnderlyingNetworks")
field.set(caps, null)
} else if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
val field = XposedHelpers.findFieldIfExists(NetworkCapabilities::class.java, "mUnderlyingNetworks")
field?.set(caps, null)
} }
val field = XposedHelpers.findField(NetworkCapabilities::class.java, "mUnderlyingNetworks")
field.set(caps, null)
} }
private fun clearOwnerUid(caps: NetworkCapabilities) { private fun clearOwnerUid(caps: NetworkCapabilities) {