Don't send the same PendingIntent more than once.

Fixing a bug where a NetworkRequest's PendingIntent can be sent more
than once when networks are rematched before the intent completes.

Added a small delay before removing the request to give the receiving
client an opportunity to put in its own request. The delay value is
configurable via Settings.Secure.

Bug: 18614074
Change-Id: Iac7c5e5a04f42f2b6794e9e22349cc631bebeab7
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3bc74ae..555f64c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4349,6 +4349,16 @@
                 Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS;
 
         /**
+         * The number of milliseconds to hold on to a PendingIntent based request. This delay gives
+         * the receivers of the PendingIntent an opportunity to make a new network request before
+         * the Network satisfying the request is potentially removed.
+         *
+         * @hide
+         */
+        public static final String CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS =
+                "connectivity_release_pending_intent_delay_ms";
+
+        /**
          * Whether background data usage is allowed.
          *
          * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH},
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 84fddd7..555a121 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -215,6 +215,10 @@
 
     private static final int SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE = 0;
 
+    // How long to delay to removal of a pending intent based request.
+    // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
+    private final int mReleasePendingIntentDelayMs;
+
     private PendingIntent mSampleIntervalElapsedIntent;
 
     // Set network sampling interval at 12 minutes, this way, even if the timers get
@@ -645,6 +649,9 @@
             loge("Error setting defaultDns using " + dns);
         }
 
+        mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
+                Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
+
         mContext = checkNotNull(context, "missing Context");
         mNetd = checkNotNull(netManager, "missing INetworkManagementService");
         mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager");
@@ -3376,6 +3383,7 @@
 
         final NetworkRequest request;
         final PendingIntent mPendingIntent;
+        boolean mPendingIntentSent;
         private final IBinder mBinder;
         final int mPid;
         final int mUid;
@@ -3497,6 +3505,12 @@
         return networkRequest;
     }
 
+    private void releasePendingNetworkRequestWithDelay(PendingIntent operation) {
+        mHandler.sendMessageDelayed(
+                mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
+                getCallingUid(), 0, operation), mReleasePendingIntentDelayMs);
+    }
+
     @Override
     public void releasePendingNetworkRequest(PendingIntent operation) {
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST_WITH_INTENT,
@@ -3810,10 +3824,11 @@
 
     private void sendPendingIntentForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent,
             int notificationType) {
-        if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE) {
+        if (notificationType == ConnectivityManager.CALLBACK_AVAILABLE && !nri.mPendingIntentSent) {
             Intent intent = new Intent();
             intent.putExtra(ConnectivityManager.EXTRA_NETWORK, networkAgent.network);
             intent.putExtra(ConnectivityManager.EXTRA_NETWORK_REQUEST, nri.request);
+            nri.mPendingIntentSent = true;
             sendIntent(nri.mPendingIntent, intent);
         }
         // else not handled
@@ -3837,7 +3852,9 @@
             String resultData, Bundle resultExtras) {
         if (DBG) log("Finished sending " + pendingIntent);
         mPendingIntentWakeLock.release();
-        releasePendingNetworkRequest(pendingIntent);
+        // Release with a delay so the receiving client has an opportunity to put in its
+        // own request.
+        releasePendingNetworkRequestWithDelay(pendingIntent);
     }
 
     private void callCallbackForRequest(NetworkRequestInfo nri,