Send callbacks for Net property changes

LinkProperties and NetworkCapabilities changes were not calling app callbacks.

bug:17681483
Change-Id: I67dac3c4dc1284f5c4bfb24de239da4ec776336f
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 2e24785..9194ca8 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -25,6 +25,7 @@
 import android.net.NetworkUtils;
 import android.os.Binder;
 import android.os.Build.VERSION_CODES;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
@@ -2147,50 +2148,57 @@
             Log.d(TAG, "CM callback handler got msg " + message.what);
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onPreCheck(getNetwork(message));
+                        callbacks.onPreCheck((Network)getObject(message, Network.class));
                     } else {
                         Log.e(TAG, "callback not found for PRECHECK message");
                     }
                     break;
                 }
                 case CALLBACK_AVAILABLE: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onAvailable(getNetwork(message));
+                        callbacks.onAvailable((Network)getObject(message, Network.class));
                     } else {
                         Log.e(TAG, "callback not found for AVAILABLE message");
                     }
                     break;
                 }
                 case CALLBACK_LOSING: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onLosing(getNetwork(message), message.arg1);
+                        callbacks.onLosing((Network)getObject(message, Network.class),
+                                message.arg1);
                     } else {
                         Log.e(TAG, "callback not found for LOSING message");
                     }
                     break;
                 }
                 case CALLBACK_LOST: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
+
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        callbacks.onLost(getNetwork(message));
+                        callbacks.onLost((Network)getObject(message, Network.class));
                     } else {
                         Log.e(TAG, "callback not found for LOST message");
                     }
                     break;
                 }
                 case CALLBACK_UNAVAIL: {
-                    NetworkRequest req = (NetworkRequest)message.obj;
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = null;
                     synchronized(mCallbackMap) {
-                        callbacks = mCallbackMap.get(req);
+                        callbacks = mCallbackMap.get(request);
                     }
                     if (callbacks != null) {
                         callbacks.onUnavailable();
@@ -2200,33 +2208,37 @@
                     break;
                 }
                 case CALLBACK_CAP_CHANGED: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        Network network = getNetwork(message);
-                        NetworkCapabilities cap = mCm.getNetworkCapabilities(network);
+                        Network network = (Network)getObject(message, Network.class);
+                        NetworkCapabilities cap = (NetworkCapabilities)getObject(message,
+                                NetworkCapabilities.class);
 
                         callbacks.onCapabilitiesChanged(network, cap);
                     } else {
-                        Log.e(TAG, "callback not found for CHANGED message");
+                        Log.e(TAG, "callback not found for CAP_CHANGED message");
                     }
                     break;
                 }
                 case CALLBACK_IP_CHANGED: {
-                    NetworkRequest request = getNetworkRequest(message);
+                    NetworkRequest request = (NetworkRequest)getObject(message,
+                            NetworkRequest.class);
                     NetworkCallback callbacks = getCallbacks(request);
                     if (callbacks != null) {
-                        Network network = getNetwork(message);
-                        LinkProperties lp = mCm.getLinkProperties(network);
+                        Network network = (Network)getObject(message, Network.class);
+                        LinkProperties lp = (LinkProperties)getObject(message,
+                                LinkProperties.class);
 
                         callbacks.onLinkPropertiesChanged(network, lp);
                     } else {
-                        Log.e(TAG, "callback not found for CHANGED message");
+                        Log.e(TAG, "callback not found for IP_CHANGED message");
                     }
                     break;
                 }
                 case CALLBACK_RELEASED: {
-                    NetworkRequest req = (NetworkRequest)message.obj;
+                    NetworkRequest req = (NetworkRequest)getObject(message, NetworkRequest.class);
                     NetworkCallback callbacks = null;
                     synchronized(mCallbackMap) {
                         callbacks = mCallbackMap.remove(req);
@@ -2254,23 +2266,14 @@
             }
         }
 
-        private NetworkRequest getNetworkRequest(Message msg) {
-            return (NetworkRequest)(msg.obj);
+        private Object getObject(Message msg, Class c) {
+            return msg.getData().getParcelable(c.getSimpleName());
         }
         private NetworkCallback getCallbacks(NetworkRequest req) {
             synchronized(mCallbackMap) {
                 return mCallbackMap.get(req);
             }
         }
-        private Network getNetwork(Message msg) {
-            return new Network(msg.arg2);
-        }
-        private NetworkCallback removeCallbacks(Message msg) {
-            NetworkRequest req = (NetworkRequest)msg.obj;
-            synchronized(mCallbackMap) {
-                return mCallbackMap.remove(req);
-            }
-        }
     }
 
     private void incCallbackHandlerRefCount() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 85ab249..5978ea6 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -90,6 +90,7 @@
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Build;
+import android.os.Bundle;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -170,6 +171,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Random;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -3533,6 +3535,10 @@
         updateDnses(newLp, oldLp, netId, flushDns);
         updateClat(newLp, oldLp, networkAgent);
         if (isDefaultNetwork(networkAgent)) handleApplyDefaultProxy(newLp.getHttpProxy());
+        // TODO - move this check to cover the whole function
+        if (!Objects.equals(newLp, oldLp)) {
+            notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
+        }
     }
 
     private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo na) {
@@ -3670,10 +3676,13 @@
 
     private void updateCapabilities(NetworkAgentInfo networkAgent,
             NetworkCapabilities networkCapabilities) {
-        // TODO - what else here?  Verify still satisfies everybody?
-        // Check if satisfies somebody new?  call callbacks?
-        synchronized (networkAgent) {
-            networkAgent.networkCapabilities = networkCapabilities;
+        //  TODO - turn this on in MR1 when we have more dogfooding time.
+        // rematchAllNetworksAndRequests();
+        if (!Objects.equals(networkAgent.networkCapabilities, networkCapabilities)) {
+            synchronized (networkAgent) {
+                networkAgent.networkCapabilities = networkCapabilities;
+            }
+            notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
         }
     }
 
@@ -3688,37 +3697,32 @@
     private void callCallbackForRequest(NetworkRequestInfo nri,
             NetworkAgentInfo networkAgent, int notificationType) {
         if (nri.messenger == null) return;  // Default request has no msgr
-        Object o;
-        int a1 = 0;
-        int a2 = 0;
+        Bundle bundle = new Bundle();
+        bundle.putParcelable(NetworkRequest.class.getSimpleName(),
+                new NetworkRequest(nri.request));
+        Message msg = Message.obtain();
+        if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL &&
+                notificationType != ConnectivityManager.CALLBACK_RELEASED) {
+            bundle.putParcelable(Network.class.getSimpleName(), networkAgent.network);
+        }
         switch (notificationType) {
-            case ConnectivityManager.CALLBACK_LOSING:
-                a1 = 30 * 1000; // TODO - read this from NetworkMonitor
-                // fall through
-            case ConnectivityManager.CALLBACK_PRECHECK:
-            case ConnectivityManager.CALLBACK_AVAILABLE:
-            case ConnectivityManager.CALLBACK_LOST:
-            case ConnectivityManager.CALLBACK_CAP_CHANGED:
+            case ConnectivityManager.CALLBACK_LOSING: {
+                msg.arg1 = 30 * 1000; // TODO - read this from NetworkMonitor
+                break;
+            }
+            case ConnectivityManager.CALLBACK_CAP_CHANGED: {
+                bundle.putParcelable(NetworkCapabilities.class.getSimpleName(),
+                        new NetworkCapabilities(networkAgent.networkCapabilities));
+                break;
+            }
             case ConnectivityManager.CALLBACK_IP_CHANGED: {
-                o = new NetworkRequest(nri.request);
-                a2 = networkAgent.network.netId;
+                bundle.putParcelable(LinkProperties.class.getSimpleName(),
+                        new LinkProperties(networkAgent.linkProperties));
                 break;
             }
-            case ConnectivityManager.CALLBACK_UNAVAIL:
-            case ConnectivityManager.CALLBACK_RELEASED: {
-                o = new NetworkRequest(nri.request);
-                break;
-            }
-            default: {
-                loge("Unknown notificationType " + notificationType);
-                return;
-            }
         }
-        Message msg = Message.obtain();
-        msg.arg1 = a1;
-        msg.arg2 = a2;
-        msg.obj = o;
         msg.what = notificationType;
+        msg.setData(bundle);
         try {
             if (VDBG) {
                 log("sending notification " + notifyTypeToName(notificationType) +