Merge "Create the MdnsDiscoveryManager"
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 8840394..565675f 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -50,6 +50,15 @@
// as the above target may have different "enabled" values
// depending on the branch
+// cronet_in_tethering_apex_defaults can be used to specify an apex_defaults target that either
+// enables or disables inclusion of Cronet in the Tethering apex. This is used to disable Cronet
+// on tm-mainline-prod. Note: in order for Cronet APIs to work Cronet must also be enabled
+// by the cronet_java_*_defaults in common/TetheringLib/Android.bp.
+cronet_in_tethering_apex_defaults = "CronetInTetheringApexDefaultsEnabled"
+// This is a placeholder comment to avoid merge conflicts
+// as cronet_apex_defaults may have different values
+// depending on the branch
+
apex {
name: "com.android.tethering",
defaults: [
diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp
index 3f4da10..6df522c 100644
--- a/Tethering/common/TetheringLib/Android.bp
+++ b/Tethering/common/TetheringLib/Android.bp
@@ -31,7 +31,7 @@
java_sdk_library {
name: "framework-tethering",
- defaults: ["framework-module-defaults"],
+ defaults: ["framework-tethering-defaults"],
impl_library_visibility: [
"//packages/modules/Connectivity/Tethering:__subpackages__",
"//packages/modules/Connectivity/framework",
@@ -57,24 +57,54 @@
"//packages/modules/NetworkStack/tests:__subpackages__",
"//packages/modules/Wifi/service/tests/wifitests",
],
-
- srcs: [":framework-tethering-srcs"],
- libs: ["framework-connectivity.stubs.module_lib"],
stub_only_libs: ["framework-connectivity.stubs.module_lib"],
+
+ jarjar_rules: ":framework-tethering-jarjar-rules",
+ installable: true,
+
+ hostdex: true, // for hiddenapi check
+ permitted_packages: ["android.net"],
+ lint: { strict_updatability_linting: true },
+}
+
+java_library {
+ name: "framework-tethering-pre-jarjar",
+ defaults: ["framework-tethering-defaults"],
+}
+
+java_genrule {
+ name: "framework-tethering-jarjar-rules",
+ tool_files: [
+ ":framework-tethering-pre-jarjar{.jar}",
+ ":framework-tethering.stubs.module_lib{.jar}",
+ "jarjar-excludes.txt",
+ ],
+ tools: [
+ "jarjar-rules-generator",
+ ],
+ out: ["framework_tethering_jarjar_rules.txt"],
+ cmd: "$(location jarjar-rules-generator) " +
+ "$(location :framework-tethering-pre-jarjar{.jar}) " +
+ "--apistubs $(location :framework-tethering.stubs.module_lib{.jar}) " +
+ "--prefix android.net.http.internal " +
+ "--excludes $(location jarjar-excludes.txt) " +
+ "--output $(out)",
+}
+
+java_defaults {
+ name: "framework-tethering-defaults",
+ defaults: ["framework-module-defaults"],
+ srcs: [
+ ":framework-tethering-srcs"
+ ],
+ libs: ["framework-connectivity.stubs.module_lib"],
aidl: {
include_dirs: [
"packages/modules/Connectivity/framework/aidl-export",
],
},
-
- jarjar_rules: "jarjar-rules.txt",
- installable: true,
-
- hostdex: true, // for hiddenapi check
apex_available: ["com.android.tethering"],
- permitted_packages: ["android.net"],
min_sdk_version: "30",
- lint: { strict_updatability_linting: true },
}
filegroup {
diff --git a/Tethering/common/TetheringLib/jarjar-excludes.txt b/Tethering/common/TetheringLib/jarjar-excludes.txt
new file mode 100644
index 0000000..50bc186
--- /dev/null
+++ b/Tethering/common/TetheringLib/jarjar-excludes.txt
@@ -0,0 +1,2 @@
+# Don't touch anything that's already under android.net
+android\.net\..+
\ No newline at end of file
diff --git a/Tethering/common/TetheringLib/jarjar-rules.txt b/Tethering/common/TetheringLib/jarjar-rules.txt
deleted file mode 100644
index e459fad..0000000
--- a/Tethering/common/TetheringLib/jarjar-rules.txt
+++ /dev/null
@@ -1 +0,0 @@
-# jarjar rules for the bootclasspath tethering framework library here
\ No newline at end of file
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index e1b7016..e48019c 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -1203,6 +1203,9 @@
}
private void handleConnectivityAction(Intent intent) {
+ // CONNECTIVITY_ACTION is not handled since U+ device.
+ if (SdkLevel.isAtLeastU()) return;
+
final NetworkInfo networkInfo =
(NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO);
if (networkInfo == null
@@ -2034,6 +2037,11 @@
// broadcasts that result in being passed a
// TetherMainSM.CMD_UPSTREAM_CHANGED.
handleNewUpstreamNetworkState(null);
+
+ if (SdkLevel.isAtLeastU()) {
+ // Need to try DUN immediately if Wi-Fi goes down.
+ chooseUpstreamType(true);
+ }
break;
default:
mLog.e("Unknown arg1 value: " + arg1);
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 38f1e9c..da81bda 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -666,7 +666,7 @@
// Calling System.gc() or System.runFinalization() doesn't guarantee GCs or finalizers
// are executed synchronously. The finalizer is called after GC on a separate thread.
- final int attempts = 100;
+ final int attempts = 600;
final long waitIntervalMs = 50;
for (int i = 0; i < attempts; i++) {
forceGc();
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
index a8d886b..63702f2 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java
@@ -82,6 +82,8 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeFalse;
@@ -179,6 +181,7 @@
import android.util.ArraySet;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -1337,6 +1340,131 @@
verifyDisableTryCellWhenTetheringStop(inOrder);
}
+ private void verifyWifiUpstreamAndUnregisterDunCallback(@NonNull final InOrder inOrder,
+ @NonNull final TestNetworkAgent wifi,
+ @NonNull final NetworkCallback currentDunCallack) throws Exception {
+ assertNotNull(currentDunCallack);
+
+ inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false);
+ inOrder.verify(mCm).unregisterNetworkCallback(eq(currentDunCallack));
+ inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(wifi.networkId);
+ inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any());
+ }
+
+ @Nullable
+ private NetworkCallback verifyDunUpstream(@NonNull final InOrder inOrder,
+ @NonNull final TestNetworkAgent dun, final boolean needToRequestNetwork)
+ throws Exception {
+ inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true);
+ ArgumentCaptor<NetworkCallback> captor = ArgumentCaptor.forClass(NetworkCallback.class);
+ NetworkCallback dunNetworkCallback = null;
+ if (needToRequestNetwork) {
+ inOrder.verify(mCm).requestNetwork(any(), eq(0), eq(TYPE_MOBILE_DUN), any(),
+ captor.capture());
+ dunNetworkCallback = captor.getValue();
+ }
+ inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(null);
+ final Runnable doDispatchAll = () -> mLooper.dispatchAll();
+ dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(dun.networkId);
+
+ if (needToRequestNetwork) {
+ assertNotNull(dunNetworkCallback);
+ } else {
+ assertNull(dunNetworkCallback);
+ }
+
+ return dunNetworkCallback;
+ }
+
+ // Overall test coverage:
+ // - verifyChooseDunUpstreamByAutomaticMode: common, test#1, test#2
+ // - testChooseDunUpstreamByAutomaticMode_defaultNetworkWifi: test#3, test#4
+ // - testChooseDunUpstreamByAutomaticMode_loseDefaultNetworkWifi: test#5
+ // - testChooseDunUpstreamByAutomaticMode_defaultNetworkCell: test#5, test#7
+ // - testChooseDunUpstreamByAutomaticMode_loseAndRegainDun: test#8
+ // - testChooseDunUpstreamByAutomaticMode_switchDefaultFromWifiToCell: test#9, test#10
+ //
+ // Overall test cases:
+ // +-------+-------+-------+-------+-------+
+ // | Test | WiFi | Cellu | Dun | Expec |
+ // | Case | | alr | | ted |
+ // | # | | | | Upstr |
+ // | | | | | eam |
+ // +-------+-------+-------+-------+-------+
+ // | - | | | | - | --+
+ // +-------+-------+-------+-------+-------+ |
+ // | - | | V | | - | |
+ // +-------+-------+-------+-------+-------+ |
+ // | - | | V | O | Dun | +-- chooseDunUpstreamTestCommon
+ // +-------+-------+-------+-------+-------+ |
+ // | - | V | O | O | WiFi | |
+ // +-------+-------+-------+-------+-------+ |
+ // | - | V | O | | WiFi | --+
+ // +-------+-------+-------+-------+-------+
+ // | | O | V | | - |
+ // | 1 +-------+-------+-------+-------+
+ // | | O | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | | O | V | | - |
+ // | 2 +-------+-------+-------+-------+
+ // | | O | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | 3 | V | O | | WiFi |
+ // +-------+-------+-------+-------+-------+
+ // | 4 | V | | | WiFi |
+ // +-------+-------+-------+-------+-------+
+ // | 5 | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | 6 | | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | 7 | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | | | | | - |
+ // | 8 +-------+-------+-------+-------+
+ // | | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | | V | | O | WiFi |
+ // | 9 +-------+-------+-------+-------+
+ // | | V | | | WiFi |
+ // +-------+-------+-------+-------+-------+
+ // | | O | V | | - |
+ // | 10 +-------+-------+-------+-------+
+ // | | O | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ //
+ // Annotation:
+ // 1. "V" means that the given network is connected and it is default network.
+ // 2. "O" means that the given network is connected and it is not default network.
+ //
+
+ // Test case:
+ // +-------+-------+-------+-------+-------+
+ // | Test | WiFi | Cellu | Dun | Expec |
+ // | Case | | alr | | ted |
+ // | # | | | | Upstr |
+ // | | | | | eam |
+ // +-------+-------+-------+-------+-------+
+ // | - | | | | - | --+
+ // +-------+-------+-------+-------+-------+ |
+ // | - | | V | | - | |
+ // +-------+-------+-------+-------+-------+ |
+ // | - | | V | O | Dun | +-- chooseDunUpstreamTestCommon
+ // +-------+-------+-------+-------+-------+ |
+ // | - | V | O | O | WiFi | |
+ // +-------+-------+-------+-------+-------+ |
+ // | - | V | O | | WiFi | --+
+ // +-------+-------+-------+-------+-------+
+ // | | O | V | | - |
+ // | 1 +-------+-------+-------+-------+
+ // | | O | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | | O | V | | - |
+ // | 2 +-------+-------+-------+-------+
+ // | | O | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ //
private void verifyChooseDunUpstreamByAutomaticMode(boolean configAutomatic) throws Exception {
// Enable automatic upstream selection.
TestNetworkAgent mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState());
@@ -1345,20 +1473,14 @@
InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor);
chooseDunUpstreamTestCommon(configAutomatic, inOrder, mobile, wifi, dun);
- // When default network switch to mobile and wifi is connected (may have low signal),
+ // [1] When default network switch to mobile and wifi is connected (may have low signal),
// automatic mode would request dun again and choose it as upstream.
mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST);
mLooper.dispatchAll();
- inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true);
- ArgumentCaptor<NetworkCallback> captor = ArgumentCaptor.forClass(NetworkCallback.class);
- inOrder.verify(mCm).requestNetwork(any(), eq(0), eq(TYPE_MOBILE_DUN), any(), any());
- inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(null);
- final Runnable doDispatchAll = () -> mLooper.dispatchAll();
- dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll);
- mLooper.dispatchAll();
- inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(dun.networkId);
+ verifyDunUpstream(inOrder, dun, true /* needToRequestNetwork */);
- // Lose and regain upstream again.
+ // [2] Lose and regain upstream again.
+ final Runnable doDispatchAll = () -> mLooper.dispatchAll();
dun.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll);
mLooper.dispatchAll();
inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true);
@@ -1376,12 +1498,245 @@
verifyChooseDunUpstreamByAutomaticMode(true /* configAutomatic */);
}
+ // testChooseDunUpstreamByAutomaticMode_* doesn't verify configAutomatic:false because no
+ // matter |configAutomatic| set to true or false, the result always be automatic mode. We
+ // just need one test to make sure this behavior. Don't need to test this configuration
+ // in all tests.
@Test
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
public void testChooseDunUpstreamByAutomaticModeWithConfigDisabled() throws Exception {
verifyChooseDunUpstreamByAutomaticMode(false /* configAutomatic */);
}
+ // Test case:
+ // +-------+-------+-------+-------+-------+
+ // | Test | WiFi | Cellu | Dun | Expec |
+ // | Case | | alr | | ted |
+ // | # | | | | Upstr |
+ // | | | | | eam |
+ // +-------+-------+-------+-------+-------+
+ // | - | O | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | 3 | V | O | | WiFi |
+ // +-------+-------+-------+-------+-------+
+ // | 4 | V | | | WiFi |
+ // +-------+-------+-------+-------+-------+
+ //
+ // See verifyChooseDunUpstreamByAutomaticMode for the annotation.
+ //
+ @Test
+ public void testChooseDunUpstreamByAutomaticMode_defaultNetworkWifi() throws Exception {
+ TestNetworkAgent mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState());
+ TestNetworkAgent wifi = new TestNetworkAgent(mCm, buildWifiUpstreamState());
+ TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState());
+ final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor);
+ final NetworkCallback dunNetworkCallback1 = setupDunUpstreamTest(
+ true /* configAutomatic */, inOrder);
+
+ // When wifi connected, unregister dun request and choose wifi as upstream.
+ wifi.fakeConnect();
+ mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST);
+ mLooper.dispatchAll();
+ verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback1);
+
+ // When default network switch to mobile and wifi is connected (may have low signal),
+ // automatic mode would request dun again and choose it as upstream.
+ mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST);
+ mLooper.dispatchAll();
+ final NetworkCallback dunNetworkCallback2 =
+ verifyDunUpstream(inOrder, dun, true /* needToRequestNetwork */);
+
+ // [3] When default network switch to wifi and mobile is still connected,
+ // unregister dun request and choose wifi as upstream.
+ mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST);
+ mLooper.dispatchAll();
+ verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback2);
+
+ // [4] When mobile is disconnected, keep wifi as upstream.
+ final Runnable doDispatchAll = () -> mLooper.dispatchAll();
+ mobile.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any());
+
+ verifyDisableTryCellWhenTetheringStop(inOrder);
+ }
+
+ // Test case:
+ // +-------+-------+-------+-------+-------+
+ // | Test | WiFi | Cellu | Dun | Expec |
+ // | Case | | alr | | ted |
+ // | # | | | | Upstr |
+ // | | | | | eam |
+ // +-------+-------+-------+-------+-------+
+ // | - | V | | | WiFi |
+ // +-------+-------+-------+-------+-------+
+ // | 5 | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ //
+ // See verifyChooseDunUpstreamByAutomaticMode for the annotation.
+ //
+ @Test
+ public void testChooseDunUpstreamByAutomaticMode_loseDefaultNetworkWifi() throws Exception {
+ TestNetworkAgent wifi = new TestNetworkAgent(mCm, buildWifiUpstreamState());
+ TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState());
+ final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor);
+ final NetworkCallback dunNetworkCallback = setupDunUpstreamTest(
+ true /* configAutomatic */, inOrder);
+
+ // When wifi connected, unregister dun request and choose wifi as upstream.
+ wifi.fakeConnect();
+ mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST);
+ mLooper.dispatchAll();
+ verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback);
+
+ // [5] When wifi is disconnected, automatic mode would request dun again and choose it
+ // as upstream.
+ final Runnable doDispatchAll = () -> mLooper.dispatchAll();
+ mCm.makeDefaultNetwork(null, CALLBACKS_FIRST, doDispatchAll);
+ wifi.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ verifyDunUpstream(inOrder, dun, true /* needToRequestNetwork */);
+
+ verifyDisableTryCellWhenTetheringStop(inOrder);
+ }
+
+ // Test case:
+ // +-------+-------+-------+-------+-------+
+ // | Test | WiFi | Cellu | Dun | Expec |
+ // | Case | | alr | | ted |
+ // | # | | | | Upstr |
+ // | | | | | eam |
+ // +-------+-------+-------+-------+-------+
+ // | - | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | 6 | | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | 7 | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ //
+ // See verifyChooseDunUpstreamByAutomaticMode for the annotation.
+ //
+ @Test
+ public void testChooseDunUpstreamByAutomaticMode_defaultNetworkCell() throws Exception {
+ TestNetworkAgent mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState());
+ TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState());
+ final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor);
+ setupDunUpstreamTest(true /* configAutomatic */, inOrder);
+
+ // Pretend dun connected and expect choose dun as upstream.
+ final Runnable doDispatchAll = () -> mLooper.dispatchAll();
+ dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(dun.networkId);
+
+ // [6] When mobile is connected and default network switch to mobile, keep dun as upstream.
+ mobile.fakeConnect();
+ mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST);
+ mLooper.dispatchAll();
+ inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any());
+
+ // [7] When mobile is disconnected, keep dun as upstream.
+ mCm.makeDefaultNetwork(null, CALLBACKS_FIRST, doDispatchAll);
+ mobile.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any());
+
+ verifyDisableTryCellWhenTetheringStop(inOrder);
+ }
+
+ // Test case:
+ // +-------+-------+-------+-------+-------+
+ // | Test | WiFi | Cellu | Dun | Expec |
+ // | Case | | alr | | ted |
+ // | # | | | | Upstr |
+ // | | | | | eam |
+ // +-------+-------+-------+-------+-------+
+ // | - | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | | | | | - |
+ // | 8 +-------+-------+-------+-------+
+ // | | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ //
+ // See verifyChooseDunUpstreamByAutomaticMode for the annotation.
+ //
+ @Test
+ public void testChooseDunUpstreamByAutomaticMode_loseAndRegainDun() throws Exception {
+ TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState());
+ final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor);
+ setupDunUpstreamTest(true /* configAutomatic */, inOrder);
+
+ // Pretend dun connected and expect choose dun as upstream.
+ final Runnable doDispatchAll = () -> mLooper.dispatchAll();
+ dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(dun.networkId);
+
+ // [8] Lose and regain upstream again.
+ dun.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ verifyDunUpstream(inOrder, dun, false /* needToRequestNetwork */);
+
+ verifyDisableTryCellWhenTetheringStop(inOrder);
+ }
+
+ // Test case:
+ // +-------+-------+-------+-------+-------+
+ // | Test | WiFi | Cellu | Dun | Expec |
+ // | Case | | alr | | ted |
+ // | # | | | | Upstr |
+ // | | | | | eam |
+ // +-------+-------+-------+-------+-------+
+ // | - | | | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ // | | V | | O | WiFi |
+ // | 9 +-------+-------+-------+-------+
+ // | | V | | | WiFi |
+ // +-------+-------+-------+-------+-------+
+ // | | O | V | | - |
+ // | 10 +-------+-------+-------+-------+
+ // | | O | V | O | Dun |
+ // +-------+-------+-------+-------+-------+
+ //
+ // See verifyChooseDunUpstreamByAutomaticMode for the annotation.
+ //
+ @Test
+ public void testChooseDunUpstreamByAutomaticMode_switchDefaultFromWifiToCell()
+ throws Exception {
+ TestNetworkAgent mobile = new TestNetworkAgent(mCm, buildMobileDualStackUpstreamState());
+ TestNetworkAgent wifi = new TestNetworkAgent(mCm, buildWifiUpstreamState());
+ TestNetworkAgent dun = new TestNetworkAgent(mCm, buildDunUpstreamState());
+ final InOrder inOrder = inOrder(mCm, mUpstreamNetworkMonitor);
+ final NetworkCallback dunNetworkCallback = setupDunUpstreamTest(
+ true /* configAutomatic */, inOrder);
+
+ // Pretend dun connected and expect choose dun as upstream.
+ final Runnable doDispatchAll = () -> mLooper.dispatchAll();
+ dun.fakeConnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(dun.networkId);
+
+ // [9] When wifi is connected and default network switch to wifi, unregister dun request
+ // and choose wifi as upstream. When dun is disconnected, keep wifi as upstream.
+ wifi.fakeConnect();
+ mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST);
+ mLooper.dispatchAll();
+ verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback);
+ dun.fakeDisconnect(CALLBACKS_FIRST, doDispatchAll);
+ mLooper.dispatchAll();
+ inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any());
+
+ // [10] When mobile and mobile are connected and default network switch to mobile
+ // (may have low signal), automatic mode would request dun again and choose it as
+ // upstream.
+ mobile.fakeConnect();
+ mCm.makeDefaultNetwork(mobile, CALLBACKS_FIRST);
+ mLooper.dispatchAll();
+ verifyDunUpstream(inOrder, dun, true /* needToRequestNetwork */);
+
+ verifyDisableTryCellWhenTetheringStop(inOrder);
+ }
+
@Test
@IgnoreAfter(Build.VERSION_CODES.TIRAMISU)
public void testChooseDunUpstreamByLegacyMode() throws Exception {
@@ -1425,8 +1780,7 @@
verifyDisableTryCellWhenTetheringStop(inOrder);
}
- private void chooseDunUpstreamTestCommon(final boolean automatic, InOrder inOrder,
- TestNetworkAgent mobile, TestNetworkAgent wifi, TestNetworkAgent dun) throws Exception {
+ private NetworkCallback setupDunUpstreamTest(final boolean automatic, InOrder inOrder) {
when(mResources.getBoolean(R.bool.config_tether_upstream_automatic)).thenReturn(automatic);
when(mTelephonyManager.isTetheringApnRequired()).thenReturn(true);
sendConfigurationChanged();
@@ -1439,8 +1793,14 @@
inOrder.verify(mUpstreamNetworkMonitor).setTryCell(true);
ArgumentCaptor<NetworkCallback> captor = ArgumentCaptor.forClass(NetworkCallback.class);
inOrder.verify(mCm).requestNetwork(any(), eq(0), eq(TYPE_MOBILE_DUN), any(),
- captor.capture());
- final NetworkCallback dunNetworkCallback1 = captor.getValue();
+ captor.capture() /* DUN network callback */);
+
+ return captor.getValue();
+ }
+
+ private void chooseDunUpstreamTestCommon(final boolean automatic, InOrder inOrder,
+ TestNetworkAgent mobile, TestNetworkAgent wifi, TestNetworkAgent dun) throws Exception {
+ final NetworkCallback dunNetworkCallback = setupDunUpstreamTest(automatic, inOrder);
// Pretend cellular connected and expect the upstream to be set.
mobile.fakeConnect();
@@ -1458,9 +1818,7 @@
wifi.fakeConnect();
mCm.makeDefaultNetwork(wifi, CALLBACKS_FIRST);
mLooper.dispatchAll();
- inOrder.verify(mUpstreamNetworkMonitor).setTryCell(false);
- inOrder.verify(mCm).unregisterNetworkCallback(eq(dunNetworkCallback1));
- inOrder.verify(mUpstreamNetworkMonitor).setCurrentUpstream(wifi.networkId);
+ verifyWifiUpstreamAndUnregisterDunCallback(inOrder, wifi, dunNetworkCallback);
dun.fakeDisconnect(BROADCAST_FIRST, doDispatchAll);
mLooper.dispatchAll();
inOrder.verify(mUpstreamNetworkMonitor, never()).setCurrentUpstream(any());
@@ -1767,7 +2125,7 @@
new ArrayList<Network>(Arrays.asList(networks));
for (Network upstream : expectedUpstreams) {
// throws OOB if no expectations
- assertEquals(mActualUpstreams.remove(0), upstream);
+ assertEquals(upstream, mActualUpstreams.remove(0));
}
assertNoUpstreamChangeCallback();
}
@@ -1782,14 +2140,14 @@
for (TetheringConfigurationParcel config : expectedTetherConfig) {
// throws OOB if no expectations
final TetheringConfigurationParcel actualConfig = mTetheringConfigs.remove(0);
- assertTetherConfigParcelEqual(actualConfig, config);
+ assertTetherConfigParcelEqual(config, actualConfig);
}
assertNoConfigChangeCallback();
}
public void expectOffloadStatusChanged(final int expectedStatus) {
assertOffloadStatusChangedCallback();
- assertEquals(mOffloadStatus.remove(0), new Integer(expectedStatus));
+ assertEquals(Integer.valueOf(expectedStatus), mOffloadStatus.remove(0));
}
public TetherStatesParcel pollTetherStatesChanged() {
@@ -1880,12 +2238,12 @@
private void assertTetherConfigParcelEqual(@NonNull TetheringConfigurationParcel actual,
@NonNull TetheringConfigurationParcel expect) {
- assertArrayEquals(actual.tetherableUsbRegexs, expect.tetherableUsbRegexs);
- assertArrayEquals(actual.tetherableWifiRegexs, expect.tetherableWifiRegexs);
- assertArrayEquals(actual.tetherableBluetoothRegexs, expect.tetherableBluetoothRegexs);
- assertArrayEquals(actual.legacyDhcpRanges, expect.legacyDhcpRanges);
- assertArrayEquals(actual.provisioningApp, expect.provisioningApp);
- assertEquals(actual.provisioningAppNoUi, expect.provisioningAppNoUi);
+ assertArrayEquals(expect.tetherableUsbRegexs, actual.tetherableUsbRegexs);
+ assertArrayEquals(expect.tetherableWifiRegexs, actual.tetherableWifiRegexs);
+ assertArrayEquals(expect.tetherableBluetoothRegexs, actual.tetherableBluetoothRegexs);
+ assertArrayEquals(expect.legacyDhcpRanges, actual.legacyDhcpRanges);
+ assertArrayEquals(expect.provisioningApp, actual.provisioningApp);
+ assertEquals(expect.provisioningAppNoUi, actual.provisioningAppNoUi);
}
}
diff --git a/framework-t/src/android/net/IpSecManager.java b/framework-t/src/android/net/IpSecManager.java
index c8469b1..3afa6ef 100644
--- a/framework-t/src/android/net/IpSecManager.java
+++ b/framework-t/src/android/net/IpSecManager.java
@@ -273,7 +273,7 @@
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
- mCloseGuard.open("open");
+ mCloseGuard.open("close");
}
/** @hide */
diff --git a/framework-t/src/android/net/IpSecTransform.java b/framework-t/src/android/net/IpSecTransform.java
index 68ae5de..c236b6c 100644
--- a/framework-t/src/android/net/IpSecTransform.java
+++ b/framework-t/src/android/net/IpSecTransform.java
@@ -126,7 +126,7 @@
checkResultStatus(status);
mResourceId = result.resourceId;
Log.d(TAG, "Added Transform with Id " + mResourceId);
- mCloseGuard.open("build");
+ mCloseGuard.open("close");
} catch (ServiceSpecificException e) {
throw IpSecManager.rethrowUncheckedExceptionFromServiceSpecificException(e);
}
diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java
index b2da371..f633a8f 100644
--- a/framework-t/src/android/net/NetworkTemplate.java
+++ b/framework-t/src/android/net/NetworkTemplate.java
@@ -88,18 +88,6 @@
public static final int MATCH_WIFI = 4;
/** Match rule to match ethernet networks. */
public static final int MATCH_ETHERNET = 5;
- /**
- * Match rule to match all cellular networks.
- *
- * @hide
- */
- public static final int MATCH_MOBILE_WILDCARD = 6;
- /**
- * Match rule to match all wifi networks.
- *
- * @hide
- */
- public static final int MATCH_WIFI_WILDCARD = 7;
/** Match rule to match bluetooth networks. */
public static final int MATCH_BLUETOOTH = 8;
/**
@@ -177,8 +165,6 @@
case MATCH_MOBILE:
case MATCH_WIFI:
case MATCH_ETHERNET:
- case MATCH_MOBILE_WILDCARD:
- case MATCH_WIFI_WILDCARD:
case MATCH_BLUETOOTH:
case MATCH_PROXY:
case MATCH_CARRIER:
@@ -258,7 +244,6 @@
}
private final int mMatchRule;
- private final String mSubscriberId;
/**
* Ugh, templates are designed to target a single subscriber, but we might
@@ -285,9 +270,8 @@
private static void checkValidMatchSubscriberIds(int matchRule, String[] matchSubscriberIds) {
switch (matchRule) {
- case MATCH_MOBILE:
case MATCH_CARRIER:
- // MOBILE and CARRIER templates must always specify a subscriber ID.
+ // CARRIER templates must always specify a valid subscriber ID.
if (matchSubscriberIds.length == 0) {
throw new IllegalArgumentException("checkValidMatchSubscriberIds with empty"
+ " list of ids for rule" + getMatchRuleName(matchRule));
@@ -313,21 +297,20 @@
// to metered networks. It is now possible to match mobile with any meteredness, but
// in order to preserve backward compatibility of @UnsupportedAppUsage methods, this
//constructor passes METERED_YES for these types.
- this(matchRule, subscriberId, new String[] { subscriberId },
+ this(matchRule, new String[] { subscriberId },
wifiNetworkKey != null ? new String[] { wifiNetworkKey } : new String[0],
- (matchRule == MATCH_MOBILE || matchRule == MATCH_MOBILE_WILDCARD
- || matchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
+ (matchRule == MATCH_MOBILE || matchRule == MATCH_CARRIER)
+ ? METERED_YES : METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
}
/** @hide */
- public NetworkTemplate(int matchRule, String subscriberId, String[] matchSubscriberIds,
- String[] matchWifiNetworkKeys, int metered, int roaming,
- int defaultNetwork, int ratType, int oemManaged) {
+ public NetworkTemplate(int matchRule, String[] matchSubscriberIds,
+ String[] matchWifiNetworkKeys, int metered, int roaming, int defaultNetwork,
+ int ratType, int oemManaged) {
Objects.requireNonNull(matchWifiNetworkKeys);
Objects.requireNonNull(matchSubscriberIds);
mMatchRule = matchRule;
- mSubscriberId = subscriberId;
mMatchSubscriberIds = matchSubscriberIds;
mMatchWifiNetworkKeys = matchWifiNetworkKeys;
mMetered = metered;
@@ -344,7 +327,6 @@
private NetworkTemplate(Parcel in) {
mMatchRule = in.readInt();
- mSubscriberId = in.readString();
mMatchSubscriberIds = in.createStringArray();
mMatchWifiNetworkKeys = in.createStringArray();
mMetered = in.readInt();
@@ -357,7 +339,6 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
dest.writeInt(mMatchRule);
- dest.writeString(mSubscriberId);
dest.writeStringArray(mMatchSubscriberIds);
dest.writeStringArray(mMatchWifiNetworkKeys);
dest.writeInt(mMetered);
@@ -376,10 +357,6 @@
public String toString() {
final StringBuilder builder = new StringBuilder("NetworkTemplate: ");
builder.append("matchRule=").append(getMatchRuleName(mMatchRule));
- if (mSubscriberId != null) {
- builder.append(", subscriberId=").append(
- NetworkIdentityUtils.scrubSubscriberId(mSubscriberId));
- }
if (mMatchSubscriberIds != null) {
builder.append(", matchSubscriberIds=").append(
Arrays.toString(NetworkIdentityUtils.scrubSubscriberIds(mMatchSubscriberIds)));
@@ -406,7 +383,7 @@
@Override
public int hashCode() {
- return Objects.hash(mMatchRule, mSubscriberId, Arrays.hashCode(mMatchWifiNetworkKeys),
+ return Objects.hash(mMatchRule, Arrays.hashCode(mMatchWifiNetworkKeys),
mMetered, mRoaming, mDefaultNetwork, mRatType, mOemManaged);
}
@@ -415,7 +392,6 @@
if (obj instanceof NetworkTemplate) {
final NetworkTemplate other = (NetworkTemplate) obj;
return mMatchRule == other.mMatchRule
- && Objects.equals(mSubscriberId, other.mSubscriberId)
&& mMetered == other.mMetered
&& mRoaming == other.mRoaming
&& mDefaultNetwork == other.mDefaultNetwork
@@ -426,42 +402,25 @@
return false;
}
- /** @hide */
- public boolean isMatchRuleMobile() {
- switch (mMatchRule) {
- case MATCH_MOBILE:
- case MATCH_MOBILE_WILDCARD:
- return true;
- default:
- return false;
- }
- }
-
/**
* Get match rule of the template. See {@code MATCH_*}.
*/
- @UnsupportedAppUsage
public int getMatchRule() {
- // Wildcard rules are not exposed. For external callers, convert wildcard rules to
- // exposed rules before returning.
- switch (mMatchRule) {
- case MATCH_MOBILE_WILDCARD:
- return MATCH_MOBILE;
- case MATCH_WIFI_WILDCARD:
- return MATCH_WIFI;
- default:
- return mMatchRule;
- }
+ return mMatchRule;
}
/**
* Get subscriber Id of the template.
+ *
+ * @deprecated User should use {@link #getSubscriberIds} instead.
* @hide
*/
+ @Deprecated
@Nullable
- @UnsupportedAppUsage
+ @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
+ publicAlternatives = "Caller should use {@code getSubscriberIds} instead.")
public String getSubscriberId() {
- return mSubscriberId;
+ return CollectionUtils.isEmpty(mMatchSubscriberIds) ? null : mMatchSubscriberIds[0];
}
/**
@@ -548,10 +507,6 @@
return matchesWifi(ident);
case MATCH_ETHERNET:
return matchesEthernet(ident);
- case MATCH_MOBILE_WILDCARD:
- return matchesMobileWildcard(ident);
- case MATCH_WIFI_WILDCARD:
- return matchesWifiWildcard(ident);
case MATCH_BLUETOOTH:
return matchesBluetooth(ident);
case MATCH_PROXY:
@@ -632,9 +587,9 @@
// TODO: consider matching against WiMAX subscriber identity
return true;
} else {
- return ident.mType == TYPE_MOBILE && !CollectionUtils.isEmpty(mMatchSubscriberIds)
- && CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId)
- && matchesCollapsedRatType(ident);
+ return (CollectionUtils.isEmpty(mMatchSubscriberIds)
+ || CollectionUtils.contains(mMatchSubscriberIds, ident.mSubscriberId))
+ && (ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident));
}
}
@@ -646,6 +601,8 @@
case TYPE_WIFI:
return matchesSubscriberId(ident.mSubscriberId)
&& matchesWifiNetworkKey(ident.mWifiNetworkKey);
+ case TYPE_WIFI_P2P:
+ return CollectionUtils.isEmpty(mMatchWifiNetworkKeys);
default:
return false;
}
@@ -681,24 +638,6 @@
|| CollectionUtils.contains(mMatchWifiNetworkKeys, ident.mWifiNetworkKey)));
}
- private boolean matchesMobileWildcard(NetworkIdentity ident) {
- if (ident.mType == TYPE_WIMAX) {
- return true;
- } else {
- return ident.mType == TYPE_MOBILE && matchesCollapsedRatType(ident);
- }
- }
-
- private boolean matchesWifiWildcard(NetworkIdentity ident) {
- switch (ident.mType) {
- case TYPE_WIFI:
- case TYPE_WIFI_P2P:
- return true;
- default:
- return false;
- }
- }
-
/**
* Check if matches Bluetooth network template.
*/
@@ -724,10 +663,6 @@
return "WIFI";
case MATCH_ETHERNET:
return "ETHERNET";
- case MATCH_MOBILE_WILDCARD:
- return "MOBILE_WILDCARD";
- case MATCH_WIFI_WILDCARD:
- return "WIFI_WILDCARD";
case MATCH_BLUETOOTH:
return "BLUETOOTH";
case MATCH_PROXY:
@@ -775,20 +710,20 @@
// information. For instances:
// The TYPE_WIFI with subscriberId means that it is a merged carrier wifi network.
// The TYPE_CARRIER means that the network associate to specific carrier network.
- if (template.mSubscriberId == null) return template;
- if (CollectionUtils.contains(merged, template.mSubscriberId)) {
+ if (CollectionUtils.isEmpty(template.mMatchSubscriberIds)) return template;
+
+ if (CollectionUtils.contains(merged, template.mMatchSubscriberIds[0])) {
// Requested template subscriber is part of the merge group; return
// a template that matches all merged subscribers.
final String[] matchWifiNetworkKeys = template.mMatchWifiNetworkKeys;
// TODO: Use NetworkTemplate.Builder to build a template after NetworkTemplate
// could handle incompatible subscriberIds. See b/217805241.
- return new NetworkTemplate(template.mMatchRule, merged[0], merged,
+ return new NetworkTemplate(template.mMatchRule, merged,
CollectionUtils.isEmpty(matchWifiNetworkKeys)
? new String[0] : new String[] { matchWifiNetworkKeys[0] },
- (template.mMatchRule == MATCH_MOBILE
- || template.mMatchRule == MATCH_MOBILE_WILDCARD
- || template.mMatchRule == MATCH_CARRIER) ? METERED_YES : METERED_ALL,
+ (template.mMatchRule == MATCH_MOBILE || template.mMatchRule == MATCH_CARRIER)
+ ? METERED_YES : METERED_ALL,
ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL);
}
@@ -956,10 +891,7 @@
* @param matchRule the target match rule to be checked.
*/
private static void assertRequestableMatchRule(final int matchRule) {
- if (!isKnownMatchRule(matchRule)
- || matchRule == MATCH_PROXY
- || matchRule == MATCH_MOBILE_WILDCARD
- || matchRule == MATCH_WIFI_WILDCARD) {
+ if (!isKnownMatchRule(matchRule) || matchRule == MATCH_PROXY) {
throw new IllegalArgumentException("Invalid match rule: "
+ getMatchRuleName(matchRule));
}
@@ -980,20 +912,6 @@
}
/**
- * For backward compatibility, deduce match rule to a wildcard match rule
- * if the Subscriber Ids are empty.
- */
- private int getWildcardDeducedMatchRule() {
- if (mMatchRule == MATCH_MOBILE && mMatchSubscriberIds.isEmpty()) {
- return MATCH_MOBILE_WILDCARD;
- } else if (mMatchRule == MATCH_WIFI && mMatchSubscriberIds.isEmpty()
- && mMatchWifiNetworkKeys.isEmpty()) {
- return MATCH_WIFI_WILDCARD;
- }
- return mMatchRule;
- }
-
- /**
* Builds the instance of the NetworkTemplate.
*
* @return the built instance of NetworkTemplate.
@@ -1001,8 +919,7 @@
@NonNull
public NetworkTemplate build() {
assertRequestableParameters();
- return new NetworkTemplate(getWildcardDeducedMatchRule(),
- mMatchSubscriberIds.isEmpty() ? null : mMatchSubscriberIds.iterator().next(),
+ return new NetworkTemplate(mMatchRule,
mMatchSubscriberIds.toArray(new String[0]),
mMatchWifiNetworkKeys.toArray(new String[0]), mMetered, mRoaming,
mDefaultNetwork, mRatType, mOemManaged);
diff --git a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
index 0605abe..51683de 100644
--- a/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
+++ b/service-t/src/com/android/server/ethernet/EthernetNetworkFactory.java
@@ -491,10 +491,19 @@
mDeps.makeIpClient(mContext, name, mIpClientCallback);
mIpClientCallback.awaitIpClientStart();
+ if (mIpConfig.getProxySettings() == ProxySettings.STATIC
+ || mIpConfig.getProxySettings() == ProxySettings.PAC) {
+ mIpClient.setHttpProxy(mIpConfig.getHttpProxy());
+ }
+
if (sTcpBufferSizes == null) {
sTcpBufferSizes = mDeps.getTcpBufferSizesFromResource(mContext);
}
- provisionIpClient(mIpClient, mIpConfig, sTcpBufferSizes);
+ if (!TextUtils.isEmpty(sTcpBufferSizes)) {
+ mIpClient.setTcpBufferSizes(sTcpBufferSizes);
+ }
+
+ mIpClient.startProvisioning(createProvisioningConfiguration(mIpConfig));
}
void onIpLayerStarted(@NonNull final LinkProperties linkProperties) {
@@ -635,20 +644,6 @@
mRequestIds.clear();
}
- private static void provisionIpClient(@NonNull final IpClientManager ipClient,
- @NonNull final IpConfiguration config, @NonNull final String tcpBufferSizes) {
- if (config.getProxySettings() == ProxySettings.STATIC ||
- config.getProxySettings() == ProxySettings.PAC) {
- ipClient.setHttpProxy(config.getHttpProxy());
- }
-
- if (!TextUtils.isEmpty(tcpBufferSizes)) {
- ipClient.setTcpBufferSizes(tcpBufferSizes);
- }
-
- ipClient.startProvisioning(createProvisioningConfiguration(config));
- }
-
private static ProvisioningConfiguration createProvisioningConfiguration(
@NonNull final IpConfiguration config) {
if (config.getIpAssignment() == IpAssignment.STATIC) {
diff --git a/service-t/src/com/android/server/mdns/MdnsAnnouncer.java b/service-t/src/com/android/server/mdns/MdnsAnnouncer.java
index 7c84323..27fc945 100644
--- a/service-t/src/com/android/server/mdns/MdnsAnnouncer.java
+++ b/service-t/src/com/android/server/mdns/MdnsAnnouncer.java
@@ -30,23 +30,27 @@
*
* This allows maintaining other hosts' caches up-to-date. See RFC6762 8.3.
*/
-public class MdnsAnnouncer extends MdnsPacketRepeater<MdnsAnnouncer.AnnouncementInfo> {
+public class MdnsAnnouncer extends MdnsPacketRepeater<MdnsAnnouncer.BaseAnnouncementInfo> {
private static final long ANNOUNCEMENT_INITIAL_DELAY_MS = 1000L;
@VisibleForTesting
static final int ANNOUNCEMENT_COUNT = 8;
+ // Matches delay and GoodbyeCount used by the legacy implementation
+ private static final long EXIT_DELAY_MS = 2000L;
+ private static final int EXIT_COUNT = 3;
+
@NonNull
private final String mLogTag;
- /** Announcement request to send with {@link MdnsAnnouncer}. */
- public static class AnnouncementInfo implements MdnsPacketRepeater.Request {
+ /** Base class for announcement requests to send with {@link MdnsAnnouncer}. */
+ public abstract static class BaseAnnouncementInfo implements MdnsPacketRepeater.Request {
+ private final int mServiceId;
@NonNull
private final MdnsPacket mPacket;
- AnnouncementInfo(List<MdnsRecord> announcedRecords, List<MdnsRecord> additionalRecords) {
- // Records to announce (as answers)
- // Records to place in the "Additional records", with NSEC negative responses
- // to mark records that have been verified unique
+ protected BaseAnnouncementInfo(int serviceId, @NonNull List<MdnsRecord> announcedRecords,
+ @NonNull List<MdnsRecord> additionalRecords) {
+ mServiceId = serviceId;
final int flags = 0x8400; // Response, authoritative (rfc6762 18.4)
mPacket = new MdnsPacket(flags,
Collections.emptyList() /* questions */,
@@ -55,10 +59,22 @@
additionalRecords);
}
+ public int getServiceId() {
+ return mServiceId;
+ }
+
@Override
public MdnsPacket getPacket(int index) {
return mPacket;
}
+ }
+
+ /** Announcement request to send with {@link MdnsAnnouncer}. */
+ public static class AnnouncementInfo extends BaseAnnouncementInfo {
+ AnnouncementInfo(int serviceId, List<MdnsRecord> announcedRecords,
+ List<MdnsRecord> additionalRecords) {
+ super(serviceId, announcedRecords, additionalRecords);
+ }
@Override
public long getDelayMs(int nextIndex) {
@@ -72,9 +88,26 @@
}
}
+ /** Service exit announcement request to send with {@link MdnsAnnouncer}. */
+ public static class ExitAnnouncementInfo extends BaseAnnouncementInfo {
+ ExitAnnouncementInfo(int serviceId, List<MdnsRecord> announcedRecords) {
+ super(serviceId, announcedRecords, Collections.emptyList() /* additionalRecords */);
+ }
+
+ @Override
+ public long getDelayMs(int nextIndex) {
+ return EXIT_DELAY_MS;
+ }
+
+ @Override
+ public int getNumSends() {
+ return EXIT_COUNT;
+ }
+ }
+
public MdnsAnnouncer(@NonNull String interfaceTag, @NonNull Looper looper,
@NonNull MdnsReplySender replySender,
- @Nullable PacketRepeaterCallback<AnnouncementInfo> cb) {
+ @Nullable PacketRepeaterCallback<BaseAnnouncementInfo> cb) {
super(looper, replySender, cb);
mLogTag = MdnsAnnouncer.class.getSimpleName() + "/" + interfaceTag;
}
diff --git a/service-t/src/com/android/server/mdns/MdnsInterfaceAdvertiser.java b/service-t/src/com/android/server/mdns/MdnsInterfaceAdvertiser.java
index 997dcbb..790e69a 100644
--- a/service-t/src/com/android/server/mdns/MdnsInterfaceAdvertiser.java
+++ b/service-t/src/com/android/server/mdns/MdnsInterfaceAdvertiser.java
@@ -25,6 +25,7 @@
import android.util.Log;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo;
import com.android.server.connectivity.mdns.MdnsPacketRepeater.PacketRepeaterCallback;
import java.io.IOException;
@@ -113,9 +114,22 @@
/**
* Callbacks from {@link MdnsAnnouncer}.
*/
- private class AnnouncingCallback
- implements PacketRepeaterCallback<MdnsAnnouncer.AnnouncementInfo> {
- // TODO: implement
+ private class AnnouncingCallback implements PacketRepeaterCallback<BaseAnnouncementInfo> {
+ @Override
+ public void onSent(int index, @NonNull BaseAnnouncementInfo info) {
+ mRecordRepository.onAdvertisementSent(info.getServiceId());
+ }
+
+ @Override
+ public void onFinished(@NonNull BaseAnnouncementInfo info) {
+ if (info instanceof MdnsAnnouncer.ExitAnnouncementInfo) {
+ mRecordRepository.removeService(info.getServiceId());
+
+ if (mRecordRepository.getServicesCount() == 0) {
+ destroyNow();
+ }
+ }
+ }
}
/**
@@ -139,7 +153,7 @@
/** @see MdnsAnnouncer */
public MdnsAnnouncer makeMdnsAnnouncer(@NonNull String interfaceTag, @NonNull Looper looper,
@NonNull MdnsReplySender replySender,
- @Nullable PacketRepeaterCallback<MdnsAnnouncer.AnnouncementInfo> cb) {
+ @Nullable PacketRepeaterCallback<MdnsAnnouncer.BaseAnnouncementInfo> cb) {
return new MdnsAnnouncer(interfaceTag, looper, replySender, cb);
}
@@ -210,9 +224,10 @@
* This will trigger exit announcements for the service.
*/
public void removeService(int id) {
+ if (!mRecordRepository.hasActiveService(id)) return;
mProber.stop(id);
mAnnouncer.stop(id);
- final MdnsAnnouncer.AnnouncementInfo exitInfo = mRecordRepository.exitService(id);
+ final MdnsAnnouncer.ExitAnnouncementInfo exitInfo = mRecordRepository.exitService(id);
if (exitInfo != null) {
// This effectively schedules destroyNow(), as it is to be called when the exit
// announcement finishes if there is no service left.
diff --git a/service-t/src/com/android/server/mdns/MdnsNsecRecord.java b/service-t/src/com/android/server/mdns/MdnsNsecRecord.java
index 06fdd5e..6ec2f99 100644
--- a/service-t/src/com/android/server/mdns/MdnsNsecRecord.java
+++ b/service-t/src/com/android/server/mdns/MdnsNsecRecord.java
@@ -17,12 +17,14 @@
package com.android.server.connectivity.mdns;
import android.net.DnsResolver;
+import android.text.TextUtils;
import com.android.net.module.util.CollectionUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Objects;
/**
* A mDNS "NSEC" record, used in particular for negative responses (RFC6762 6.1).
@@ -140,4 +142,30 @@
writer.writeUInt8(bytesInBlock);
writer.writeBytes(bytes);
}
+
+ @Override
+ public String toString() {
+ return "NSEC: NextDomain: " + TextUtils.join(".", mNextDomain)
+ + " Types " + Arrays.toString(mTypes);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(super.hashCode(),
+ Arrays.hashCode(mNextDomain), Arrays.hashCode(mTypes));
+ }
+
+ @Override
+ public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof MdnsNsecRecord)) {
+ return false;
+ }
+
+ return super.equals(other)
+ && Arrays.equals(mNextDomain, ((MdnsNsecRecord) other).mNextDomain)
+ && Arrays.equals(mTypes, ((MdnsNsecRecord) other).mTypes);
+ }
}
diff --git a/service-t/src/com/android/server/mdns/MdnsRecordRepository.java b/service-t/src/com/android/server/mdns/MdnsRecordRepository.java
index bb9c751..dd00212 100644
--- a/service-t/src/com/android/server/mdns/MdnsRecordRepository.java
+++ b/service-t/src/com/android/server/mdns/MdnsRecordRepository.java
@@ -18,21 +18,32 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TargetApi;
import android.net.LinkAddress;
import android.net.nsd.NsdServiceInfo;
+import android.os.Build;
import android.os.Looper;
+import android.os.SystemClock;
+import android.util.ArraySet;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.CollectionUtils;
+import com.android.net.module.util.HexDump;
import java.io.IOException;
+import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
+import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -41,6 +52,7 @@
*
* Must be used on a consistent looper thread.
*/
+@TargetApi(Build.VERSION_CODES.TIRAMISU) // Allow calling T+ APIs; this is only loaded on T+
public class MdnsRecordRepository {
// TTLs as per RFC6762 10.
// TTL for records with a host name as the resource record's name (e.g., A, AAAA, HINFO) or a
@@ -61,6 +73,8 @@
@NonNull
private final SparseArray<ServiceRegistration> mServices = new SparseArray<>();
@NonNull
+ private final List<RecordInfo<?>> mGeneralRecords = new ArrayList<>();
+ @NonNull
private final Looper mLooper;
@NonNull
private String[] mDeviceHostname;
@@ -124,6 +138,12 @@
*/
public boolean isProbing;
+ /**
+ * Last time (as per SystemClock.elapsedRealtime) when sent via unicast or multicast,
+ * 0 if never
+ */
+ public long lastSentTimeMs;
+
RecordInfo(NsdServiceInfo serviceInfo, T record, boolean sharedName,
boolean probing) {
this.serviceInfo = serviceInfo;
@@ -221,7 +241,29 @@
* Inform the repository of the latest interface addresses.
*/
public void updateAddresses(@NonNull List<LinkAddress> newAddresses) {
- // TODO: implement to update addresses in records
+ mGeneralRecords.clear();
+ for (LinkAddress addr : newAddresses) {
+ final String[] revDnsAddr = getReverseDnsAddress(addr.getAddress());
+ mGeneralRecords.add(new RecordInfo<>(
+ null /* serviceInfo */,
+ new MdnsPointerRecord(
+ revDnsAddr,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ NAME_RECORDS_TTL_MILLIS,
+ mDeviceHostname),
+ false /* sharedName */, false /* probing */));
+
+ mGeneralRecords.add(new RecordInfo<>(
+ null /* serviceInfo */,
+ new MdnsInetAddressRecord(
+ mDeviceHostname,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ NAME_RECORDS_TTL_MILLIS,
+ addr.getAddress()),
+ false /* sharedName */, false /* probing */));
+ }
}
/**
@@ -298,20 +340,31 @@
* @return The exit announcement to indicate the service was removed, or null if not necessary.
*/
@Nullable
- public MdnsAnnouncer.AnnouncementInfo exitService(int id) {
+ public MdnsAnnouncer.ExitAnnouncementInfo exitService(int id) {
final ServiceRegistration registration = mServices.get(id);
if (registration == null) return null;
if (registration.exiting) return null;
- registration.exiting = true;
+ // Send exit (TTL 0) for the PTR record, if the record was sent (in particular don't send
+ // if still probing)
+ if (registration.ptrRecord.lastSentTimeMs == 0L) {
+ return null;
+ }
- // TODO: implement
- return null;
+ registration.exiting = true;
+ final MdnsPointerRecord expiredRecord = new MdnsPointerRecord(
+ registration.ptrRecord.record.getName(),
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 0L /* ttlMillis */,
+ registration.ptrRecord.record.getPointer());
+
+ // Exit should be skipped if the record is still advertised by another service, but that
+ // would be a conflict (2 service registrations with the same service name), so it would
+ // not have been allowed by the repository.
+ return new MdnsAnnouncer.ExitAnnouncementInfo(id, Collections.singletonList(expiredRecord));
}
- /**
- * Remove a service from the repository
- */
public void removeService(int id) {
mServices.remove(id);
}
@@ -338,14 +391,110 @@
}
/**
+ * Add NSEC records indicating that the response records are unique.
+ *
+ * Following RFC6762 6.1:
+ * "On receipt of a question for a particular name, rrtype, and rrclass, for which a responder
+ * does have one or more unique answers, the responder MAY also include an NSEC record in the
+ * Additional Record Section indicating the nonexistence of other rrtypes for that name and
+ * rrclass."
+ * @param destinationList List to add the NSEC records to.
+ * @param answerRecords Lists of answered records based on which to add NSEC records (typically
+ * answer and additionalAnswer sections)
+ */
+ @SafeVarargs
+ private static void addNsecRecordsForUniqueNames(
+ List<MdnsRecord> destinationList,
+ Iterator<RecordInfo<?>>... answerRecords) {
+ // Group unique records by name. Use a TreeMap with comparator as arrays don't implement
+ // equals / hashCode.
+ final Map<String[], List<MdnsRecord>> nsecByName = new TreeMap<>(Arrays::compare);
+ // But keep the list of names in added order, otherwise records would be sorted in
+ // alphabetical order instead of the order of the original records, which would look like
+ // inconsistent behavior depending on service name.
+ final List<String[]> namesInAddedOrder = new ArrayList<>();
+ for (Iterator<RecordInfo<?>> answers : answerRecords) {
+ addNonSharedRecordsToMap(answers, nsecByName, namesInAddedOrder);
+ }
+
+ for (String[] nsecName : namesInAddedOrder) {
+ final List<MdnsRecord> entryRecords = nsecByName.get(nsecName);
+ long minTtl = Long.MAX_VALUE;
+ final Set<Integer> types = new ArraySet<>(entryRecords.size());
+ for (MdnsRecord record : entryRecords) {
+ if (minTtl > record.getTtl()) minTtl = record.getTtl();
+ types.add(record.getType());
+ }
+
+ destinationList.add(new MdnsNsecRecord(
+ nsecName,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ minTtl,
+ nsecName,
+ CollectionUtils.toIntArray(types)));
+ }
+ }
+
+ /**
+ * Add non-shared records to a map listing them by record name, and to a list of names that
+ * remembers the adding order.
+ *
+ * In the destination map records are grouped by name; so the map has one key per record name,
+ * and the values are the lists of different records that share the same name.
+ * @param records Records to scan.
+ * @param dest Map to add the records to.
+ * @param namesInAddedOrder List of names to add the names in order, keeping the first
+ * occurrence of each name.
+ */
+ private static void addNonSharedRecordsToMap(
+ Iterator<RecordInfo<?>> records,
+ Map<String[], List<MdnsRecord>> dest,
+ List<String[]> namesInAddedOrder) {
+ while (records.hasNext()) {
+ final RecordInfo<?> record = records.next();
+ if (record.isSharedName) continue;
+ final List<MdnsRecord> recordsForName = dest.computeIfAbsent(record.record.name,
+ key -> {
+ namesInAddedOrder.add(key);
+ return new ArrayList<>();
+ });
+ recordsForName.add(record.record);
+ }
+ }
+
+ /**
* Called to indicate that probing succeeded for a service.
* @param probeSuccessInfo The successful probing info.
* @return The {@link MdnsAnnouncer.AnnouncementInfo} to send, now that probing has succeeded.
*/
public MdnsAnnouncer.AnnouncementInfo onProbingSucceeded(
- MdnsProber.ProbingInfo probeSuccessInfo) throws IOException {
- // TODO: implement: set service as not probing anymore and generate announcements
- throw new IOException("Announcements not implemented");
+ MdnsProber.ProbingInfo probeSuccessInfo)
+ throws IOException {
+
+ final ServiceRegistration registration = mServices.get(probeSuccessInfo.getServiceId());
+ if (registration == null) throw new IOException(
+ "Service is not registered: " + probeSuccessInfo.getServiceId());
+ registration.setProbing(false);
+
+ final ArrayList<MdnsRecord> answers = new ArrayList<>();
+ final ArrayList<MdnsRecord> additionalAnswers = new ArrayList<>();
+
+ // Interface address records in general records
+ for (RecordInfo<?> record : mGeneralRecords) {
+ answers.add(record.record);
+ }
+
+ // All service records
+ for (RecordInfo<?> info : registration.allRecords) {
+ answers.add(info.record);
+ }
+
+ addNsecRecordsForUniqueNames(additionalAnswers,
+ mGeneralRecords.iterator(), registration.allRecords.iterator());
+
+ return new MdnsAnnouncer.AnnouncementInfo(probeSuccessInfo.getServiceId(),
+ answers, additionalAnswers);
}
/**
@@ -371,6 +520,60 @@
return registration.srvRecord.isProbing;
}
+ /**
+ * Return whether the repository has an active (non-exiting) service for the given ID.
+ */
+ public boolean hasActiveService(int serviceId) {
+ final ServiceRegistration registration = mServices.get(serviceId);
+ if (registration == null) return false;
+
+ return !registration.exiting;
+ }
+
+ /**
+ * Called when {@link MdnsAdvertiser} sent an advertisement for the given service.
+ */
+ public void onAdvertisementSent(int serviceId) {
+ final ServiceRegistration registration = mServices.get(serviceId);
+ if (registration == null) return;
+
+ final long now = SystemClock.elapsedRealtime();
+ for (RecordInfo<?> record : registration.allRecords) {
+ record.lastSentTimeMs = now;
+ }
+ }
+
+ /**
+ * Compute:
+ * 2001:db8::1 --> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa
+ *
+ * Or:
+ * 192.0.2.123 --> 123.2.0.192.in-addr.arpa
+ */
+ @VisibleForTesting
+ public static String[] getReverseDnsAddress(@NonNull InetAddress addr) {
+ // xxx.xxx.xxx.xxx.in-addr.arpa (up to 28 characters)
+ // or 32 hex characters separated by dots + .ip6.arpa
+ final byte[] addrBytes = addr.getAddress();
+ final List<String> out = new ArrayList<>();
+ if (addr instanceof Inet4Address) {
+ for (int i = addrBytes.length - 1; i >= 0; i--) {
+ out.add(String.valueOf(Byte.toUnsignedInt(addrBytes[i])));
+ }
+ out.add("in-addr");
+ } else {
+ final String hexAddr = HexDump.toHexString(addrBytes);
+
+ for (int i = hexAddr.length() - 1; i >= 0; i--) {
+ out.add(String.valueOf(hexAddr.charAt(i)));
+ }
+ out.add("ip6");
+ }
+ out.add("arpa");
+
+ return out.toArray(new String[0]);
+ }
+
private static String[] splitFullyQualifiedName(
@NonNull NsdServiceInfo info, @NonNull String[] serviceType) {
final String[] split = new String[serviceType.length + 1];
diff --git a/tests/common/java/android/net/netstats/NetworkTemplateTest.kt b/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
index 3c2340c..99f1e0b 100644
--- a/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
+++ b/tests/common/java/android/net/netstats/NetworkTemplateTest.kt
@@ -26,10 +26,8 @@
import android.net.NetworkTemplate.MATCH_CARRIER
import android.net.NetworkTemplate.MATCH_ETHERNET
import android.net.NetworkTemplate.MATCH_MOBILE
-import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
import android.net.NetworkTemplate.MATCH_PROXY
import android.net.NetworkTemplate.MATCH_WIFI
-import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
import android.net.NetworkTemplate.OEM_MANAGED_ALL
import android.telephony.TelephonyManager
@@ -64,10 +62,8 @@
}
// Verify hidden match rules cannot construct templates.
- listOf(MATCH_WIFI_WILDCARD, MATCH_MOBILE_WILDCARD, MATCH_PROXY).forEach {
- assertFailsWith<IllegalArgumentException> {
- NetworkTemplate.Builder(it).build()
- }
+ assertFailsWith<IllegalArgumentException> {
+ NetworkTemplate.Builder(MATCH_PROXY).build()
}
// Verify template which matches metered cellular and carrier networks with
@@ -75,10 +71,9 @@
listOf(MATCH_MOBILE, MATCH_CARRIER).forEach { matchRule ->
NetworkTemplate.Builder(matchRule).setSubscriberIds(setOf(TEST_IMSI1))
.setMeteredness(METERED_YES).build().let {
- val expectedTemplate = NetworkTemplate(matchRule, TEST_IMSI1,
- arrayOf(TEST_IMSI1), emptyArray<String>(), METERED_YES,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL)
+ val expectedTemplate = NetworkTemplate(matchRule, arrayOf(TEST_IMSI1),
+ emptyArray<String>(), METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ NETWORK_TYPE_ALL, OEM_MANAGED_ALL)
assertEquals(expectedTemplate, it)
}
}
@@ -88,10 +83,9 @@
listOf(MATCH_MOBILE, MATCH_CARRIER).forEach { matchRule ->
NetworkTemplate.Builder(matchRule).setSubscriberIds(setOf(TEST_IMSI1))
.setRoaming(ROAMING_YES).setMeteredness(METERED_YES).build().let {
- val expectedTemplate = NetworkTemplate(matchRule, TEST_IMSI1,
- arrayOf(TEST_IMSI1), emptyArray<String>(), METERED_YES,
- ROAMING_YES, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL)
+ val expectedTemplate = NetworkTemplate(matchRule, arrayOf(TEST_IMSI1),
+ emptyArray<String>(), METERED_YES, ROAMING_YES, DEFAULT_NETWORK_ALL,
+ NETWORK_TYPE_ALL, OEM_MANAGED_ALL)
assertEquals(expectedTemplate, it)
}
}
@@ -104,42 +98,39 @@
// Verify template which matches metered cellular networks,
// regardless of IMSI. See buildTemplateMobileWildcard.
NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES).build().let {
- val expectedTemplate = NetworkTemplate(MATCH_MOBILE_WILDCARD, null /*subscriberId*/,
- emptyArray<String>() /*subscriberIds*/, emptyArray<String>(),
+ val expectedTemplate = NetworkTemplate(MATCH_MOBILE,
+ emptyArray<String>() /*subscriberIds*/, emptyArray<String>() /*wifiNetworkKey*/,
METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
OEM_MANAGED_ALL)
assertEquals(expectedTemplate, it)
}
// Verify template which matches metered cellular networks and ratType.
- // See NetworkTemplate#buildTemplateMobileWithRatType.
NetworkTemplate.Builder(MATCH_MOBILE).setSubscriberIds(setOf(TEST_IMSI1))
.setMeteredness(METERED_YES).setRatType(TelephonyManager.NETWORK_TYPE_UMTS)
.build().let {
- val expectedTemplate = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1,
- arrayOf(TEST_IMSI1), emptyArray<String>(), METERED_YES,
- ROAMING_ALL, DEFAULT_NETWORK_ALL, TelephonyManager.NETWORK_TYPE_UMTS,
- OEM_MANAGED_ALL)
+ val expectedTemplate = NetworkTemplate(MATCH_MOBILE, arrayOf(TEST_IMSI1),
+ emptyArray<String>(), METERED_YES, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ TelephonyManager.NETWORK_TYPE_UMTS, OEM_MANAGED_ALL)
assertEquals(expectedTemplate, it)
}
// Verify template which matches all wifi networks,
// regardless of Wifi Network Key. See buildTemplateWifiWildcard and buildTemplateWifi.
NetworkTemplate.Builder(MATCH_WIFI).build().let {
- val expectedTemplate = NetworkTemplate(MATCH_WIFI_WILDCARD, null /*subscriberId*/,
- emptyArray<String>() /*subscriberIds*/, emptyArray<String>(),
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL)
+ val expectedTemplate = NetworkTemplate(MATCH_WIFI,
+ emptyArray<String>() /*subscriberIds*/, emptyArray<String>(), METERED_ALL,
+ ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL)
assertEquals(expectedTemplate, it)
}
// Verify template which matches wifi networks with the given Wifi Network Key.
// See buildTemplateWifi(wifiNetworkKey).
NetworkTemplate.Builder(MATCH_WIFI).setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build().let {
- val expectedTemplate = NetworkTemplate(MATCH_WIFI, null /*subscriberId*/,
- emptyArray<String>() /*subscriberIds*/, arrayOf(TEST_WIFI_KEY1),
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL)
+ val expectedTemplate =
+ NetworkTemplate(MATCH_WIFI, emptyArray<String>() /*subscriberIds*/,
+ arrayOf(TEST_WIFI_KEY1), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ NETWORK_TYPE_ALL, OEM_MANAGED_ALL)
assertEquals(expectedTemplate, it)
}
@@ -147,10 +138,9 @@
// given Wifi Network Key, and IMSI. See buildTemplateWifi(wifiNetworkKey, subscriberId).
NetworkTemplate.Builder(MATCH_WIFI).setSubscriberIds(setOf(TEST_IMSI1))
.setWifiNetworkKeys(setOf(TEST_WIFI_KEY1)).build().let {
- val expectedTemplate = NetworkTemplate(MATCH_WIFI, TEST_IMSI1,
- arrayOf(TEST_IMSI1), arrayOf(TEST_WIFI_KEY1),
- METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
- OEM_MANAGED_ALL)
+ val expectedTemplate = NetworkTemplate(MATCH_WIFI, arrayOf(TEST_IMSI1),
+ arrayOf(TEST_WIFI_KEY1), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
+ NETWORK_TYPE_ALL, OEM_MANAGED_ALL)
assertEquals(expectedTemplate, it)
}
@@ -158,7 +148,7 @@
// See buildTemplateEthernet and buildTemplateBluetooth.
listOf(MATCH_ETHERNET, MATCH_BLUETOOTH).forEach { matchRule ->
NetworkTemplate.Builder(matchRule).build().let {
- val expectedTemplate = NetworkTemplate(matchRule, null /*subscriberId*/,
+ val expectedTemplate = NetworkTemplate(matchRule,
emptyArray<String>() /*subscriberIds*/, emptyArray<String>(),
METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
OEM_MANAGED_ALL)
@@ -193,7 +183,7 @@
// Verify template which matches wifi wildcard with the given empty key set.
NetworkTemplate.Builder(MATCH_WIFI).setWifiNetworkKeys(setOf<String>()).build().let {
- val expectedTemplate = NetworkTemplate(MATCH_WIFI_WILDCARD, null /*subscriberId*/,
+ val expectedTemplate = NetworkTemplate(MATCH_WIFI,
emptyArray<String>() /*subscriberIds*/, emptyArray<String>(),
METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
OEM_MANAGED_ALL)
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 0e04a80..61b597a 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -2391,7 +2391,7 @@
getHistory().add(new CallbackEntry.BlockedStatusInt(network, blockedReasons));
}
private void assertNoBlockedStatusCallback() {
- super.assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS,
+ super.assertNoCallback(NO_CALLBACK_TIMEOUT_MS,
c -> c instanceof CallbackEntry.BlockedStatus);
}
}
@@ -2979,7 +2979,7 @@
defaultCb.eventuallyExpect(CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
entry -> cellNetwork.equals(entry.getNetwork()));
// The network should not validate again.
- wifiCb.assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS, c -> isValidatedCaps(c));
+ wifiCb.assertNoCallback(NO_CALLBACK_TIMEOUT_MS, c -> isValidatedCaps(c));
} finally {
resetAvoidBadWifi(previousAvoidBadWifi);
mHttpServer.stop();
@@ -3151,7 +3151,7 @@
*/
private void assertNoCallbackExceptCapOrLpChange(
@NonNull final TestableNetworkCallback cb) {
- cb.assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS,
+ cb.assertNoCallback(NO_CALLBACK_TIMEOUT_MS,
c -> !(c instanceof CallbackEntry.CapabilitiesChanged
|| c instanceof CallbackEntry.LinkPropertiesChanged));
}
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 7e91478..b924f65 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -57,8 +57,8 @@
import android.os.Handler
import android.os.Looper
import android.os.OutcomeReceiver
-import android.os.SystemProperties
import android.os.Process
+import android.os.SystemProperties
import android.platform.test.annotations.AppModeFull
import androidx.test.platform.app.InstrumentationRegistry
import com.android.net.module.util.ArrayTrackRecord
@@ -77,16 +77,10 @@
import com.android.testutils.assertThrows
import com.android.testutils.runAsShell
import com.android.testutils.waitForIdle
-import org.junit.After
-import org.junit.Assume.assumeFalse
-import org.junit.Assume.assumeTrue
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
import java.io.IOException
import java.net.Inet6Address
-import java.util.Random
import java.net.Socket
+import java.util.Random
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
@@ -99,6 +93,12 @@
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.test.fail
+import org.junit.After
+import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
private const val TAG = "EthernetManagerTest"
// This timeout does not affect the test duration for passing tests. It needs to be long enough to
@@ -530,12 +530,10 @@
eventuallyExpect(Lost::class) { n?.equals(it.network) ?: true }
private fun TestableNetworkCallback.assertNeverLost(n: Network? = null) =
- assertNoCallbackThat() {
- it is Lost && (n?.equals(it.network) ?: true)
- }
+ assertNoCallback { it is Lost && (n?.equals(it.network) ?: true) }
private fun TestableNetworkCallback.assertNeverAvailable(n: Network? = null) =
- assertNoCallbackThat { it is Available && (n?.equals(it.network) ?: true) }
+ assertNoCallback { it is Available && (n?.equals(it.network) ?: true) }
private fun TestableNetworkCallback.expectCapabilitiesWithInterfaceName(name: String) =
expect<CapabilitiesChanged> { it.caps.networkSpecifier == EthernetNetworkSpecifier(name) }
diff --git a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
index a9a3380..5fc3068 100644
--- a/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
+++ b/tests/cts/net/src/android/net/cts/IpSecManagerTunnelTest.java
@@ -32,10 +32,13 @@
import static android.system.OsConstants.AF_INET;
import static android.system.OsConstants.AF_INET6;
+import static com.android.compatibility.common.util.PropertyUtil.getVsrApiLevel;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
@@ -80,6 +83,11 @@
private static final String TAG = IpSecManagerTunnelTest.class.getSimpleName();
+ // Redefine this flag here so that IPsec code shipped in a mainline module can build on old
+ // platforms before FEATURE_IPSEC_TUNNEL_MIGRATION API is released.
+ private static final String FEATURE_IPSEC_TUNNEL_MIGRATION =
+ "android.software.ipsec_tunnel_migration";
+
private static final InetAddress LOCAL_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.1");
private static final InetAddress REMOTE_OUTER_4 = InetAddress.parseNumericAddress("192.0.2.2");
private static final InetAddress LOCAL_OUTER_6 =
@@ -994,6 +1002,41 @@
checkTunnelInput(innerFamily, outerFamily, useEncap, transportInTunnelMode);
}
+ /** Checks if FEATURE_IPSEC_TUNNEL_MIGRATION is enabled on the device */
+ private static boolean hasIpsecTunnelMigrateFeature() {
+ return sContext.getPackageManager().hasSystemFeature(FEATURE_IPSEC_TUNNEL_MIGRATION);
+ }
+
+ @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+ @Test
+ public void testHasIpSecTunnelMigrateFeature() throws Exception {
+ // FEATURE_IPSEC_TUNNEL_MIGRATION is required when VSR API is U/U+
+ if (getVsrApiLevel() > Build.VERSION_CODES.TIRAMISU) {
+ assertTrue(hasIpsecTunnelMigrateFeature());
+ }
+ }
+
+ @IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+ @Test
+ public void testMigrateTunnelModeTransform() throws Exception {
+ assumeTrue(mCtsNetUtils.hasIpsecTunnelsFeature());
+ assumeTrue(hasIpsecTunnelMigrateFeature());
+
+ IpSecTransform.Builder transformBuilder = new IpSecTransform.Builder(sContext);
+ transformBuilder.setEncryption(new IpSecAlgorithm(IpSecAlgorithm.CRYPT_AES_CBC, CRYPT_KEY));
+ transformBuilder.setAuthentication(
+ new IpSecAlgorithm(IpSecAlgorithm.AUTH_HMAC_SHA256, AUTH_KEY, AUTH_KEY.length * 4));
+ int spi = getRandomSpi(LOCAL_OUTER_4, REMOTE_OUTER_4);
+
+ try (IpSecManager.SecurityParameterIndex outSpi =
+ mISM.allocateSecurityParameterIndex(REMOTE_OUTER_4, spi);
+ IpSecTransform outTunnelTransform =
+ transformBuilder.buildTunnelModeTransform(LOCAL_INNER_4, outSpi)) {
+ mISM.startTunnelModeTransformMigration(
+ outTunnelTransform, LOCAL_OUTER_4_NEW, REMOTE_OUTER_4_NEW);
+ }
+ }
+
// Transport-in-Tunnel mode tests
@Test
public void testTransportInTunnelModeV4InV4() throws Exception {
diff --git a/tests/unit/java/android/net/NetworkTemplateTest.kt b/tests/unit/java/android/net/NetworkTemplateTest.kt
index c3440c5..78854fb 100644
--- a/tests/unit/java/android/net/NetworkTemplateTest.kt
+++ b/tests/unit/java/android/net/NetworkTemplateTest.kt
@@ -34,10 +34,8 @@
import android.net.NetworkStats.ROAMING_ALL
import android.net.NetworkTemplate.MATCH_CARRIER
import android.net.NetworkTemplate.MATCH_MOBILE
-import android.net.NetworkTemplate.MATCH_MOBILE_WILDCARD
import android.net.NetworkTemplate.MATCH_TEST
import android.net.NetworkTemplate.MATCH_WIFI
-import android.net.NetworkTemplate.MATCH_WIFI_WILDCARD
import android.net.NetworkTemplate.NETWORK_TYPE_ALL
import android.net.NetworkTemplate.OEM_MANAGED_ALL
import android.net.NetworkTemplate.OEM_MANAGED_NO
@@ -231,7 +229,6 @@
val templateMobileWildcard = buildTemplateMobileWildcard()
val templateMobileNullImsiWithRatType = NetworkTemplate.Builder(MATCH_MOBILE)
.setRatType(TelephonyManager.NETWORK_TYPE_UMTS).build()
-
val mobileImsi1 = buildMobileNetworkState(TEST_IMSI1)
val identMobile1 = buildNetworkIdentity(mockContext, mobileImsi1,
false /* defaultNetwork */, TelephonyManager.NETWORK_TYPE_UMTS)
@@ -447,18 +444,18 @@
@Test
fun testParcelUnparcel() {
- val templateMobile = NetworkTemplate(MATCH_MOBILE, TEST_IMSI1, arrayOf(TEST_IMSI1),
+ val templateMobile = NetworkTemplate(MATCH_MOBILE, arrayOf(TEST_IMSI1),
emptyArray<String>(), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL,
TelephonyManager.NETWORK_TYPE_LTE, OEM_MANAGED_ALL)
- val templateWifi = NetworkTemplate(MATCH_WIFI, null, emptyArray<String>(),
+ val templateWifi = NetworkTemplate(MATCH_WIFI, emptyArray<String>(),
arrayOf(TEST_WIFI_KEY1), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, 0,
OEM_MANAGED_ALL)
- val templateOem = NetworkTemplate(MATCH_MOBILE_WILDCARD, null, emptyArray<String>(),
+ val templateOem = NetworkTemplate(MATCH_MOBILE, emptyArray<String>(),
emptyArray<String>(), METERED_ALL, ROAMING_ALL, DEFAULT_NETWORK_ALL, 0,
OEM_MANAGED_YES)
- assertParcelSane(templateMobile, 9)
- assertParcelSane(templateWifi, 9)
- assertParcelSane(templateOem, 9)
+ assertParcelSane(templateMobile, 8)
+ assertParcelSane(templateWifi, 8)
+ assertParcelSane(templateOem, 8)
}
// Verify NETWORK_TYPE_* constants in NetworkTemplate do not conflict with
@@ -491,13 +488,14 @@
* @param matchType A match rule from {@code NetworkTemplate.MATCH_*} corresponding to the
* networkType.
* @param subscriberId To be populated with {@code TEST_IMSI*} only if networkType is
- * {@code TYPE_MOBILE}. May be left as null when matchType is
- * {@link NetworkTemplate.MATCH_MOBILE_WILDCARD}.
- * @param templateWifiKey Top be populated with {@code TEST_WIFI_KEY*} only if networkType is
- * {@code TYPE_WIFI}. May be left as null when matchType is
- * {@link NetworkTemplate.MATCH_WIFI_WILDCARD}.
- * @param identWifiKey If networkType is {@code TYPE_WIFI}, this value must *NOT* be null. Provide
- * one of {@code TEST_WIFI_KEY*}.
+ * {@code TYPE_MOBILE}. Note that {@code MATCH_MOBILE} with an empty subscriberId list
+ * will match any subscriber ID.
+ * @param templateWifiKey To be populated with {@code TEST_WIFI_KEY*} only if networkType is
+ * {@code TYPE_WIFI}. Note that {@code MATCH_WIFI} with both an empty subscriberId list
+ * and an empty wifiNetworkKey list will match any subscriber ID and/or any wifi network
+ * key.
+ * @param identWifiKey If networkType is {@code TYPE_WIFI}, this value must *NOT* be null.
+ * Provide one of {@code TEST_WIFI_KEY*}.
*/
private fun matchOemManagedIdent(
networkType: Int,
@@ -507,13 +505,15 @@
identWifiKey: String? = null
) {
val oemManagedStates = arrayOf(OEM_NONE, OEM_PAID, OEM_PRIVATE, OEM_PAID or OEM_PRIVATE)
- val matchSubscriberIds = arrayOf(subscriberId)
- val matchWifiNetworkKeys = arrayOf(templateWifiKey)
+ val matchSubscriberIds =
+ if (subscriberId == null) emptyArray<String>() else arrayOf(subscriberId)
+ val matchWifiNetworkKeys =
+ if (templateWifiKey == null) emptyArray<String>() else arrayOf(templateWifiKey)
- val templateOemYes = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ val templateOemYes = NetworkTemplate(matchType, matchSubscriberIds,
matchWifiNetworkKeys, METERED_ALL, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_YES)
- val templateOemAll = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ val templateOemAll = NetworkTemplate(matchType, matchSubscriberIds,
matchWifiNetworkKeys, METERED_ALL, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, OEM_MANAGED_ALL)
@@ -524,7 +524,7 @@
// Create a template with each OEM managed type and match it against the NetworkIdentity
for (templateOemManagedState in oemManagedStates) {
- val template = NetworkTemplate(matchType, subscriberId, matchSubscriberIds,
+ val template = NetworkTemplate(matchType, matchSubscriberIds,
matchWifiNetworkKeys, METERED_ALL, ROAMING_ALL,
DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL, templateOemManagedState)
if (identityOemManagedState == templateOemManagedState) {
@@ -547,11 +547,10 @@
@Test
fun testOemManagedMatchesIdent() {
matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE, subscriberId = TEST_IMSI1)
- matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE_WILDCARD)
+ matchOemManagedIdent(TYPE_MOBILE, MATCH_MOBILE)
matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, templateWifiKey = TEST_WIFI_KEY1,
identWifiKey = TEST_WIFI_KEY1)
- matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI_WILDCARD,
- identWifiKey = TEST_WIFI_KEY1)
+ matchOemManagedIdent(TYPE_WIFI, MATCH_WIFI, identWifiKey = TEST_WIFI_KEY1)
}
@Test
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 7d64c26..51f54a4 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -2806,7 +2806,8 @@
// for any other request.
generalCb.expectLosing(net2);
net2.assertNotDisconnected(TEST_CALLBACK_TIMEOUT_MS);
- generalCb.assertNoCallback();
+ // Timeout 0 because after a while LOST will actually arrive
+ generalCb.assertNoCallback(0 /* timeoutMs */);
net2.expectDisconnected(UNREASONABLY_LONG_ALARM_WAIT_MS);
} else {
net2.expectDisconnected(TEST_CALLBACK_TIMEOUT_MS);
@@ -3006,14 +3007,12 @@
*/
private class TestNetworkCallback extends TestableNetworkCallback {
TestNetworkCallback() {
- super(TEST_CALLBACK_TIMEOUT_MS);
- }
-
- @Override
- public void assertNoCallback() {
- // TODO: better support this use case in TestableNetworkCallback
- waitForIdle();
- assertNoCallback(0 /* timeout */);
+ // In the context of this test, the testable network callbacks should use waitForIdle
+ // before calling assertNoCallback in an effort to detect issues where a callback is
+ // not yet sent but a message currently in the queue of a handler will cause it to
+ // be sent soon.
+ super(TEST_CALLBACK_TIMEOUT_MS, TEST_CALLBACK_TIMEOUT_MS,
+ ConnectivityServiceTest.this::waitForIdle);
}
public CallbackEntry.Losing expectLosing(final HasNetwork n, final long timeoutMs) {
@@ -3039,9 +3038,15 @@
// Can't be part of TestNetworkCallback because "cannot be declared static; static methods can
// only be declared in a static or top level type".
+ static void assertNoCallbacks(final long timeoutMs, TestNetworkCallback ... callbacks) {
+ for (TestNetworkCallback c : callbacks) {
+ c.assertNoCallback(timeoutMs);
+ }
+ }
+
static void assertNoCallbacks(TestNetworkCallback ... callbacks) {
for (TestNetworkCallback c : callbacks) {
- c.assertNoCallback();
+ c.assertNoCallback(); // each callback uses its own timeout
}
}
@@ -3177,7 +3182,10 @@
wifiNetworkCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent);
cellNetworkCallback.expectLosing(mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
- assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
+ // Cell will disconnect after the lingering period. Before that elapses check that
+ // there have been no callbacks.
+ assertNoCallbacks(0 /* timeoutMs */,
+ genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
mWiFiNetworkAgent.disconnect();
genericNetworkCallback.expect(CallbackEntry.LOST, mWiFiNetworkAgent);
@@ -3488,7 +3496,7 @@
callback.expectLosing(mCellNetworkAgent);
// Let linger run its course.
- callback.assertNoCallback();
+ callback.assertNoCallback(0 /* timeoutMs */);
final int lingerTimeoutMs = mService.mLingerDelayMs + mService.mLingerDelayMs / 4;
callback.expect(CallbackEntry.LOST, mCellNetworkAgent, lingerTimeoutMs);
@@ -5927,7 +5935,7 @@
.clearCapabilities()
.addTransportType(TRANSPORT_WIFI)
.build();
- final TestableNetworkCallback wifiCallback = new TestableNetworkCallback();
+ final TestNetworkCallback wifiCallback = new TestNetworkCallback();
mCm.registerNetworkCallback(wifiRequest, wifiCallback);
// Bring up validated cell and unvalidated wifi.
@@ -10507,7 +10515,7 @@
mCm.unregisterNetworkCallback(networkCallback);
}
- private void expectNat64PrefixChange(TestableNetworkCallback callback,
+ private void expectNat64PrefixChange(TestNetworkCallback callback,
TestNetworkAgentWrapper agent, IpPrefix prefix) {
callback.expectLinkPropertiesThat(agent, x -> Objects.equals(x.getNat64Prefix(), prefix));
}
@@ -16409,7 +16417,7 @@
final NetworkCallback[] callbacks = new NetworkCallback[remainingCount];
doAsUid(otherAppUid, () -> {
for (int i = 0; i < remainingCount; ++i) {
- callbacks[i] = new TestableNetworkCallback();
+ callbacks[i] = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(callbacks[i]);
}
});
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
index 961f0f0..650607d 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsAnnouncerTest.kt
@@ -22,11 +22,11 @@
import android.os.SystemClock
import com.android.internal.util.HexDump
import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo
+import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo
+import com.android.server.connectivity.mdns.MdnsRecordRepository.getReverseDnsAddress
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import java.net.DatagramPacket
-import java.net.Inet6Address
-import java.net.InetAddress
import kotlin.test.assertEquals
import kotlin.test.assertTrue
import org.junit.After
@@ -68,7 +68,7 @@
private class TestAnnouncementInfo(
announcedRecords: List<MdnsRecord>,
additionalRecords: List<MdnsRecord>
- ) : AnnouncementInfo(announcedRecords, additionalRecords) {
+ ) : AnnouncementInfo(1 /* serviceId */, announcedRecords, additionalRecords) {
override fun getDelayMs(nextIndex: Int) =
if (nextIndex < FIRST_ANNOUNCES_COUNT) {
FIRST_ANNOUNCES_DELAY
@@ -82,7 +82,7 @@
val replySender = MdnsReplySender(thread.looper, socket, buffer)
@Suppress("UNCHECKED_CAST")
val cb = mock(MdnsPacketRepeater.PacketRepeaterCallback::class.java)
- as MdnsPacketRepeater.PacketRepeaterCallback<AnnouncementInfo>
+ as MdnsPacketRepeater.PacketRepeaterCallback<BaseAnnouncementInfo>
val announcer = MdnsAnnouncer("testiface", thread.looper, replySender, cb)
/*
The expected packet replicates records announced when registering a service, as observed in
@@ -150,8 +150,8 @@
val v6Addr1 = parseNumericAddress("2001:DB8::123")
val v6Addr2 = parseNumericAddress("2001:DB8::456")
val v4AddrRev = arrayOf("123", "0", "2", "192", "in-addr", "arpa")
- val v6Addr1Rev = getReverseV6AddressName(v6Addr1)
- val v6Addr2Rev = getReverseV6AddressName(v6Addr2)
+ val v6Addr1Rev = getReverseDnsAddress(v6Addr1)
+ val v6Addr2Rev = getReverseDnsAddress(v6Addr2)
val announcedRecords = listOf(
// Reverse address records
@@ -267,13 +267,3 @@
}
}
}
-
-/**
- * Compute 2001:db8::1 --> 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.1.0.0.2.ip6.arpa
- */
-private fun getReverseV6AddressName(addr: InetAddress): Array<String> {
- assertTrue(addr is Inet6Address)
- return addr.address.flatMapTo(mutableListOf("arpa", "ip6")) {
- HexDump.toHexString(it).toCharArray().map(Char::toString)
- }.reversed().toTypedArray()
-}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
index ad22305..2cb0850 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
@@ -22,6 +22,8 @@
import android.os.Build
import android.os.HandlerThread
import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo
+import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo
+import com.android.server.connectivity.mdns.MdnsAnnouncer.ExitAnnouncementInfo
import com.android.server.connectivity.mdns.MdnsInterfaceAdvertiser.EXIT_ANNOUNCEMENT_DELAY_MS
import com.android.server.connectivity.mdns.MdnsPacketRepeater.PacketRepeaterCallback
import com.android.server.connectivity.mdns.MdnsProber.ProbingInfo
@@ -35,8 +37,10 @@
import org.mockito.ArgumentCaptor
import org.mockito.Mockito.any
import org.mockito.Mockito.anyInt
+import org.mockito.Mockito.doAnswer
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
import org.mockito.Mockito.verify
private const val LOG_TAG = "testlogtag"
@@ -66,7 +70,7 @@
private val probeCbCaptor = ArgumentCaptor.forClass(PacketRepeaterCallback::class.java)
as ArgumentCaptor<PacketRepeaterCallback<ProbingInfo>>
private val announceCbCaptor = ArgumentCaptor.forClass(PacketRepeaterCallback::class.java)
- as ArgumentCaptor<PacketRepeaterCallback<AnnouncementInfo>>
+ as ArgumentCaptor<PacketRepeaterCallback<BaseAnnouncementInfo>>
private val probeCb get() = probeCbCaptor.value
private val announceCb get() = announceCbCaptor.value
@@ -82,7 +86,21 @@
doReturn(announcer).`when`(deps).makeMdnsAnnouncer(any(), any(), any(), any())
doReturn(prober).`when`(deps).makeMdnsProber(any(), any(), any(), any())
- doReturn(-1).`when`(repository).addService(anyInt(), any())
+ val knownServices = mutableSetOf<Int>()
+ doAnswer { inv ->
+ knownServices.add(inv.getArgument(0))
+ -1
+ }.`when`(repository).addService(anyInt(), any())
+ doAnswer { inv ->
+ knownServices.remove(inv.getArgument(0))
+ null
+ }.`when`(repository).removeService(anyInt())
+ doAnswer {
+ knownServices.toIntArray().also { knownServices.clear() }
+ }.`when`(repository).clearServices()
+ doAnswer { inv ->
+ knownServices.contains(inv.getArgument(0))
+ }.`when`(repository).hasActiveService(anyInt())
thread.start()
advertiser.start()
@@ -97,18 +115,7 @@
@Test
fun testAddRemoveService() {
- val testProbingInfo = mock(ProbingInfo::class.java)
- doReturn(TEST_SERVICE_ID_1).`when`(testProbingInfo).serviceId
- doReturn(testProbingInfo).`when`(repository).setServiceProbing(TEST_SERVICE_ID_1)
-
- advertiser.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
- verify(repository).addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
- verify(prober).startProbing(testProbingInfo)
-
- // Simulate probing success: continues to announcing
- val testAnnouncementInfo = mock(AnnouncementInfo::class.java)
- doReturn(testAnnouncementInfo).`when`(repository).onProbingSucceeded(testProbingInfo)
- probeCb.onFinished(testProbingInfo)
+ val testAnnouncementInfo = addServiceAndFinishProbing(TEST_SERVICE_ID_1, TEST_SERVICE_1)
verify(announcer).startSending(TEST_SERVICE_ID_1, testAnnouncementInfo,
0L /* initialDelayMs */)
@@ -117,13 +124,53 @@
verify(cb).onRegisterServiceSucceeded(advertiser, TEST_SERVICE_ID_1)
// Remove the service: expect exit announcements
- val testExitInfo = mock(AnnouncementInfo::class.java)
+ val testExitInfo = mock(ExitAnnouncementInfo::class.java)
doReturn(testExitInfo).`when`(repository).exitService(TEST_SERVICE_ID_1)
advertiser.removeService(TEST_SERVICE_ID_1)
+ verify(prober).stop(TEST_SERVICE_ID_1)
+ verify(announcer).stop(TEST_SERVICE_ID_1)
verify(announcer).startSending(TEST_SERVICE_ID_1, testExitInfo, EXIT_ANNOUNCEMENT_DELAY_MS)
- // TODO: after exit announcements are implemented, verify that announceCb.onFinished causes
- // cb.onDestroyed to be called.
+ // Exit announcements finish: the advertiser has no left service and destroys itself
+ announceCb.onFinished(testExitInfo)
+ thread.waitForIdle(TIMEOUT_MS)
+ verify(cb).onDestroyed(socket)
+ }
+
+ @Test
+ fun testDoubleRemove() {
+ addServiceAndFinishProbing(TEST_SERVICE_ID_1, TEST_SERVICE_1)
+
+ val testExitInfo = mock(ExitAnnouncementInfo::class.java)
+ doReturn(testExitInfo).`when`(repository).exitService(TEST_SERVICE_ID_1)
+ advertiser.removeService(TEST_SERVICE_ID_1)
+
+ verify(prober).stop(TEST_SERVICE_ID_1)
+ verify(announcer).stop(TEST_SERVICE_ID_1)
+ verify(announcer).startSending(TEST_SERVICE_ID_1, testExitInfo, EXIT_ANNOUNCEMENT_DELAY_MS)
+
+ doReturn(false).`when`(repository).hasActiveService(TEST_SERVICE_ID_1)
+ advertiser.removeService(TEST_SERVICE_ID_1)
+ // Prober, announcer were still stopped only one time
+ verify(prober, times(1)).stop(TEST_SERVICE_ID_1)
+ verify(announcer, times(1)).stop(TEST_SERVICE_ID_1)
+ }
+
+ private fun addServiceAndFinishProbing(serviceId: Int, serviceInfo: NsdServiceInfo):
+ AnnouncementInfo {
+ val testProbingInfo = mock(ProbingInfo::class.java)
+ doReturn(serviceId).`when`(testProbingInfo).serviceId
+ doReturn(testProbingInfo).`when`(repository).setServiceProbing(serviceId)
+
+ advertiser.addService(serviceId, serviceInfo)
+ verify(repository).addService(serviceId, serviceInfo)
+ verify(prober).startProbing(testProbingInfo)
+
+ // Simulate probing success: continues to announcing
+ val testAnnouncementInfo = mock(AnnouncementInfo::class.java)
+ doReturn(testAnnouncementInfo).`when`(repository).onProbingSucceeded(testProbingInfo)
+ probeCb.onFinished(testProbingInfo)
+ return testAnnouncementInfo
}
}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
index 502a36a..29d0854 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsRecordRepositoryTest.kt
@@ -17,10 +17,12 @@
package com.android.server.connectivity.mdns
import android.net.InetAddresses.parseNumericAddress
+import android.net.LinkAddress
import android.net.nsd.NsdServiceInfo
import android.os.Build
import android.os.HandlerThread
import com.android.server.connectivity.mdns.MdnsRecordRepository.Dependencies
+import com.android.server.connectivity.mdns.MdnsRecordRepository.getReverseDnsAddress
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
import java.net.NetworkInterface
@@ -28,6 +30,7 @@
import kotlin.test.assertContentEquals
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
+import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import org.junit.After
@@ -39,10 +42,10 @@
private const val TEST_SERVICE_ID_2 = 43
private const val TEST_PORT = 12345
private val TEST_HOSTNAME = arrayOf("Android_000102030405060708090A0B0C0D0E0F", "local")
-private val TEST_ADDRESSES = arrayOf(
- parseNumericAddress("192.0.2.111"),
- parseNumericAddress("2001:db8::111"),
- parseNumericAddress("2001:db8::222"))
+private val TEST_ADDRESSES = listOf(
+ LinkAddress(parseNumericAddress("192.0.2.111"), 24),
+ LinkAddress(parseNumericAddress("2001:db8::111"), 64),
+ LinkAddress(parseNumericAddress("2001:db8::222"), 64))
private val TEST_SERVICE_1 = NsdServiceInfo().apply {
serviceType = "_testservice._tcp"
@@ -50,6 +53,12 @@
port = TEST_PORT
}
+private val TEST_SERVICE_2 = NsdServiceInfo().apply {
+ serviceType = "_testservice._tcp"
+ serviceName = "MyOtherTestService"
+ port = TEST_PORT
+}
+
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
class MdnsRecordRepositoryTest {
@@ -57,7 +66,7 @@
private val deps = object : Dependencies() {
override fun getHostname() = TEST_HOSTNAME
override fun getInterfaceInetAddresses(iface: NetworkInterface) =
- Collections.enumeration(TEST_ADDRESSES.toList())
+ Collections.enumeration(TEST_ADDRESSES.map { it.address })
}
@Before
@@ -113,9 +122,71 @@
}
@Test
+ fun testInvalidReuseOfServiceId() {
+ val repository = MdnsRecordRepository(thread.looper, deps)
+ repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
+ assertFailsWith(IllegalArgumentException::class) {
+ repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_2)
+ }
+ }
+
+ @Test
+ fun testHasActiveService() {
+ val repository = MdnsRecordRepository(thread.looper, deps)
+ assertFalse(repository.hasActiveService(TEST_SERVICE_ID_1))
+
+ repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
+ assertTrue(repository.hasActiveService(TEST_SERVICE_ID_1))
+
+ val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1)
+ repository.onProbingSucceeded(probingInfo)
+ repository.onAdvertisementSent(TEST_SERVICE_ID_1)
+ assertTrue(repository.hasActiveService(TEST_SERVICE_ID_1))
+
+ repository.exitService(TEST_SERVICE_ID_1)
+ assertFalse(repository.hasActiveService(TEST_SERVICE_ID_1))
+ }
+
+ @Test
+ fun testExitAnnouncements() {
+ val repository = MdnsRecordRepository(thread.looper, deps)
+ repository.updateAddresses(TEST_ADDRESSES)
+
+ repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
+ val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1)
+ repository.onProbingSucceeded(probingInfo)
+ repository.onAdvertisementSent(TEST_SERVICE_ID_1)
+
+ val exitAnnouncement = repository.exitService(TEST_SERVICE_ID_1)
+ assertNotNull(exitAnnouncement)
+ assertEquals(1, repository.servicesCount)
+ val packet = exitAnnouncement.getPacket(0)
+
+ assertEquals(0x8400 /* response, authoritative */, packet.flags)
+ assertEquals(0, packet.questions.size)
+ assertEquals(0, packet.authorityRecords.size)
+ assertEquals(0, packet.additionalRecords.size)
+
+ assertContentEquals(listOf(
+ MdnsPointerRecord(
+ arrayOf("_testservice", "_tcp", "local"),
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 0L /* ttlMillis */,
+ arrayOf("MyTestService", "_testservice", "_tcp", "local"))
+ ), packet.answers)
+
+ repository.removeService(TEST_SERVICE_ID_1)
+ assertEquals(0, repository.servicesCount)
+ }
+
+ @Test
fun testExitingServiceReAdded() {
val repository = MdnsRecordRepository(thread.looper, deps)
repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
+ val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1)
+ repository.onProbingSucceeded(probingInfo)
+ repository.onAdvertisementSent(TEST_SERVICE_ID_1)
repository.exitService(TEST_SERVICE_ID_1)
assertEquals(TEST_SERVICE_ID_1, repository.addService(TEST_SERVICE_ID_2, TEST_SERVICE_1))
@@ -124,4 +195,131 @@
repository.removeService(TEST_SERVICE_ID_2)
assertEquals(0, repository.servicesCount)
}
+
+ @Test
+ fun testOnProbingSucceeded() {
+ val repository = MdnsRecordRepository(thread.looper, deps)
+ repository.updateAddresses(TEST_ADDRESSES)
+
+ repository.addService(TEST_SERVICE_ID_1, TEST_SERVICE_1)
+ val probingInfo = repository.setServiceProbing(TEST_SERVICE_ID_1)
+ val announcementInfo = repository.onProbingSucceeded(probingInfo)
+ val packet = announcementInfo.getPacket(0)
+
+ assertEquals(0x8400 /* response, authoritative */, packet.flags)
+ assertEquals(0, packet.questions.size)
+ assertEquals(0, packet.authorityRecords.size)
+
+ val serviceType = arrayOf("_testservice", "_tcp", "local")
+ val serviceName = arrayOf("MyTestService", "_testservice", "_tcp", "local")
+ val v4AddrRev = getReverseDnsAddress(TEST_ADDRESSES[0].address)
+ val v6Addr1Rev = getReverseDnsAddress(TEST_ADDRESSES[1].address)
+ val v6Addr2Rev = getReverseDnsAddress(TEST_ADDRESSES[2].address)
+
+ assertContentEquals(listOf(
+ // Reverse address and address records for the hostname
+ MdnsPointerRecord(v4AddrRev,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ TEST_HOSTNAME),
+ MdnsInetAddressRecord(TEST_HOSTNAME,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ TEST_ADDRESSES[0].address),
+ MdnsPointerRecord(v6Addr1Rev,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ TEST_HOSTNAME),
+ MdnsInetAddressRecord(TEST_HOSTNAME,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ TEST_ADDRESSES[1].address),
+ MdnsPointerRecord(v6Addr2Rev,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ TEST_HOSTNAME),
+ MdnsInetAddressRecord(TEST_HOSTNAME,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ TEST_ADDRESSES[2].address),
+ // Service registration records (RFC6763)
+ MdnsPointerRecord(
+ serviceType,
+ 0L /* receiptTimeMillis */,
+ // Not a unique name owned by the announcer, so cacheFlush=false
+ false /* cacheFlush */,
+ 4500000L /* ttlMillis */,
+ serviceName),
+ MdnsServiceRecord(
+ serviceName,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ 0 /* servicePriority */,
+ 0 /* serviceWeight */,
+ TEST_PORT /* servicePort */,
+ TEST_HOSTNAME),
+ MdnsTextRecord(
+ serviceName,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 4500000L /* ttlMillis */,
+ emptyList() /* entries */),
+ // Service type enumeration record (RFC6763 9.)
+ MdnsPointerRecord(
+ arrayOf("_services", "_dns-sd", "_udp", "local"),
+ 0L /* receiptTimeMillis */,
+ false /* cacheFlush */,
+ 4500000L /* ttlMillis */,
+ serviceType)
+ ), packet.answers)
+
+ assertContentEquals(listOf(
+ MdnsNsecRecord(v4AddrRev,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ v4AddrRev,
+ intArrayOf(MdnsRecord.TYPE_PTR)),
+ MdnsNsecRecord(TEST_HOSTNAME,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ TEST_HOSTNAME,
+ intArrayOf(MdnsRecord.TYPE_A, MdnsRecord.TYPE_AAAA)),
+ MdnsNsecRecord(v6Addr1Rev,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ v6Addr1Rev,
+ intArrayOf(MdnsRecord.TYPE_PTR)),
+ MdnsNsecRecord(v6Addr2Rev,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 120000L /* ttlMillis */,
+ v6Addr2Rev,
+ intArrayOf(MdnsRecord.TYPE_PTR)),
+ MdnsNsecRecord(serviceName,
+ 0L /* receiptTimeMillis */,
+ true /* cacheFlush */,
+ 4500000L /* ttlMillis */,
+ serviceName,
+ intArrayOf(MdnsRecord.TYPE_TXT, MdnsRecord.TYPE_SRV))
+ ), packet.additionalRecords)
+ }
+
+ @Test
+ fun testGetReverseDnsAddress() {
+ val expectedV6 = "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.8.B.D.0.1.0.0.2.ip6.arpa"
+ .split(".").toTypedArray()
+ assertContentEquals(expectedV6, getReverseDnsAddress(parseNumericAddress("2001:db8::1")))
+ val expectedV4 = "123.2.0.192.in-addr.arpa".split(".").toTypedArray()
+ assertContentEquals(expectedV4, getReverseDnsAddress(parseNumericAddress("192.0.2.123")))
+ }
}
diff --git a/tools/gn2bp/Android.bp.swp b/tools/gn2bp/Android.bp.swp
index 2398349..ebf1a9b 100644
--- a/tools/gn2bp/Android.bp.swp
+++ b/tools/gn2bp/Android.bp.swp
@@ -33,32 +33,35 @@
":cronet_aml_components_cronet_android_interface_api_version",
"components/cronet/android/api/src/android/net/http/BidirectionalStream.java",
"components/cronet/android/api/src/android/net/http/CallbackException.java",
- "components/cronet/android/api/src/android/net/http/CronetEngine.java",
- "components/cronet/android/api/src/android/net/http/CronetException.java",
+ "components/cronet/android/api/src/android/net/http/ConnectionMigrationOptions.java",
+ "components/cronet/android/api/src/android/net/http/DnsOptions.java",
"components/cronet/android/api/src/android/net/http/ExperimentalBidirectionalStream.java",
- "components/cronet/android/api/src/android/net/http/ExperimentalCronetEngine.java",
+ "components/cronet/android/api/src/android/net/http/ExperimentalHttpEngine.java",
"components/cronet/android/api/src/android/net/http/ExperimentalUrlRequest.java",
- "components/cronet/android/api/src/android/net/http/ICronetEngineBuilder.java",
+ "components/cronet/android/api/src/android/net/http/HttpEngine.java",
+ "components/cronet/android/api/src/android/net/http/HttpException.java",
+ "components/cronet/android/api/src/android/net/http/IHttpEngineBuilder.java",
"components/cronet/android/api/src/android/net/http/InlineExecutionProhibitedException.java",
"components/cronet/android/api/src/android/net/http/NetworkException.java",
"components/cronet/android/api/src/android/net/http/NetworkQualityRttListener.java",
"components/cronet/android/api/src/android/net/http/NetworkQualityThroughputListener.java",
"components/cronet/android/api/src/android/net/http/QuicException.java",
+ "components/cronet/android/api/src/android/net/http/QuicOptions.java",
"components/cronet/android/api/src/android/net/http/RequestFinishedInfo.java",
"components/cronet/android/api/src/android/net/http/UploadDataProvider.java",
"components/cronet/android/api/src/android/net/http/UploadDataSink.java",
"components/cronet/android/api/src/android/net/http/UrlRequest.java",
"components/cronet/android/api/src/android/net/http/UrlResponseInfo.java",
- "components/cronet/android/api/src/android/net/http/apihelpers/ByteArrayCronetCallback.java",
+ "components/cronet/android/api/src/android/net/http/apihelpers/ByteArrayCallback.java",
"components/cronet/android/api/src/android/net/http/apihelpers/ContentTypeParametersParser.java",
- "components/cronet/android/api/src/android/net/http/apihelpers/CronetRequestCompletionListener.java",
- "components/cronet/android/api/src/android/net/http/apihelpers/CronetResponse.java",
+ "components/cronet/android/api/src/android/net/http/apihelpers/HttpResponse.java",
"components/cronet/android/api/src/android/net/http/apihelpers/ImplicitFlowControlCallback.java",
- "components/cronet/android/api/src/android/net/http/apihelpers/InMemoryTransformCronetCallback.java",
- "components/cronet/android/api/src/android/net/http/apihelpers/JsonCronetCallback.java",
+ "components/cronet/android/api/src/android/net/http/apihelpers/InMemoryTransformCallback.java",
+ "components/cronet/android/api/src/android/net/http/apihelpers/JsonCallback.java",
"components/cronet/android/api/src/android/net/http/apihelpers/RedirectHandler.java",
"components/cronet/android/api/src/android/net/http/apihelpers/RedirectHandlers.java",
- "components/cronet/android/api/src/android/net/http/apihelpers/StringCronetCallback.java",
+ "components/cronet/android/api/src/android/net/http/apihelpers/RequestCompletionListener.java",
+ "components/cronet/android/api/src/android/net/http/apihelpers/StringCallback.java",
"components/cronet/android/api/src/android/net/http/apihelpers/UploadDataProviders.java",
"components/cronet/android/api/src/android/net/http/apihelpers/UrlRequestCallbacks.java",
],
@@ -1092,6 +1095,7 @@
"base/android/java/src/org/chromium/base/MemoryPressureListener.java",
"base/android/java/src/org/chromium/base/PathService.java",
"base/android/java/src/org/chromium/base/PathUtils.java",
+ "base/android/java/src/org/chromium/base/PiiElider.java",
"base/android/java/src/org/chromium/base/PowerMonitor.java",
"base/android/java/src/org/chromium/base/RadioUtils.java",
"base/android/java/src/org/chromium/base/SysUtils.java",
@@ -1165,6 +1169,8 @@
"--output_name " +
"PathUtils_jni.h " +
"--output_name " +
+ "PiiElider_jni.h " +
+ "--output_name " +
"PowerMonitor_jni.h " +
"--output_name " +
"RadioUtils_jni.h " +
@@ -1245,6 +1251,8 @@
"--input_file " +
"$(location base/android/java/src/org/chromium/base/PathUtils.java) " +
"--input_file " +
+ "$(location base/android/java/src/org/chromium/base/PiiElider.java) " +
+ "--input_file " +
"$(location base/android/java/src/org/chromium/base/PowerMonitor.java) " +
"--input_file " +
"$(location base/android/java/src/org/chromium/base/RadioUtils.java) " +
@@ -1309,6 +1317,7 @@
"base/base_jni_headers/NativeUmaRecorder_jni.h",
"base/base_jni_headers/PathService_jni.h",
"base/base_jni_headers/PathUtils_jni.h",
+ "base/base_jni_headers/PiiElider_jni.h",
"base/base_jni_headers/PostTask_jni.h",
"base/base_jni_headers/PowerMonitor_jni.h",
"base/base_jni_headers/RadioUtils_jni.h",
@@ -4181,6 +4190,7 @@
apex_available: [
"com.android.tethering",
],
+ min_sdk_version: "30",
libs: [
"androidx.annotation_annotation",
"androidx.annotation_annotation-experimental-nodeps",
diff --git a/tools/gn2bp/desc_arm.json b/tools/gn2bp/desc_arm.json
index b59157a..aa76d1c 100644
--- a/tools/gn2bp/desc_arm.json
+++ b/tools/gn2bp/desc_arm.json
Binary files differ
diff --git a/tools/gn2bp/desc_arm64.json b/tools/gn2bp/desc_arm64.json
index 9881124..2bdbc03 100644
--- a/tools/gn2bp/desc_arm64.json
+++ b/tools/gn2bp/desc_arm64.json
Binary files differ
diff --git a/tools/gn2bp/desc_x64.json b/tools/gn2bp/desc_x64.json
index 3a2ce2a..ddf9d3e 100644
--- a/tools/gn2bp/desc_x64.json
+++ b/tools/gn2bp/desc_x64.json
Binary files differ
diff --git a/tools/gn2bp/desc_x86.json b/tools/gn2bp/desc_x86.json
index 03bcf2f..f57f15a 100644
--- a/tools/gn2bp/desc_x86.json
+++ b/tools/gn2bp/desc_x86.json
Binary files differ
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp
index dcf8897..e10c415 100755
--- a/tools/gn2bp/gen_android_bp
+++ b/tools/gn2bp/gen_android_bp
@@ -1529,6 +1529,7 @@
module.aidl["include_dirs"] = {"frameworks/base/core/java/"}
module.aidl["local_include_dirs"] = {"base/android/java/src/"}
module.sdk_version = "module_current"
+ module.min_sdk_version = 30
module.apex_available.add(tethering_apex)
# TODO: support for this flag is removed upstream in crrev/c/4062652.
# Consider reverting this change upstream, or worst-case downstream. As an