diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index 85507f6d16..f888da526c 100755 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -97,14 +97,12 @@ import static android.os.Process.VPN_UID; import static android.system.OsConstants.ETH_P_ALL; import static android.system.OsConstants.IPPROTO_TCP; import static android.system.OsConstants.IPPROTO_UDP; - import static com.android.net.module.util.NetworkMonitorUtils.isPrivateDnsValidationRequired; import static com.android.net.module.util.PermissionUtils.checkAnyPermissionOf; import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf; import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission; import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr; import static com.android.server.ConnectivityStatsLog.CONNECTIVITY_STATE_SAMPLE; - import static java.util.Map.Entry; import android.Manifest; @@ -10614,6 +10612,16 @@ public class ConnectivityService extends IConnectivityManager.Stub err.getFileDescriptor(), args); } + private Boolean parseBooleanArgument(final String arg) { + if ("true".equals(arg)) { + return true; + } else if ("false".equals(arg)) { + return false; + } else { + return null; + } + } + private class ShellCmd extends BasicShellCommandHandler { @Override public int onCommand(String cmd) { @@ -10643,6 +10651,54 @@ public class ConnectivityService extends IConnectivityManager.Stub onHelp(); return -1; } + case "set-chain3-enabled": { + final Boolean enabled = parseBooleanArgument(getNextArg()); + if (null == enabled) { + onHelp(); + return -1; + } + Log.i(TAG, (enabled ? "En" : "Dis") + "abled FIREWALL_CHAIN_OEM_DENY_3"); + setFirewallChainEnabled(ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3, + enabled); + return 0; + } + case "get-chain3-enabled": { + final boolean chainEnabled = getFirewallChainEnabled( + ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3); + pw.println("chain:" + (chainEnabled ? "enabled" : "disabled")); + return 0; + } + case "set-package-networking-enabled": { + final Boolean enabled = parseBooleanArgument(getNextArg()); + final String packageName = getNextArg(); + if (null == enabled || null == packageName) { + onHelp(); + return -1; + } + // Throws NameNotFound if the package doesn't exist. + final int appId = setPackageFirewallRule( + ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3, + packageName, enabled ? FIREWALL_RULE_DEFAULT : FIREWALL_RULE_DENY); + final String msg = (enabled ? "Enabled" : "Disabled") + + " networking for " + packageName + ", appId " + appId; + Log.i(TAG, msg); + pw.println(msg); + return 0; + } + case "get-package-networking-enabled": { + final String packageName = getNextArg(); + final int rule = getPackageFirewallRule( + ConnectivityManager.FIREWALL_CHAIN_OEM_DENY_3, packageName); + if (FIREWALL_RULE_ALLOW == rule || FIREWALL_RULE_DEFAULT == rule) { + pw.println(packageName + ":" + "allow"); + } else if (FIREWALL_RULE_DENY == rule) { + pw.println(packageName + ":" + "deny"); + } else { + throw new IllegalStateException("Unknown rule " + rule + " for package " + + packageName); + } + return 0; + } case "reevaluate": // Usage : adb shell cmd connectivity reevaluate // If netId is omitted, then reevaluate the default network @@ -10683,6 +10739,15 @@ public class ConnectivityService extends IConnectivityManager.Stub pw.println(" Turn airplane mode on or off."); pw.println(" airplane-mode"); pw.println(" Get airplane mode."); + pw.println(" set-chain3-enabled [true|false]"); + pw.println(" Enable or disable FIREWALL_CHAIN_OEM_DENY_3 for debugging."); + pw.println(" get-chain3-enabled"); + pw.println(" Returns whether FIREWALL_CHAIN_OEM_DENY_3 is enabled."); + pw.println(" set-package-networking-enabled [true|false] [package name]"); + pw.println(" Set the deny bit in FIREWALL_CHAIN_OEM_DENY_3 to package. This has\n" + + " no effect if the chain is disabled."); + pw.println(" get-package-networking-enabled [package name]"); + pw.println(" Get the deny bit in FIREWALL_CHAIN_OEM_DENY_3 for package."); } } @@ -12418,6 +12483,21 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private int setPackageFirewallRule(final int chain, final String packageName, final int rule) + throws PackageManager.NameNotFoundException { + final PackageManager pm = mContext.getPackageManager(); + final int appId = UserHandle.getAppId(pm.getPackageUid(packageName, 0 /* flags */)); + if (appId < Process.FIRST_APPLICATION_UID) { + throw new RuntimeException("Can't set package firewall rule for system app " + + packageName + " with appId " + appId); + } + for (final UserHandle uh : mUserManager.getUserHandles(false /* excludeDying */)) { + final int uid = uh.getUid(appId); + setUidFirewallRule(chain, uid, rule); + } + return appId; + } + @Override public void setUidFirewallRule(final int chain, final int uid, final int rule) { enforceNetworkStackOrSettingsPermission(); @@ -12436,6 +12516,13 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private int getPackageFirewallRule(final int chain, final String packageName) + throws PackageManager.NameNotFoundException { + final PackageManager pm = mContext.getPackageManager(); + final int appId = UserHandle.getAppId(pm.getPackageUid(packageName, 0 /* flags */)); + return getUidFirewallRule(chain, appId); + } + @Override public int getUidFirewallRule(final int chain, final int uid) { enforceNetworkStackOrSettingsPermission(); diff --git a/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt b/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt index 3fc74aa1a4..eb9478154a 100644 --- a/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt +++ b/staticlibs/testutils/host/com/android/testutils/ConnectivityTestTargetPreparer.kt @@ -32,6 +32,10 @@ private const val CONNECTIVITY_CHECK_CLASS = "$CONNECTIVITY_PKG_NAME.Connectivit private const val CONNECTIVITY_CHECK_RUNNER_NAME = "androidx.test.runner.AndroidJUnitRunner" private const val IGNORE_CONN_CHECK_OPTION = "ignore-connectivity-check" +// The default updater package names, which might be updating packages while the CTS +// are running +private val UPDATER_PKGS = arrayOf("com.google.android.gms", "com.android.vending") + /** * A target preparer that sets up and verifies a device for connectivity tests. * @@ -45,35 +49,42 @@ open class ConnectivityTestTargetPreparer : BaseTargetPreparer() { @Option(name = IGNORE_CONN_CHECK_OPTION, description = "Disables the check for mobile data and wifi") private var ignoreConnectivityCheck = false + // The default value is never used, but false is a reasonable default + private var originalTestChainEnabled = false + private val originalUpdaterPkgsStatus = HashMap() - override fun setUp(testInformation: TestInformation) { + override fun setUp(testInfo: TestInformation) { if (isDisabled) return - disableGmsUpdate(testInformation) - runPreparerApk(testInformation) + disableGmsUpdate(testInfo) + originalTestChainEnabled = getTestChainEnabled(testInfo) + originalUpdaterPkgsStatus.putAll(getUpdaterPkgsStatus(testInfo)) + setUpdaterNetworkingEnabled(testInfo, enableChain = true, + enablePkgs = UPDATER_PKGS.associateWith { false }) + runPreparerApk(testInfo) } - private fun runPreparerApk(testInformation: TestInformation) { + private fun runPreparerApk(testInfo: TestInformation) { installer.setCleanApk(true) installer.addTestFileName(CONNECTIVITY_CHECKER_APK) installer.setShouldGrantPermission(true) - installer.setUp(testInformation) + installer.setUp(testInfo) val runner = DefaultRemoteAndroidTestRunner( CONNECTIVITY_PKG_NAME, CONNECTIVITY_CHECK_RUNNER_NAME, - testInformation.device.iDevice) + testInfo.device.iDevice) runner.runOptions = "--no-hidden-api-checks" val receiver = CollectingTestListener() - if (!testInformation.device.runInstrumentationTests(runner, receiver)) { + if (!testInfo.device.runInstrumentationTests(runner, receiver)) { throw TargetSetupError("Device state check failed to complete", - testInformation.device.deviceDescriptor) + testInfo.device.deviceDescriptor) } val runResult = receiver.currentRunResults if (runResult.isRunFailure) { throw TargetSetupError("Failed to check device state before the test: " + - runResult.runFailureMessage, testInformation.device.deviceDescriptor) + runResult.runFailureMessage, testInfo.device.deviceDescriptor) } val ignoredTestClasses = mutableSetOf() @@ -92,25 +103,50 @@ open class ConnectivityTestTargetPreparer : BaseTargetPreparer() { if (errorMsg.isBlank()) return throw TargetSetupError("Device setup checks failed. Check the test bench: \n$errorMsg", - testInformation.device.deviceDescriptor) + testInfo.device.deviceDescriptor) } - private fun disableGmsUpdate(testInformation: TestInformation) { + private fun disableGmsUpdate(testInfo: TestInformation) { // This will be a no-op on devices without root (su) or not using gservices, but that's OK. - testInformation.device.executeShellCommand("su 0 am broadcast " + + testInfo.exec("su 0 am broadcast " + "-a com.google.gservices.intent.action.GSERVICES_OVERRIDE " + "-e finsky.play_services_auto_update_enabled false") } - private fun clearGmsUpdateOverride(testInformation: TestInformation) { - testInformation.device.executeShellCommand("su 0 am broadcast " + + private fun clearGmsUpdateOverride(testInfo: TestInformation) { + testInfo.exec("su 0 am broadcast " + "-a com.google.gservices.intent.action.GSERVICES_OVERRIDE " + "--esn finsky.play_services_auto_update_enabled") } - override fun tearDown(testInformation: TestInformation, e: Throwable?) { + private fun setUpdaterNetworkingEnabled( + testInfo: TestInformation, + enableChain: Boolean, + enablePkgs: Map + ) { + // Build.VERSION_CODES.S = 31 where this is not available, then do nothing. + if (testInfo.device.getApiLevel() < 31) return + testInfo.exec("cmd connectivity set-chain3-enabled $enableChain") + enablePkgs.forEach { (pkg, allow) -> + testInfo.exec("cmd connectivity set-package-networking-enabled $pkg $allow") + } + } + + private fun getTestChainEnabled(testInfo: TestInformation) = + testInfo.exec("cmd connectivity get-chain3-enabled").contains("chain:enabled") + + private fun getUpdaterPkgsStatus(testInfo: TestInformation) = + UPDATER_PKGS.associateWith { pkg -> + !testInfo.exec("cmd connectivity get-package-networking-enabled $pkg") + .contains(":deny") + } + + override fun tearDown(testInfo: TestInformation, e: Throwable?) { if (isTearDownDisabled) return - installer.tearDown(testInformation, e) - clearGmsUpdateOverride(testInformation) + installer.tearDown(testInfo, e) + setUpdaterNetworkingEnabled(testInfo, + enableChain = originalTestChainEnabled, + enablePkgs = originalUpdaterPkgsStatus) + clearGmsUpdateOverride(testInfo) } } diff --git a/staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt b/staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt index 63f05a6cb1..bc00f3cfd4 100644 --- a/staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt +++ b/staticlibs/testutils/host/com/android/testutils/DisableConfigSyncTargetPreparer.kt @@ -58,4 +58,4 @@ class DisableConfigSyncTargetPreparer : BaseTargetPreparer() { } } -private fun TestInformation.exec(cmd: String) = this.device.executeShellCommand(cmd) \ No newline at end of file +fun TestInformation.exec(cmd: String) = this.device.executeShellCommand(cmd)