Merge "Implement ConnectivityManager.reportBadNetwork() to trigger network validation." into lmp-dev
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 4bfef41..70b402d 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -685,6 +685,23 @@
     }
 
     /**
+     * Returns the {@link Network} object currently serving a given type, or
+     * null if the given type is not connected.
+     *
+     * <p>This method requires the caller to hold the permission
+     * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+     *
+     * @hide
+     */
+    public Network getNetworkForType(int networkType) {
+        try {
+            return mService.getNetworkForType(networkType);
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
      * Returns an array of all {@link Network} currently tracked by the
      * framework.
      *
@@ -1281,7 +1298,7 @@
     }
 
     /**
-     * Callback for use with {@link ConnectivityManager#registerDefaultNetworkActiveListener}
+     * Callback for use with {@link ConnectivityManager#addDefaultNetworkActiveListener}
      * to find out when the system default network has gone in to a high power state.
      */
     public interface OnNetworkActiveListener {
@@ -1323,7 +1340,7 @@
      *
      * @param l The listener to be told when the network is active.
      */
-    public void registerDefaultNetworkActiveListener(final OnNetworkActiveListener l) {
+    public void addDefaultNetworkActiveListener(final OnNetworkActiveListener l) {
         INetworkActivityListener rl = new INetworkActivityListener.Stub() {
             @Override
             public void onNetworkActive() throws RemoteException {
@@ -1340,11 +1357,11 @@
 
     /**
      * Remove network active listener previously registered with
-     * {@link #registerDefaultNetworkActiveListener}.
+     * {@link #addDefaultNetworkActiveListener}.
      *
      * @param l Previously registered listener.
      */
-    public void unregisterDefaultNetworkActiveListener(OnNetworkActiveListener l) {
+    public void removeDefaultNetworkActiveListener(OnNetworkActiveListener l) {
         INetworkActivityListener rl = mNetworkActivityListeners.get(l);
         if (rl == null) {
             throw new IllegalArgumentException("Listener not registered: " + l);
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index b2fc3be..974c4cd 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -48,6 +48,7 @@
     NetworkInfo getNetworkInfo(int networkType);
     NetworkInfo getNetworkInfoForNetwork(in Network network);
     NetworkInfo[] getAllNetworkInfo();
+    Network getNetworkForType(int networkType);
     Network[] getAllNetworks();
 
     NetworkInfo getProvisioningOrActiveNetworkInfo();
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index f9a25f9..c387055 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -274,7 +274,6 @@
 
     /**
      * Implement the Parcelable interface.
-     * @hide
      */
     public int describeContents() {
         return 0;
@@ -282,7 +281,6 @@
 
     /**
      * Implement the Parcelable interface.
-     * @hide
      */
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeByteArray(address.getAddress());
@@ -293,7 +291,6 @@
 
     /**
      * Implement the Parcelable interface.
-     * @hide
      */
     public static final Creator<LinkAddress> CREATOR =
         new Creator<LinkAddress>() {
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index d2a4728..e686be7 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -35,6 +35,7 @@
 import java.util.concurrent.atomic.AtomicReference;
 import javax.net.SocketFactory;
 
+import com.android.okhttp.ConnectionPool;
 import com.android.okhttp.HostResolver;
 import com.android.okhttp.OkHttpClient;
 
@@ -60,6 +61,17 @@
     private volatile OkHttpClient mOkHttpClient = null;
     private Object mLock = new Object();
 
+    // Default connection pool values. These are evaluated at startup, just
+    // like the OkHttp code. Also like the OkHttp code, we will throw parse
+    // exceptions at class loading time if the properties are set but are not
+    // valid integers.
+    private static final boolean httpKeepAlive =
+            Boolean.parseBoolean(System.getProperty("http.keepAlive", "true"));
+    private static final int httpMaxConnections =
+            httpKeepAlive ? Integer.parseInt(System.getProperty("http.maxConnections", "5")) : 0;
+    private static final long httpKeepAliveDurationMs =
+            Long.parseLong(System.getProperty("http.keepAliveDuration", "300000"));  // 5 minutes.
+
     /**
      * @hide
      */
@@ -183,6 +195,20 @@
         return mNetworkBoundSocketFactory;
     }
 
+    // TODO: This creates an OkHttpClient with its own connection pool for
+    // every Network object, instead of one for every NetId. This is
+    // suboptimal, because an app could potentially have more than one
+    // Network object for the same NetId, causing increased memory footprint
+    // and performance penalties due to lack of connection reuse (connection
+    // setup time, congestion window growth time, etc.).
+    //
+    // Instead, investigate only having one OkHttpClient for every NetId,
+    // perhaps by using a static HashMap of NetIds to OkHttpClient objects. The
+    // tricky part is deciding when to remove an OkHttpClient; a WeakHashMap
+    // shouldn't be used because whether a Network is referenced doesn't
+    // correlate with whether a new Network will be instantiated in the near
+    // future with the same NetID. A good solution would involve purging empty
+    // (or when all connections are timed out) ConnectionPools.
     private void maybeInitHttpClient() {
         if (mOkHttpClient == null) {
             synchronized (mLock) {
@@ -193,9 +219,12 @@
                             return Network.this.getAllByName(host);
                         }
                     };
+                    ConnectionPool pool = new ConnectionPool(httpMaxConnections,
+                                                             httpKeepAliveDurationMs);
                     mOkHttpClient = new OkHttpClient()
                             .setSocketFactory(getSocketFactory())
-                            .setHostResolver(hostResolver);
+                            .setHostResolver(hostResolver)
+                            .setConnectionPool(pool);
                 }
             }
         }
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 22da90e..8df9916 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -45,7 +45,7 @@
     private volatile AsyncChannel mAsyncChannel;
     private final String LOG_TAG;
     private static final boolean DBG = true;
-    private static final boolean VDBG = true;
+    private static final boolean VDBG = false;
     private final Context mContext;
     private final ArrayList<Message>mPreConnectedQueue = new ArrayList<Message>();
 
@@ -134,7 +134,7 @@
             throw new IllegalArgumentException();
         }
 
-        if (DBG) log("Registering NetworkAgent");
+        if (VDBG) log("Registering NetworkAgent");
         ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService(
                 Context.CONNECTIVITY_SERVICE);
         cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni),
@@ -148,7 +148,7 @@
                 if (mAsyncChannel != null) {
                     log("Received new connection while already connected!");
                 } else {
-                    if (DBG) log("NetworkAgent fully connected");
+                    if (VDBG) log("NetworkAgent fully connected");
                     AsyncChannel ac = new AsyncChannel();
                     ac.connected(null, this, msg.replyTo);
                     ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
@@ -164,7 +164,7 @@
                 break;
             }
             case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
-                if (DBG) log("CMD_CHANNEL_DISCONNECT");
+                if (VDBG) log("CMD_CHANNEL_DISCONNECT");
                 if (mAsyncChannel != null) mAsyncChannel.disconnect();
                 break;
             }
diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java
index d279412..7664c95 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -128,14 +128,6 @@
     private boolean mIsAvailable;
 
     /**
-     * @param type network type
-     * @deprecated
-     * @hide because this constructor was only meant for internal use (and
-     * has now been superseded by the package-private constructor below).
-     */
-    public NetworkInfo(int type) {}
-
-    /**
      * @hide
      */
     public NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 83bdfaa..5a09b46 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -52,6 +52,9 @@
      * @hide
      */
     public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId) {
+        if (nc == null) {
+            throw new NullPointerException();
+        }
         requestId = rId;
         networkCapabilities = nc;
         this.legacyType = legacyType;
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index 7ea6bae..1534e2c 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -334,10 +334,6 @@
         dest.writeStringArray(mParsedExclusionList);
     }
 
-    /**
-     * Implement the Parcelable interface.
-     * @hide
-     */
     public static final Creator<ProxyInfo> CREATOR =
         new Creator<ProxyInfo>() {
             public ProxyInfo createFromParcel(Parcel in) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 109c2ee..c5931dd 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -185,7 +185,7 @@
     private static final String TAG = "ConnectivityService";
 
     private static final boolean DBG = true;
-    private static final boolean VDBG = true; // STOPSHIP
+    private static final boolean VDBG = false;
 
     // network sampling debugging
     private static final boolean SAMPLE_DBG = false;
@@ -425,8 +425,8 @@
 
     TelephonyManager mTelephonyManager;
 
-    // sequence number for Networks
-    private final static int MIN_NET_ID = 10; // some reserved marks
+    // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp
+    private final static int MIN_NET_ID = 100; // some reserved marks
     private final static int MAX_NET_ID = 65535;
     private int mNextNetId = MIN_NET_ID;
 
@@ -863,11 +863,11 @@
             // network is blocked; clone and override state
             info = new NetworkInfo(info);
             info.setDetailedState(DetailedState.BLOCKED, null, null);
-            if (VDBG) log("returning Blocked NetworkInfo");
+            if (DBG) log("returning Blocked NetworkInfo");
         }
         if (mLockdownTracker != null) {
             info = mLockdownTracker.augmentNetworkInfo(info);
-            if (VDBG) log("returning Locked NetworkInfo");
+            if (DBG) log("returning Locked NetworkInfo");
         }
         return info;
     }
@@ -1000,6 +1000,17 @@
     }
 
     @Override
+    public Network getNetworkForType(int networkType) {
+        enforceAccessPermission();
+        final int uid = Binder.getCallingUid();
+        if (isNetworkBlocked(networkType, uid)) {
+            return null;
+        }
+        NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
+        return (nai == null) ? null : nai.network;
+    }
+
+    @Override
     public Network[] getAllNetworks() {
         enforceAccessPermission();
         final ArrayList<Network> result = new ArrayList();
@@ -1235,7 +1246,7 @@
                 bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface);
             }
         }
-        if (VDBG) log("Adding " + bestRoute + " for interface " + bestRoute.getInterface());
+        if (DBG) log("Adding " + bestRoute + " for interface " + bestRoute.getInterface());
         try {
             mNetd.addLegacyRouteForNetId(netId, bestRoute, uid);
         } catch (Exception e) {
@@ -1440,7 +1451,7 @@
                 mInitialBroadcast = new Intent(intent);
             }
             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
-            if (VDBG) {
+            if (DBG) {
                 log("sendStickyBroadcast: action=" + intent.getAction());
             }
 
@@ -1597,7 +1608,7 @@
         }
 
         try {
-            if (VDBG) log("Setting MTU size: " + iface + ", " + mtu);
+            if (DBG) log("Setting MTU size: " + iface + ", " + mtu);
             mNetd.setMtu(iface, mtu);
         } catch (Exception e) {
             Slog.e(TAG, "exception in setMtu()" + e);
@@ -1618,7 +1629,7 @@
         }
 
         if (values == null || values.length != 6) {
-            if (VDBG) log("Invalid tcpBufferSizes string: " + tcpBufferSizes +", using defaults");
+            if (DBG) log("Invalid tcpBufferSizes string: " + tcpBufferSizes +", using defaults");
             tcpBufferSizes = DEFAULT_TCP_BUFFER_SIZES;
             values = tcpBufferSizes.split(",");
         }
@@ -1626,7 +1637,7 @@
         if (tcpBufferSizes.equals(mCurrentTcpBufferSizes)) return;
 
         try {
-            if (VDBG) Slog.d(TAG, "Setting tx/rx TCP buffers to " + tcpBufferSizes);
+            if (DBG) Slog.d(TAG, "Setting tx/rx TCP buffers to " + tcpBufferSizes);
 
             final String prefix = "/sys/kernel/ipv4/tcp_";
             FileUtils.stringToFile(prefix + "rmem_min", values[0]);
@@ -1763,7 +1774,7 @@
         pw.println();
 
         synchronized (this) {
-            pw.println("NetworkTranstionWakeLock is currently " +
+            pw.println("NetworkTransitionWakeLock is currently " +
                     (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held.");
             pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy);
         }
@@ -1789,7 +1800,7 @@
         }
         if (officialNai != null && officialNai.equals(nai)) return true;
         if (officialNai != null || VDBG) {
-            loge(msg + " - validateNetworkAgent found mismatched netId: " + officialNai +
+            loge(msg + " - isLiveNetworkAgent found mismatched netId: " + officialNai +
                 " - " + nai);
         }
         return false;
@@ -1833,7 +1844,7 @@
                         loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED");
                     } else {
                         if (VDBG) {
-                            log("Update of Linkproperties for " + nai.name() +
+                            log("Update of LinkProperties for " + nai.name() +
                                     "; created=" + nai.created);
                         }
                         LinkProperties oldLp = nai.linkProperties;
@@ -1937,17 +1948,17 @@
                     break;
                 }
                 case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: {
-                    NetworkAgentInfo nai = null;
-                    synchronized (mNetworkForNetId) {
-                        nai = mNetworkForNetId.get(msg.arg2);
-                    }
-                    if (nai == null) {
-                        loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
-                        break;
-                    }
                     if (msg.arg1 == 0) {
                         setProvNotificationVisibleIntent(false, msg.arg2, 0, null, null);
                     } else {
+                        NetworkAgentInfo nai = null;
+                        synchronized (mNetworkForNetId) {
+                            nai = mNetworkForNetId.get(msg.arg2);
+                        }
+                        if (nai == null) {
+                            loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
+                            break;
+                        }
                         setProvNotificationVisibleIntent(true, msg.arg2, nai.networkInfo.getType(),
                                 nai.networkInfo.getExtraInfo(), (PendingIntent)msg.obj);
                     }
@@ -2112,11 +2123,10 @@
             for (int i = 0; i < nai.networkRequests.size(); i++) {
                 NetworkRequest request = nai.networkRequests.valueAt(i);
                 NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
-                if (VDBG) {
-                    log(" checking request " + request + ", currentNetwork = " +
-                            (currentNetwork != null ? currentNetwork.name() : "null"));
-                }
                 if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
+                    if (DBG) {
+                        log("Checking for replacement network to handle request " + request );
+                    }
                     mNetworkForRequestId.remove(request.requestId);
                     sendUpdatedScoreToFactories(request, 0);
                     NetworkAgentInfo alternative = null;
@@ -2130,8 +2140,11 @@
                             alternative = existing;
                         }
                     }
-                    if (alternative != null && !toActivate.contains(alternative)) {
-                        toActivate.add(alternative);
+                    if (alternative != null) {
+                        if (DBG) log(" found replacement in " + alternative.name());
+                        if (!toActivate.contains(alternative)) {
+                            toActivate.add(alternative);
+                        }
                     }
                 }
             }
@@ -2154,9 +2167,9 @@
         // Check for the best currently alive network that satisfies this request
         NetworkAgentInfo bestNetwork = null;
         for (NetworkAgentInfo network : mNetworkAgentInfos.values()) {
-            if (VDBG) log("handleRegisterNetworkRequest checking " + network.name());
+            if (DBG) log("handleRegisterNetworkRequest checking " + network.name());
             if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) {
-                if (VDBG) log("apparently satisfied.  currentScore=" + network.currentScore);
+                if (DBG) log("apparently satisfied.  currentScore=" + network.currentScore);
                 if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) {
                     if (!nri.isRequest) {
                         // Not setting bestNetwork here as a listening NetworkRequest may be
@@ -2171,7 +2184,7 @@
             }
         }
         if (bestNetwork != null) {
-            if (VDBG) log("using " + bestNetwork.name());
+            if (DBG) log("using " + bestNetwork.name());
             if (bestNetwork.networkInfo.isConnected()) {
                 // Cancel any lingering so the linger timeout doesn't teardown this network
                 // even though we have a request for it.
@@ -2206,41 +2219,53 @@
             if (DBG) log("releasing NetworkRequest " + request);
             nri.unlinkDeathRecipient();
             mNetworkRequests.remove(request);
-            // tell the network currently servicing this that it's no longer interested
-            NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId);
-            if (affectedNetwork != null) {
-                mNetworkForRequestId.remove(nri.request.requestId);
-                affectedNetwork.networkRequests.remove(nri.request.requestId);
-                if (VDBG) {
-                    log(" Removing from current network " + affectedNetwork.name() + ", leaving " +
-                            affectedNetwork.networkRequests.size() + " requests.");
-                }
-                if (nri.isRequest && nri.request.legacyType != TYPE_NONE) {
-                    mLegacyTypeTracker.remove(nri.request.legacyType, affectedNetwork);
-                }
-            }
-
             if (nri.isRequest) {
+                // Find all networks that are satisfying this request and remove the request
+                // from their request lists.
+                for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+                    if (nai.networkRequests.get(nri.request.requestId) != null) {
+                        nai.networkRequests.remove(nri.request.requestId);
+                        if (DBG) {
+                            log(" Removing from current network " + nai.name() +
+                                    ", leaving " + nai.networkRequests.size() +
+                                    " requests.");
+                        }
+                        // check if has any requests remaining and if not,
+                        // disconnect (unless it's a VPN).
+                        boolean keep = nai.isVPN();
+                        for (int i = 0; i < nai.networkRequests.size() && !keep; i++) {
+                            NetworkRequest r = nai.networkRequests.valueAt(i);
+                            if (mNetworkRequests.get(r).isRequest) keep = true;
+                        }
+                        if (!keep) {
+                            if (DBG) log("no live requests for " + nai.name() + "; disconnecting");
+                            nai.asyncChannel.disconnect();
+                        }
+                    }
+                }
+
+                // Maintain the illusion.  When this request arrived, we might have preteneded
+                // that a network connected to serve it, even though the network was already
+                // connected.  Now that this request has gone away, we might have to pretend
+                // that the network disconnected.  LegacyTypeTracker will generate that
+                // phatom disconnect for this type.
+                NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+                if (nai != null) {
+                    mNetworkForRequestId.remove(nri.request.requestId);
+                    if (nri.request.legacyType != TYPE_NONE) {
+                        mLegacyTypeTracker.remove(nri.request.legacyType, nai);
+                    }
+                }
+
                 for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) {
                     nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST,
                             nri.request);
                 }
-
-                if (affectedNetwork != null) {
-                    // check if this network still has live requests - otherwise, tear down
-                    // TODO - probably push this to the NF/NA
-                    boolean keep = affectedNetwork.isVPN();
-                    for (int i = 0; i < affectedNetwork.networkRequests.size() && !keep; i++) {
-                        NetworkRequest r = affectedNetwork.networkRequests.valueAt(i);
-                        if (mNetworkRequests.get(r).isRequest) {
-                            keep = true;
-                        }
-                    }
-                    if (keep == false) {
-                        if (DBG) log("no live requests for " + affectedNetwork.name() +
-                                "; disconnecting");
-                        affectedNetwork.asyncChannel.disconnect();
-                    }
+            } else {
+                // listens don't have a singular affectedNetwork.  Check all networks to see
+                // if this listen request applies and remove it.
+                for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) {
+                    nai.networkRequests.remove(nri.request.requestId);
                 }
             }
             callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED);
@@ -3599,7 +3624,7 @@
             // Check for  apps that can handle provisioning first
             Intent provisioningIntent = new Intent(TelephonyIntents.ACTION_CARRIER_SETUP);
             List<String> carrierPackages =
-                    mTelephonyManager.getCarrierPackageNamesForBroadcastIntent(provisioningIntent);
+                    mTelephonyManager.getCarrierPackageNamesForIntent(provisioningIntent);
             if (carrierPackages != null && !carrierPackages.isEmpty()) {
                 if (carrierPackages.size() != 1) {
                     if (DBG) log("Multiple matching carrier apps found, launching the first.");
@@ -3962,7 +3987,7 @@
 
     private void handleNetworkSamplingTimeout() {
 
-        log("Sampling interval elapsed, updating statistics ..");
+        if (SAMPLE_DBG) log("Sampling interval elapsed, updating statistics ..");
 
         // initialize list of interfaces ..
         Map<String, SamplingDataTracker.SamplingSnapshot> mapIfaceToSample =
@@ -3993,13 +4018,15 @@
             }
         }
 
-        log("Done.");
+        if (SAMPLE_DBG) log("Done.");
 
         int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS,
                 DEFAULT_SAMPLING_INTERVAL_IN_SECONDS);
 
-        if (DBG) log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds");
+        if (SAMPLE_DBG) {
+            log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds");
+        }
 
         setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent);
     }
@@ -4167,7 +4194,7 @@
     }
 
     private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) {
-        if (VDBG) log("Got NetworkFactory Messenger for " + nfi.name);
+        if (DBG) log("Got NetworkFactory Messenger for " + nfi.name);
         mNetworkFactoryInfos.put(nfi.messenger, nfi);
         nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger);
     }
@@ -4181,10 +4208,10 @@
     private void handleUnregisterNetworkFactory(Messenger messenger) {
         NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger);
         if (nfi == null) {
-            if (VDBG) log("Failed to find Messenger in unregisterNetworkFactory");
+            loge("Failed to find Messenger in unregisterNetworkFactory");
             return;
         }
-        if (VDBG) log("unregisterNetworkFactory for " + nfi.name);
+        if (DBG) log("unregisterNetworkFactory for " + nfi.name);
     }
 
     /**
@@ -4222,7 +4249,7 @@
         synchronized (this) {
             nai.networkMonitor.systemReady = mSystemReady;
         }
-        if (VDBG) log("registerNetworkAgent " + nai);
+        if (DBG) log("registerNetworkAgent " + nai);
         mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai));
     }
 
@@ -4283,6 +4310,7 @@
         }
         for (String iface : interfaceDiff.added) {
             try {
+                if (DBG) log("Adding iface " + iface + " to network " + netId);
                 mNetd.addInterfaceToNetwork(iface, netId);
             } catch (Exception e) {
                 loge("Exception adding interface: " + e);
@@ -4290,6 +4318,7 @@
         }
         for (String iface : interfaceDiff.removed) {
             try {
+                if (DBG) log("Removing iface " + iface + " from network " + netId);
                 mNetd.removeInterfaceFromNetwork(iface, netId);
             } catch (Exception e) {
                 loge("Exception removing interface: " + e);
@@ -4314,22 +4343,29 @@
         // do this twice, adding non-nexthop routes first, then routes they are dependent on
         for (RouteInfo route : routeDiff.added) {
             if (route.hasGateway()) continue;
+            if (DBG) log("Adding Route [" + route + "] to network " + netId);
             try {
                 mNetd.addRoute(netId, route);
             } catch (Exception e) {
-                loge("Exception in addRoute for non-gateway: " + e);
+                if ((route.getDestination().getAddress() instanceof Inet4Address) || VDBG) {
+                    loge("Exception in addRoute for non-gateway: " + e);
+                }
             }
         }
         for (RouteInfo route : routeDiff.added) {
             if (route.hasGateway() == false) continue;
+            if (DBG) log("Adding Route [" + route + "] to network " + netId);
             try {
                 mNetd.addRoute(netId, route);
             } catch (Exception e) {
-                loge("Exception in addRoute for gateway: " + e);
+                if ((route.getGateway() instanceof Inet4Address) || VDBG) {
+                    loge("Exception in addRoute for gateway: " + e);
+                }
             }
         }
 
         for (RouteInfo route : routeDiff.removed) {
+            if (DBG) log("Removing Route [" + route + "] from network " + netId);
             try {
                 mNetd.removeRoute(netId, route);
             } catch (Exception e) {
@@ -4348,6 +4384,7 @@
                     loge("no dns provided for netId " + netId + ", so using defaults");
                 }
             }
+            if (DBG) log("Setting Dns servers for network " + netId + " to " + dnses);
             try {
                 mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses),
                     newLp.getDomains());
@@ -4437,7 +4474,10 @@
         msg.obj = o;
         msg.what = notificationType;
         try {
-            if (VDBG) log("sending notification " + notificationType + " for " + nri.request);
+            if (VDBG) {
+                log("sending notification " + notifyTypeToName(notificationType) +
+                        " for " + nri.request);
+            }
             nri.messenger.send(msg);
         } catch (RemoteException e) {
             // may occur naturally in the race of binder death.
@@ -4460,7 +4500,7 @@
     }
 
     private void makeDefault(NetworkAgentInfo newNetwork) {
-        if (VDBG) log("Switching to new default network: " + newNetwork);
+        if (DBG) log("Switching to new default network: " + newNetwork);
         mActiveDefaultNetwork = newNetwork.networkInfo.getType();
         setupDataActivityTracking(newNetwork);
         try {
@@ -4488,7 +4528,7 @@
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
             NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
             if (newNetwork == currentNetwork) {
-                if (VDBG) log("Network " + newNetwork.name() + " was already satisfying" +
+                if (DBG) log("Network " + newNetwork.name() + " was already satisfying" +
                               " request " + nri.request.requestId + ". No change.");
                 keep = true;
                 continue;
@@ -4512,12 +4552,12 @@
                 if (currentNetwork == null ||
                         currentNetwork.currentScore < newNetwork.currentScore) {
                     if (currentNetwork != null) {
-                        if (VDBG) log("   accepting network in place of " + currentNetwork.name());
+                        if (DBG) log("   accepting network in place of " + currentNetwork.name());
                         currentNetwork.networkRequests.remove(nri.request.requestId);
                         currentNetwork.networkLingered.add(nri.request);
                         affectedNetworks.add(currentNetwork);
                     } else {
-                        if (VDBG) log("   accepting network in place of null");
+                        if (DBG) log("   accepting network in place of null");
                     }
                     mNetworkForRequestId.put(nri.request.requestId, newNetwork);
                     newNetwork.addRequest(nri.request);
@@ -4618,7 +4658,7 @@
                     loge("  " + newNetwork.networkRequests.valueAt(i));
                 }
             }
-            if (VDBG) log("Validated network turns out to be unwanted.  Tear it down.");
+            if (DBG) log("Validated network turns out to be unwanted.  Tear it down.");
             newNetwork.asyncChannel.disconnect();
         }
     }
@@ -4789,7 +4829,7 @@
     }
 
     protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) {
-        if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name());
+        if (DBG) log("notifyType " + notifyTypeToName(notifyType) + " for " + networkAgent.name());
         for (int i = 0; i < networkAgent.networkRequests.size(); i++) {
             NetworkRequest nr = networkAgent.networkRequests.valueAt(i);
             NetworkRequestInfo nri = mNetworkRequests.get(nr);
@@ -4798,6 +4838,20 @@
         }
     }
 
+    private String notifyTypeToName(int notifyType) {
+        switch (notifyType) {
+            case ConnectivityManager.CALLBACK_PRECHECK:    return "PRECHECK";
+            case ConnectivityManager.CALLBACK_AVAILABLE:   return "AVAILABLE";
+            case ConnectivityManager.CALLBACK_LOSING:      return "LOSING";
+            case ConnectivityManager.CALLBACK_LOST:        return "LOST";
+            case ConnectivityManager.CALLBACK_UNAVAIL:     return "UNAVAILABLE";
+            case ConnectivityManager.CALLBACK_CAP_CHANGED: return "CAP_CHANGED";
+            case ConnectivityManager.CALLBACK_IP_CHANGED:  return "IP_CHANGED";
+            case ConnectivityManager.CALLBACK_RELEASED:    return "RELEASED";
+        }
+        return "UNKNOWN";
+    }
+
     private LinkProperties getLinkPropertiesForTypeInternal(int networkType) {
         NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
         if (nai != null) {
@@ -4818,7 +4872,8 @@
             result.setType(networkType);
             return result;
         } else {
-            NetworkInfo result = new NetworkInfo(networkType);
+            NetworkInfo result = new NetworkInfo(
+                    networkType, 0, ConnectivityManager.getNetworkTypeName(networkType), "");
             result.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, null, null);
             return result;
         }