Merge changes I86257bc8,I5c2221c5 into nyc-dev

* changes:
  Use Netd's binder interface to set resolver configuration.
  Add Gservices settings for resolver configuration.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9070ad9..933dddf 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -81,13 +81,6 @@
 public class ConnectivityManager {
     private static final String TAG = "ConnectivityManager";
 
-    private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
-            new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
-
-    private static final String whatToString(int what) {
-        return sMagicDecoderRing.get(what, Integer.toString(what));
-    }
-
     /**
      * A change in network connectivity has occurred. A default connection has either
      * been established or lost. The NetworkInfo for the affected network is
@@ -781,8 +774,13 @@
      * @hide
      */
     public Network getActiveNetworkForUid(int uid) {
+        return getActiveNetworkForUid(uid, false);
+    }
+
+    /** {@hide} */
+    public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
         try {
-            return mService.getActiveNetworkForUid(uid);
+            return mService.getActiveNetworkForUid(uid, ignoreBlocked);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -843,8 +841,13 @@
      * {@hide}
      */
     public NetworkInfo getActiveNetworkInfoForUid(int uid) {
+        return getActiveNetworkInfoForUid(uid, false);
+    }
+
+    /** {@hide} */
+    public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
         try {
-            return mService.getActiveNetworkInfoForUid(uid);
+            return mService.getActiveNetworkInfoForUid(uid, ignoreBlocked);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -887,8 +890,13 @@
      *        is not valid.
      */
     public NetworkInfo getNetworkInfo(Network network) {
+        return getNetworkInfoForUid(network, Process.myUid(), false);
+    }
+
+    /** {@hide} */
+    public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
         try {
-            return mService.getNetworkInfoForNetwork(network);
+            return mService.getNetworkInfoForUid(network, uid, ignoreBlocked);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -3360,4 +3368,32 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * A holder class for debug info (mapping CALLBACK values to field names). This is stored
+     * in a holder for two reasons:
+     * 1) The reflection necessary to establish the map can't be run at compile-time. Thus, this
+     *    code will make the enclosing class not compile-time initializeable, deferring its
+     *    initialization to zygote startup. This leads to dirty (but shared) memory.
+     *    As this is debug info, use a holder that isn't initialized by default. This way the map
+     *    will be created on demand, while ConnectivityManager can be compile-time initialized.
+     * 2) Static initialization is still preferred for its strong thread safety guarantees without
+     *    requiring a lock.
+     */
+    private static class NoPreloadHolder {
+        public static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
+                new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
+    }
+
+    static {
+        // When debug is enabled, aggressively initialize the holder by touching the field (which
+        // will guarantee static initialization).
+        if (CallbackHandler.DBG) {
+            Object dummy = NoPreloadHolder.sMagicDecoderRing;
+        }
+    }
+
+    private static final String whatToString(int what) {
+        return NoPreloadHolder.sMagicDecoderRing.get(what, Integer.toString(what));
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index c897c45..aec6b3e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -44,11 +44,11 @@
 interface IConnectivityManager
 {
     Network getActiveNetwork();
-    Network getActiveNetworkForUid(int uid);
+    Network getActiveNetworkForUid(int uid, boolean ignoreBlocked);
     NetworkInfo getActiveNetworkInfo();
-    NetworkInfo getActiveNetworkInfoForUid(int uid);
+    NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked);
     NetworkInfo getNetworkInfo(int networkType);
-    NetworkInfo getNetworkInfoForNetwork(in Network network);
+    NetworkInfo getNetworkInfoForUid(in Network network, int uid, boolean ignoreBlocked);
     NetworkInfo[] getAllNetworkInfo();
     Network getNetworkForType(int networkType);
     Network[] getAllNetworks();
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 6418614..6243f46 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -809,17 +809,7 @@
     @Override
     public String toString() {
         int[] types = getTransportTypes();
-        String transports = (types.length > 0 ? " Transports: " : "");
-        for (int i = 0; i < types.length;) {
-            switch (types[i]) {
-                case TRANSPORT_CELLULAR:    transports += "CELLULAR"; break;
-                case TRANSPORT_WIFI:        transports += "WIFI"; break;
-                case TRANSPORT_BLUETOOTH:   transports += "BLUETOOTH"; break;
-                case TRANSPORT_ETHERNET:    transports += "ETHERNET"; break;
-                case TRANSPORT_VPN:         transports += "VPN"; break;
-            }
-            if (++i < types.length) transports += "|";
-        }
+        String transports = (types.length > 0) ? " Transports: " + transportNamesOf(types) : "";
 
         types = getCapabilities();
         String capabilities = (types.length > 0 ? " Capabilities: " : "");
@@ -859,4 +849,22 @@
 
         return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength + "]";
     }
+
+    /**
+     * @hide
+     */
+    public static String transportNamesOf(int[] types) {
+        String transports = "";
+        for (int i = 0; i < types.length;) {
+            switch (types[i]) {
+                case TRANSPORT_CELLULAR:    transports += "CELLULAR"; break;
+                case TRANSPORT_WIFI:        transports += "WIFI"; break;
+                case TRANSPORT_BLUETOOTH:   transports += "BLUETOOTH"; break;
+                case TRANSPORT_ETHERNET:    transports += "ETHERNET"; break;
+                case TRANSPORT_VPN:         transports += "VPN"; break;
+            }
+            if (++i < types.length) transports += "|";
+        }
+        return transports;
+    }
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 75643f6..00dcdea 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -29,8 +29,11 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
+import static android.net.NetworkPolicyManager.RULE_ALLOW_METERED;
 import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
+import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
+import static android.net.NetworkPolicyManager.RULE_UNKNOWN;
 
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
@@ -97,8 +100,10 @@
 import android.security.KeyStore;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.LocalLog.ReadOnlyLocalLog;
+import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -122,9 +127,9 @@
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.KeepaliveTracker;
-import com.android.server.connectivity.NetworkDiagnostics;
 import com.android.server.connectivity.Nat464Xlat;
 import com.android.server.connectivity.NetworkAgentInfo;
+import com.android.server.connectivity.NetworkDiagnostics;
 import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.PacManager;
 import com.android.server.connectivity.PermissionMonitor;
@@ -132,8 +137,8 @@
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
 import com.android.server.net.LockdownVpnTracker;
+
 import com.google.android.collect.Lists;
-import com.google.android.collect.Sets;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -153,11 +158,11 @@
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.SortedSet;
-import java.util.TreeSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.SortedSet;
+import java.util.TreeSet;
 
 /**
  * @hide
@@ -203,9 +208,14 @@
     /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */
     private Object mRulesLock = new Object();
     /** Currently active network rules by UID. */
+    @GuardedBy("mRulesLock")
     private SparseIntArray mUidRules = new SparseIntArray();
     /** Set of ifaces that are costly. */
-    private HashSet<String> mMeteredIfaces = Sets.newHashSet();
+    @GuardedBy("mRulesLock")
+    private ArraySet<String> mMeteredIfaces = new ArraySet<>();
+    /** Flag indicating if background data is restricted. */
+    @GuardedBy("mRulesLock")
+    private boolean mRestrictBackground;
 
     final private Context mContext;
     private int mNetworkPreference;
@@ -652,7 +662,8 @@
         mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
 
         try {
-            mPolicyManager.registerListener(mPolicyListener);
+            mPolicyManager.setConnectivityListener(mPolicyListener);
+            mRestrictBackground = mPolicyManager.getRestrictBackground();
         } catch (RemoteException e) {
             // ouch, no rules updates means some processes may never get network
             loge("unable to register INetworkPolicyListener" + e.toString());
@@ -731,7 +742,7 @@
         //set up the listener for user state for creating user VPNs
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_STARTING);
-        intentFilter.addAction(Intent.ACTION_USER_STOPPING);
+        intentFilter.addAction(Intent.ACTION_USER_STOPPED);
         intentFilter.addAction(Intent.ACTION_USER_ADDED);
         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
         intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
@@ -820,7 +831,7 @@
         throw new IllegalStateException("No free netIds");
     }
 
-    private NetworkState getFilteredNetworkState(int networkType, int uid) {
+    private NetworkState getFilteredNetworkState(int networkType, int uid, boolean ignoreBlocked) {
         if (mLegacyTypeTracker.isTypeSupported(networkType)) {
             final NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType);
             final NetworkState state;
@@ -835,7 +846,7 @@
                 state = new NetworkState(info, new LinkProperties(), new NetworkCapabilities(),
                         null, null, null);
             }
-            filterNetworkStateForUid(state, uid);
+            filterNetworkStateForUid(state, uid, ignoreBlocked);
             return state;
         } else {
             return NetworkState.EMPTY;
@@ -891,22 +902,36 @@
     /**
      * Check if UID should be blocked from using the network with the given LinkProperties.
      */
-    private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid) {
-        final boolean networkCostly;
+    private boolean isNetworkWithLinkPropertiesBlocked(LinkProperties lp, int uid,
+            boolean ignoreBlocked) {
+        // Networks aren't blocked when ignoring blocked status
+        if (ignoreBlocked) return false;
+        // Networks are never blocked for system services
+        if (uid < Process.FIRST_APPLICATION_UID) return false;
+
+        final boolean networkMetered;
         final int uidRules;
 
         final String iface = (lp == null ? "" : lp.getInterfaceName());
         synchronized (mRulesLock) {
-            networkCostly = mMeteredIfaces.contains(iface);
-            uidRules = mUidRules.get(uid, RULE_ALLOW_ALL);
+            networkMetered = mMeteredIfaces.contains(iface);
+            uidRules = mUidRules.get(uid, RULE_UNKNOWN);
         }
 
-        if (uidRules == RULE_REJECT_ALL) {
-            return true;
-        } else if ((uidRules == RULE_REJECT_METERED) && networkCostly) {
-            return true;
-        } else {
-            return false;
+        switch (uidRules) {
+            case RULE_ALLOW_ALL:
+            case RULE_ALLOW_METERED:
+            case RULE_TEMPORARY_ALLOW_METERED:
+                return false;
+            case RULE_REJECT_METERED:
+                return networkMetered;
+            case RULE_REJECT_ALL:
+                return true;
+            case RULE_UNKNOWN:
+            default:
+                // When background data is restricted device-wide, the default
+                // behavior for apps should be like RULE_REJECT_METERED
+                return mRestrictBackground ? networkMetered : false;
         }
     }
 
@@ -931,10 +956,10 @@
      * on {@link #isNetworkWithLinkPropertiesBlocked}, or
      * {@link NetworkInfo#isMetered()} based on network policies.
      */
-    private void filterNetworkStateForUid(NetworkState state, int uid) {
+    private void filterNetworkStateForUid(NetworkState state, int uid, boolean ignoreBlocked) {
         if (state == null || state.networkInfo == null || state.linkProperties == null) return;
 
-        if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) {
+        if (isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, ignoreBlocked)) {
             state.networkInfo.setDetailedState(DetailedState.BLOCKED, null, null);
         }
         if (mLockdownTracker != null) {
@@ -963,7 +988,7 @@
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
         final NetworkState state = getUnfilteredActiveNetworkState(uid);
-        filterNetworkStateForUid(state, uid);
+        filterNetworkStateForUid(state, uid, false);
         maybeLogBlockedNetworkInfo(state.networkInfo, uid);
         return state.networkInfo;
     }
@@ -971,16 +996,16 @@
     @Override
     public Network getActiveNetwork() {
         enforceAccessPermission();
-        return getActiveNetworkForUidInternal(Binder.getCallingUid());
+        return getActiveNetworkForUidInternal(Binder.getCallingUid(), false);
     }
 
     @Override
-    public Network getActiveNetworkForUid(int uid) {
+    public Network getActiveNetworkForUid(int uid, boolean ignoreBlocked) {
         enforceConnectivityInternalPermission();
-        return getActiveNetworkForUidInternal(uid);
+        return getActiveNetworkForUidInternal(uid, ignoreBlocked);
     }
 
-    private Network getActiveNetworkForUidInternal(final int uid) {
+    private Network getActiveNetworkForUidInternal(final int uid, boolean ignoreBlocked) {
         final int user = UserHandle.getUserId(uid);
         int vpnNetId = NETID_UNSET;
         synchronized (mVpns) {
@@ -995,7 +1020,10 @@
             if (nai != null) return nai.network;
         }
         nai = getDefaultNetwork();
-        if (nai != null && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) nai = null;
+        if (nai != null
+                && isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, ignoreBlocked)) {
+            nai = null;
+        }
         return nai != null ? nai.network : null;
     }
 
@@ -1007,10 +1035,10 @@
     }
 
     @Override
-    public NetworkInfo getActiveNetworkInfoForUid(int uid) {
+    public NetworkInfo getActiveNetworkInfoForUid(int uid, boolean ignoreBlocked) {
         enforceConnectivityInternalPermission();
         final NetworkState state = getUnfilteredActiveNetworkState(uid);
-        filterNetworkStateForUid(state, uid);
+        filterNetworkStateForUid(state, uid, ignoreBlocked);
         return state.networkInfo;
     }
 
@@ -1024,22 +1052,21 @@
             // getUnfilteredActiveNetworkState.
             final NetworkState state = getUnfilteredActiveNetworkState(uid);
             if (state.networkInfo != null && state.networkInfo.getType() == networkType) {
-                filterNetworkStateForUid(state, uid);
+                filterNetworkStateForUid(state, uid, false);
                 return state.networkInfo;
             }
         }
-        final NetworkState state = getFilteredNetworkState(networkType, uid);
+        final NetworkState state = getFilteredNetworkState(networkType, uid, false);
         return state.networkInfo;
     }
 
     @Override
-    public NetworkInfo getNetworkInfoForNetwork(Network network) {
+    public NetworkInfo getNetworkInfoForUid(Network network, int uid, boolean ignoreBlocked) {
         enforceAccessPermission();
-        final int uid = Binder.getCallingUid();
         final NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
         if (nai != null) {
             final NetworkState state = nai.getNetworkState();
-            filterNetworkStateForUid(state, uid);
+            filterNetworkStateForUid(state, uid, ignoreBlocked);
             return state.networkInfo;
         } else {
             return null;
@@ -1064,8 +1091,8 @@
     public Network getNetworkForType(int networkType) {
         enforceAccessPermission();
         final int uid = Binder.getCallingUid();
-        NetworkState state = getFilteredNetworkState(networkType, uid);
-        if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid)) {
+        NetworkState state = getFilteredNetworkState(networkType, uid, false);
+        if (!isNetworkWithLinkPropertiesBlocked(state.linkProperties, uid, false)) {
             return state.network;
         }
         return null;
@@ -1382,6 +1409,15 @@
             if (LOGD_RULES) {
                 log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
             }
+
+            synchronized (mRulesLock) {
+                mRestrictBackground = restrictBackground;
+            }
+
+            if (restrictBackground) {
+                log("onRestrictBackgroundChanged(true): disabling tethering");
+                mTethering.untetherAll();
+            }
         }
 
         @Override
@@ -1813,6 +1849,18 @@
         pw.decreaseIndent();
         pw.println();
 
+        pw.println("Metered Interfaces:");
+        pw.increaseIndent();
+        for (String value : mMeteredIfaces) {
+            pw.println(value);
+        }
+        pw.decreaseIndent();
+        pw.println();
+
+        pw.print("Restrict background: ");
+        pw.println(mRestrictBackground);
+        pw.println();
+
         pw.println("Network Requests:");
         pw.increaseIndent();
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -2568,7 +2616,14 @@
     public int tether(String iface) {
         ConnectivityManager.enforceTetherChangePermission(mContext);
         if (isTetheringSupported()) {
-            return mTethering.tether(iface);
+            final int status = mTethering.tether(iface);
+            if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                try {
+                    mPolicyManager.onTetheringChanged(iface, true);
+                } catch (RemoteException e) {
+                }
+            }
+            return status;
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -2579,7 +2634,14 @@
         ConnectivityManager.enforceTetherChangePermission(mContext);
 
         if (isTetheringSupported()) {
-            return mTethering.untether(iface);
+            final int status = mTethering.untether(iface);
+            if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                try {
+                    mPolicyManager.onTetheringChanged(iface, false);
+                } catch (RemoteException e) {
+                }
+            }
+            return status;
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -2740,7 +2802,7 @@
             // which isn't meant to work on uncreated networks.
             if (!nai.created) return;
 
-            if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid)) return;
+            if (isNetworkWithLinkPropertiesBlocked(nai.linkProperties, uid, false)) return;
 
             nai.networkMonitor.sendMessage(NetworkMonitor.CMD_FORCE_REEVALUATION, uid);
         }
@@ -3594,7 +3656,7 @@
         synchronized(mVpns) {
             Vpn userVpn = mVpns.get(userId);
             if (userVpn == null) {
-                loge("Stopping user has no VPN");
+                loge("Stopped user has no VPN");
                 return;
             }
             mVpns.delete(userId);
@@ -3639,7 +3701,7 @@
 
             if (Intent.ACTION_USER_STARTING.equals(action)) {
                 onUserStart(userId);
-            } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
+            } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                 onUserStop(userId);
             } else if (Intent.ACTION_USER_ADDED.equals(action)) {
                 onUserAdded(userId);