Don't tear down even when no requests

Whether tear down a network due to requests should be a decision made by connectivity service. Connectivity service will linger for a while before unwant the network.
The change is to address the issue where there is a setup
request/reponse delay, so the request brought up the network is release before the setup reponse, led to the network marking the data profile as throttled, which blocks future requests to be satisfied.

Fix: 331301784
Test: voice call + data browsing
Test: atest tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java

Change-Id: I184f3042fe0450a74a746fa1d7cd98a0490ce6e7
diff --git a/flags/data.aconfig b/flags/data.aconfig
index fbd8508..c2f27cf 100644
--- a/flags/data.aconfig
+++ b/flags/data.aconfig
@@ -1,5 +1,16 @@
 package: "com.android.internal.telephony.flags"
 
+# OWNER=linggm TARGET=24Q4
+flag {
+  name: "keep_empty_requests_network"
+  namespace: "telephony"
+  description: "Don't tear down network even if no requests attached to it."
+  bug: "331301784"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
 # OWNER=linggm TARGET=24Q3
 flag {
   name: "auto_data_switch_allow_roaming"
diff --git a/src/java/com/android/internal/telephony/data/DataNetwork.java b/src/java/com/android/internal/telephony/data/DataNetwork.java
index bd98403..a748325 100644
--- a/src/java/com/android/internal/telephony/data/DataNetwork.java
+++ b/src/java/com/android/internal/telephony/data/DataNetwork.java
@@ -1427,7 +1427,10 @@
                         setupData();
                     } else {
                         mRetryDelayMillis = DataCallResponse.RETRY_DURATION_UNDEFINED;
-                        mFailCause = DataFailCause.NO_RETRY_FAILURE;
+                        if (!mFlags.keepEmptyRequestsNetwork()) {
+                            // This will mark the data profile as no retry perm failure.
+                            mFailCause = DataFailCause.NO_RETRY_FAILURE;
+                        }
                         transitionTo(mDisconnectedState);
                     }
                     break;
@@ -1553,12 +1556,7 @@
 
                 updateDataNetwork(response);
 
-                // TODO: Evaluate all network requests and see if each request still can be
-                //  satisfied.
-                //  For requests that can't be satisfied anymore, we need to put them back to the
-                //  unsatisfied pool. If none of network requests can be satisfied, then there is no
-                //  need to mark network agent connected. Just silently deactivate the data network.
-                if (mAttachedNetworkRequestList.isEmpty()) {
+                if (!mFlags.keepEmptyRequestsNetwork() && mAttachedNetworkRequestList.isEmpty()) {
                     log("Tear down the network since there is no live network request.");
                     // Directly call onTearDown here. Calling tearDown will cause deadlock because
                     // EVENT_TEAR_DOWN_NETWORK is deferred until state machine enters connected
diff --git a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
index 19502f5..a911231 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/data/DataNetworkTest.java
@@ -1233,6 +1233,29 @@
     }
 
     @Test
+    public void testNetworkRequestDetachedBeforeConnected() throws Exception {
+        doReturn(true).when(mFeatureFlags).keepEmptyRequestsNetwork();
+        NetworkRequestList networkRequestList = new NetworkRequestList(new TelephonyNetworkRequest(
+                new NetworkRequest.Builder()
+                        .addCapability(NetworkCapabilities.NET_CAPABILITY_IMS)
+                        .build(), mPhone, mFeatureFlags));
+        mDataNetworkUT = new DataNetwork(mPhone, mFeatureFlags, Looper.myLooper(),
+                mDataServiceManagers, mImsDataProfile, networkRequestList,
+                AccessNetworkConstants.TRANSPORT_TYPE_WWAN, DataAllowedReason.NORMAL,
+                mDataNetworkCallback);
+        replaceInstance(DataNetwork.class, "mDataCallSessionStats",
+                mDataNetworkUT, mDataCallSessionStats);
+
+        // Remove the request before the network connect.
+        mDataNetworkUT.detachNetworkRequest(networkRequestList.getFirst(), false/*should retry*/);
+        setSuccessfulSetupDataResponse(mMockedWwanDataServiceManager, 123);
+        processAllMessages();
+
+        // Verify the request proceed to connected state even without requests.
+        assertThat(mDataNetworkUT.isConnected()).isTrue();
+    }
+
+    @Test
     public void testAdminAndOwnerUids() throws Exception {
         doReturn(ADMIN_UID2).when(mCarrierPrivilegesTracker).getCarrierServicePackageUid();
         setupDataNetwork();