Make change and version bump to aml_net_311411000 for mainline module file: AndroidManifest.xml

Change-Id: I5ab69daec51b09903088ff14a560bd59b279b2cb
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 9a3bac8..0a453e8 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -19,8 +19,8 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.android.networkstack"
   android:sharedUserId="android.uid.networkstack"
-  android:versionCode="311410000"
-  android:versionName="aml_net_311410000"
+  android:versionCode="311411000"
+  android:versionName="aml_net_311411000"
   coreApp="true"
 >
     <!-- Permissions must be defined here, and not in the base manifest, as the network stack
diff --git a/src/android/net/dhcp/DhcpClient.java b/src/android/net/dhcp/DhcpClient.java
index 6433e04..d20e769 100644
--- a/src/android/net/dhcp/DhcpClient.java
+++ b/src/android/net/dhcp/DhcpClient.java
@@ -747,9 +747,14 @@
     }
 
     private boolean sendDiscoverPacket() {
+        // When Rapid Commit option is enabled, limit only the first 3 DHCPDISCOVER packets
+        // taking Rapid Commit option, in order to prevent the potential interoperability issue
+        // and be able to rollback later. See {@link DHCP_TIMEOUT_MS} for the (re)transmission
+        // schedule with 10% jitter.
+        final boolean requestRapidCommit = isDhcpRapidCommitEnabled() && (getSecs() <= 4);
         final ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
                 DhcpPacket.ENCAP_L2, mTransactionId, getSecs(), mHwAddr,
-                DO_UNICAST, getRequestedParams(), isDhcpRapidCommitEnabled(), mHostname,
+                DO_UNICAST, getRequestedParams(), requestRapidCommit, mHostname,
                 mConfiguration.options);
         mMetrics.incrementCountForDiscover();
         return transmitPacket(packet, "DHCPDISCOVER", DhcpPacket.ENCAP_L2, INADDR_BROADCAST);
diff --git a/src/android/net/dhcp/DhcpPacket.java b/src/android/net/dhcp/DhcpPacket.java
index 76dc807..63c5b0c 100644
--- a/src/android/net/dhcp/DhcpPacket.java
+++ b/src/android/net/dhcp/DhcpPacket.java
@@ -321,7 +321,8 @@
      * packet may include this option.
      */
     public static final byte DHCP_RAPID_COMMIT = 80;
-    protected boolean mRapidCommit;
+    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
+    public boolean mRapidCommit;
 
     /**
      * DHCP IPv6-Only Preferred Option(RFC 8925).
diff --git a/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java b/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
index 378c733..afe0990 100644
--- a/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
+++ b/tests/integration/src/android/net/ip/IpClientIntegrationTestCommon.java
@@ -71,6 +71,7 @@
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.contains;
 import static org.mockito.ArgumentMatchers.longThat;
 import static org.mockito.Mockito.any;
@@ -592,6 +593,8 @@
         if (useNetworkStackSignature()) {
             setUpMocks();
             setUpIpClient();
+            // Enable packet retransmit alarm in DhcpClient.
+            enableRealAlarm("DhcpClient." + mIfaceName + ".KICK");
         }
 
         mIIpClient = makeIIpClient(mIfaceName, mCb);
@@ -688,6 +691,17 @@
         }
     }
 
+    private void enableRealAlarm(String cmdName) {
+        doAnswer((inv) -> {
+            final Context context = InstrumentationRegistry.getTargetContext();
+            final AlarmManager alarmManager = context.getSystemService(AlarmManager.class);
+            alarmManager.setExact(inv.getArgument(0), inv.getArgument(1), inv.getArgument(2),
+                    inv.getArgument(3), inv.getArgument(4));
+            return null;
+        }).when(mAlarm).setExact(anyInt(), anyLong(), eq(cmdName), any(OnAlarmListener.class),
+                any(Handler.class));
+    }
+
     private IpClient makeIpClient() throws Exception {
         IpClient ipc = new IpClient(mContext, mIfaceName, mCb, mNetworkObserverRegistry,
                 mNetworkStackServiceManager, mDependencies);
@@ -1388,6 +1402,27 @@
         assertIpMemoryStoreNetworkAttributes(TEST_LEASE_DURATION_S, currentTime, TEST_DEFAULT_MTU);
     }
 
+    @Test
+    public void testRollbackFromRapidCommitOption() throws Exception {
+        startIpClientProvisioning(false /* isDhcpLeaseCacheEnabled */,
+                true /* isDhcpRapidCommitEnabled */, false /* isPreConnectionEnabled */,
+                false /* isDhcpIpConflictDetectEnabled */, false /* isIPv6OnlyPreferredEnabled */);
+
+        final List<DhcpPacket> discoverList = new ArrayList<DhcpPacket>();
+        DhcpPacket packet;
+        do {
+            packet = getNextDhcpPacket();
+            assertTrue(packet instanceof DhcpDiscoverPacket);
+            discoverList.add(packet);
+        } while (discoverList.size() < 4);
+
+        // Check the only first 3 DHCPDISCOVERs take rapid commit option.
+        assertTrue(discoverList.get(0).mRapidCommit);
+        assertTrue(discoverList.get(1).mRapidCommit);
+        assertTrue(discoverList.get(2).mRapidCommit);
+        assertFalse(discoverList.get(3).mRapidCommit);
+    }
+
     @Test @SignatureRequiredTest(reason = "TODO: evaluate whether signature perms are required")
     public void testDhcpClientStartWithCachedInfiniteLease() throws Exception {
         final DhcpPacket packet = getReplyFromDhcpLease(
diff --git a/tests/integration/src/android/net/networkstack/TestNetworkStackServiceClient.kt b/tests/integration/src/android/net/networkstack/TestNetworkStackServiceClient.kt
index bc3e5e0..47936ac 100644
--- a/tests/integration/src/android/net/networkstack/TestNetworkStackServiceClient.kt
+++ b/tests/integration/src/android/net/networkstack/TestNetworkStackServiceClient.kt
@@ -33,7 +33,7 @@
     companion object {
         private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
         private val networkStackVersion by lazy {
-            val component = getNetworkStackComponent()
+            val component = getNetworkStackComponent(INetworkStackConnector::class.java.name)
             val info = context.packageManager.getPackageInfo(component.packageName, 0 /* flags */)
             info.longVersionCode
         }
@@ -54,8 +54,8 @@
             return networkStackVersion == 300000000L || networkStackVersion >= 301100000L
         }
 
-        private fun getNetworkStackComponent(): ComponentName {
-            val connectorIntent = Intent(INetworkStackConnector::class.java.name)
+        private fun getNetworkStackComponent(connectorAction: String): ComponentName {
+            val connectorIntent = Intent(connectorAction)
             return connectorIntent.resolveSystemService(context.packageManager, MATCH_SYSTEM_ONLY)
                     ?: fail("TestNetworkStackService not found")
         }
@@ -71,7 +71,7 @@
 
     private fun init() {
         val bindIntent = Intent(INetworkStackConnector::class.java.name + ".Test")
-        bindIntent.component = getNetworkStackComponent()
+        bindIntent.component = getNetworkStackComponent(bindIntent.action)
         context.bindService(bindIntent, serviceConnection, Context.BIND_AUTO_CREATE)
     }