Include elapsed realtime (nanos) of the event in the radio state change notifications.

Bug: 13247811
Change-Id: I3454aa159a68b9087b4762df947b41965b5a3941
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 5b2a29e..3da00b1 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -175,6 +175,11 @@
      * {@hide}
      */
     public static final String EXTRA_IS_ACTIVE = "isActive";
+    /**
+     * The lookup key for a long that contains the timestamp (nanos) of the radio state change.
+     * {@hide}
+     */
+    public static final String EXTRA_REALTIME_NS = "tsNanos";
 
     /**
      * Broadcast Action: The setting for background data usage has changed
diff --git a/core/java/android/net/INetworkManagementEventObserver.aidl b/core/java/android/net/INetworkManagementEventObserver.aidl
index 5b16f8b..dd9c39f 100644
--- a/core/java/android/net/INetworkManagementEventObserver.aidl
+++ b/core/java/android/net/INetworkManagementEventObserver.aidl
@@ -86,8 +86,9 @@
      *
      * @param iface The interface.
      * @param active  True if the interface is actively transmitting data, false if it is idle.
+     * @param tsNanos Elapsed realtime in nanos when the state of the network interface changed.
      */
-    void interfaceClassDataActivityChanged(String label, boolean active);
+    void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos);
 
     /**
      * Information about available DNS servers has been received.
diff --git a/core/java/com/android/server/net/BaseNetworkObserver.java b/core/java/com/android/server/net/BaseNetworkObserver.java
index 5502a17..430dd63 100644
--- a/core/java/com/android/server/net/BaseNetworkObserver.java
+++ b/core/java/com/android/server/net/BaseNetworkObserver.java
@@ -57,7 +57,7 @@
     }
 
     @Override
-    public void interfaceClassDataActivityChanged(String label, boolean active) {
+    public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
         // default no-op
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index ffc748f..68b779c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1183,9 +1183,9 @@
 
     private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() {
         @Override
-        public void interfaceClassDataActivityChanged(String label, boolean active) {
+        public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) {
             int deviceType = Integer.parseInt(label);
-            sendDataActivityBroadcast(deviceType, active);
+            sendDataActivityBroadcast(deviceType, active, tsNanos);
         }
     };
 
@@ -2169,10 +2169,11 @@
         sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs);
     }
 
-    private void sendDataActivityBroadcast(int deviceType, boolean active) {
+    private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) {
         Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE);
         intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType);
         intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active);
+        intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos);
         final long ident = Binder.clearCallingIdentity();
         try {
             mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL,
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index bfc966b..a09d605 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -346,7 +346,7 @@
     /**
      * Notify our observers of a change in the data activity state of the interface
      */
-    private void notifyInterfaceClassActivity(int type, boolean active) {
+    private void notifyInterfaceClassActivity(int type, boolean active, long tsNanos) {
         try {
             getBatteryStats().noteDataConnectionActive(type, active);
         } catch (RemoteException e) {
@@ -356,7 +356,7 @@
         for (int i = 0; i < length; i++) {
             try {
                 mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
-                        Integer.toString(type), active);
+                        Integer.toString(type), active, tsNanos);
             } catch (RemoteException e) {
             } catch (RuntimeException e) {
             }
@@ -571,8 +571,15 @@
                     if (cooked.length < 4 || !cooked[1].equals("IfaceClass")) {
                         throw new IllegalStateException(errorMessage);
                     }
+                    long timestampNanos = 0;
+                    if (cooked.length == 5) {
+                        try {
+                            timestampNanos = Long.parseLong(cooked[4]);
+                        } catch(NumberFormatException ne) {}
+                    }
                     boolean isActive = cooked[2].equals("active");
-                    notifyInterfaceClassActivity(Integer.parseInt(cooked[3]), isActive);
+                    notifyInterfaceClassActivity(Integer.parseInt(cooked[3]),
+                            isActive, timestampNanos);
                     return true;
                     // break;
             case NetdResponseCode.InterfaceAddressChange:
@@ -1261,7 +1268,7 @@
             }
             mMainHandler.post(new Runnable() {
                 @Override public void run() {
-                    notifyInterfaceClassActivity(type, true);
+                    notifyInterfaceClassActivity(type, true, SystemClock.elapsedRealtimeNanos());
                 }
             });
         }
@@ -1288,7 +1295,8 @@
             mActiveIdleTimers.remove(iface);
             mMainHandler.post(new Runnable() {
                 @Override public void run() {
-                    notifyInterfaceClassActivity(params.type, false);
+                    notifyInterfaceClassActivity(params.type, false,
+                            SystemClock.elapsedRealtimeNanos());
                 }
             });
         }