merge in klp-release history after reset to klp-dev
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
index 9c4772b..76aea9f 100644
--- a/core/java/android/net/ProxyProperties.java
+++ b/core/java/android/net/ProxyProperties.java
@@ -20,9 +20,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
-import android.util.Log;
 
-import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.UnknownHostException;
 import java.util.Locale;
@@ -38,17 +36,30 @@
     private String mExclusionList;
     private String[] mParsedExclusionList;
 
+    private String mPacFileUrl;
+    public static final String LOCAL_EXCL_LIST = "";
+    public static final int LOCAL_PORT = 8182;
+    public static final String LOCAL_HOST = "localhost";
+
     public ProxyProperties(String host, int port, String exclList) {
         mHost = host;
         mPort = port;
         setExclusionList(exclList);
     }
 
+    public ProxyProperties(String pacFileUrl) {
+        mHost = LOCAL_HOST;
+        mPort = LOCAL_PORT;
+        setExclusionList(LOCAL_EXCL_LIST);
+        mPacFileUrl = pacFileUrl;
+    }
+
     private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
         mHost = host;
         mPort = port;
         mExclusionList = exclList;
         mParsedExclusionList = parsedExclList;
+        mPacFileUrl = null;
     }
 
     // copy constructor instead of clone
@@ -56,6 +67,7 @@
         if (source != null) {
             mHost = source.getHost();
             mPort = source.getPort();
+            mPacFileUrl = source.getPacFileUrl();
             mExclusionList = source.getExclusionList();
             mParsedExclusionList = source.mParsedExclusionList;
         }
@@ -69,6 +81,10 @@
         return inetSocketAddress;
     }
 
+    public String getPacFileUrl() {
+        return mPacFileUrl;
+    }
+
     public String getHost() {
         return mHost;
     }
@@ -130,7 +146,10 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        if (mHost != null) {
+        if (mPacFileUrl != null) {
+            sb.append("PAC Script: ");
+            sb.append(mPacFileUrl);
+        } else if (mHost != null) {
             sb.append("[");
             sb.append(mHost);
             sb.append("] ");
@@ -148,6 +167,14 @@
     public boolean equals(Object o) {
         if (!(o instanceof ProxyProperties)) return false;
         ProxyProperties p = (ProxyProperties)o;
+        // If PAC URL is present in either then they must be equal.
+        // Other parameters will only be for fall back.
+        if (!TextUtils.isEmpty(mPacFileUrl)) {
+            return mPacFileUrl.equals(p.getPacFileUrl());
+        }
+        if (!TextUtils.isEmpty(p.getPacFileUrl())) {
+            return false;
+        }
         if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false;
         if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
             return false;
@@ -181,6 +208,13 @@
      * @hide
      */
     public void writeToParcel(Parcel dest, int flags) {
+        if (mPacFileUrl != null) {
+            dest.writeByte((byte)1);
+            dest.writeString(mPacFileUrl);
+            return;
+        } else {
+            dest.writeByte((byte)0);
+        }
         if (mHost != null) {
             dest.writeByte((byte)1);
             dest.writeString(mHost);
@@ -201,7 +235,10 @@
             public ProxyProperties createFromParcel(Parcel in) {
                 String host = null;
                 int port = 0;
-                if (in.readByte() == 1) {
+                if (in.readByte() != 0) {
+                    return new ProxyProperties(in.readString());
+                }
+                if (in.readByte() != 0) {
                     host = in.readString();
                     port = in.readInt();
                 }
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
index d8290f4..9fdfd0e 100644
--- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -25,14 +25,18 @@
 import java.util.ArrayList;
 
 public class LinkPropertiesTest extends TestCase {
-    private static String ADDRV4 = "75.208.6.1";
-    private static String ADDRV6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
-    private static String DNS1 = "75.208.7.1";
-    private static String DNS2 = "69.78.7.1";
-    private static String GATEWAY1 = "75.208.8.1";
-    private static String GATEWAY2 = "69.78.8.1";
+    private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
+    private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress(
+            "2001:0db8:85a3:0000:0000:8a2e:0370:7334");
+    private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1");
+    private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1");
+    private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1");
+    private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1");
     private static String NAME = "qmi0";
 
+    private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32);
+    private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128);
+
     public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) {
         // Check implementation of equals(), element by element.
         assertTrue(source.isIdenticalInterfaceName(target));
@@ -76,43 +80,37 @@
             LinkProperties source = new LinkProperties();
             source.setInterfaceName(NAME);
             // set 2 link addresses
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            source.addLinkAddress(LINKADDRV4);
+            source.addLinkAddress(LINKADDRV6);
             // set 2 dnses
-            source.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            source.addDns(NetworkUtils.numericToInetAddress(DNS2));
+            source.addDns(DNS1);
+            source.addDns(DNS2);
             // set 2 gateways
-            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            source.addRoute(new RouteInfo(GATEWAY1));
+            source.addRoute(new RouteInfo(GATEWAY2));
 
             LinkProperties target = new LinkProperties();
 
             // All fields are same
             target.setInterfaceName(NAME);
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
 
             assertLinkPropertiesEqual(source, target);
 
             target.clear();
             // change Interface Name
             target.setInterfaceName("qmi1");
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
             assertFalse(source.equals(target));
 
             target.clear();
@@ -120,38 +118,33 @@
             // change link addresses
             target.addLinkAddress(new LinkAddress(
                     NetworkUtils.numericToInetAddress("75.208.6.2"), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
             assertFalse(source.equals(target));
 
             target.clear();
             target.setInterfaceName(NAME);
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
             // change dnses
             target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2"));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addDns(DNS2);
+            target.addRoute(new RouteInfo(GATEWAY1));
+            target.addRoute(new RouteInfo(GATEWAY2));
             assertFalse(source.equals(target));
 
             target.clear();
             target.setInterfaceName(NAME);
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addDns(DNS1);
+            target.addDns(DNS2);
             // change gateway
             target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            target.addRoute(new RouteInfo(GATEWAY2));
             assertFalse(source.equals(target));
 
         } catch (Exception e) {
@@ -166,28 +159,24 @@
             LinkProperties source = new LinkProperties();
             source.setInterfaceName(NAME);
             // set 2 link addresses
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            source.addLinkAddress(LINKADDRV4);
+            source.addLinkAddress(LINKADDRV6);
             // set 2 dnses
-            source.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            source.addDns(NetworkUtils.numericToInetAddress(DNS2));
+            source.addDns(DNS1);
+            source.addDns(DNS2);
             // set 2 gateways
-            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
-            source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+            source.addRoute(new RouteInfo(GATEWAY1));
+            source.addRoute(new RouteInfo(GATEWAY2));
 
             LinkProperties target = new LinkProperties();
             // Exchange order
             target.setInterfaceName(NAME);
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS2));
-            target.addDns(NetworkUtils.numericToInetAddress(DNS1));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
-            target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+            target.addLinkAddress(LINKADDRV6);
+            target.addLinkAddress(LINKADDRV4);
+            target.addDns(DNS2);
+            target.addDns(DNS1);
+            target.addRoute(new RouteInfo(GATEWAY2));
+            target.addRoute(new RouteInfo(GATEWAY1));
 
             assertLinkPropertiesEqual(source, target);
         } catch (Exception e) {
@@ -200,21 +189,15 @@
         try {
             LinkProperties source = new LinkProperties();
             // set 3 link addresses, eg, [A, A, B]
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            source.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            source.addLinkAddress(LINKADDRV4);
+            source.addLinkAddress(LINKADDRV4);
+            source.addLinkAddress(LINKADDRV6);
 
             LinkProperties target = new LinkProperties();
             // set 3 link addresses, eg, [A, B, B]
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
-            target.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+            target.addLinkAddress(LINKADDRV4);
+            target.addLinkAddress(LINKADDRV6);
+            target.addLinkAddress(LINKADDRV6);
 
             assertLinkPropertiesEqual(source, target);
         } catch (Exception e) {
@@ -232,7 +215,7 @@
     public void testRouteInterfaces() {
         LinkAddress prefix = new LinkAddress(
             NetworkUtils.numericToInetAddress("2001:db8::"), 32);
-        InetAddress address = NetworkUtils.numericToInetAddress(ADDRV6);
+        InetAddress address = ADDRV6;
 
         // Add a route with no interface to a LinkProperties with no interface. No errors.
         LinkProperties lp = new LinkProperties();
@@ -265,7 +248,7 @@
         assertAllRoutesHaveInterface("wlan0", lp);
 
         // Routes with null interfaces are converted to wlan0.
-        r = RouteInfo.makeHostRoute(NetworkUtils.numericToInetAddress(ADDRV6), null);
+        r = RouteInfo.makeHostRoute(ADDRV6, null);
         lp.addRoute(r);
         assertEquals(3, lp.getRoutes().size());
         assertAllRoutesHaveInterface("wlan0", lp);
@@ -286,13 +269,11 @@
     public void testStackedInterfaces() {
         LinkProperties rmnet0 = new LinkProperties();
         rmnet0.setInterfaceName("rmnet0");
-        rmnet0.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV6), 128));
+        rmnet0.addLinkAddress(LINKADDRV6);
 
         LinkProperties clat4 = new LinkProperties();
         clat4.setInterfaceName("clat4");
-        clat4.addLinkAddress(new LinkAddress(
-                    NetworkUtils.numericToInetAddress(ADDRV4), 32));
+        clat4.addLinkAddress(LINKADDRV4);
 
         assertEquals(0, rmnet0.getStackedLinks().size());
         assertEquals(1, rmnet0.getAddresses().size());
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 17ae85f..3ae2eb5 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -56,13 +56,11 @@
 import android.net.INetworkStatsService;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
-import android.net.Uri;
 import android.net.LinkProperties.CompareResult;
 import android.net.MobileDataStateTracker;
 import android.net.NetworkConfig;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
-import android.net.NetworkInfo.State;
 import android.net.NetworkQuotaInfo;
 import android.net.NetworkState;
 import android.net.NetworkStateTracker;
@@ -70,6 +68,7 @@
 import android.net.Proxy;
 import android.net.ProxyProperties;
 import android.net.RouteInfo;
+import android.net.Uri;
 import android.net.wifi.WifiStateTracker;
 import android.net.wimax.WimaxManagerConstants;
 import android.os.AsyncTask;
@@ -102,6 +101,7 @@
 import android.util.Xml;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
 import com.android.internal.net.VpnProfile;
@@ -110,9 +110,11 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
+import com.android.net.IProxyService;
 import com.android.server.am.BatteryStatsService;
 import com.android.server.connectivity.DataConnectionStats;
 import com.android.server.connectivity.Nat464Xlat;
+import com.android.server.connectivity.PacManager;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
@@ -120,8 +122,6 @@
 import com.google.android.collect.Lists;
 import com.google.android.collect.Sets;
 
-import com.android.internal.annotations.GuardedBy;
-
 import dalvik.system.DexClassLoader;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -370,6 +370,8 @@
     // track the global proxy.
     private ProxyProperties mGlobalProxy = null;
 
+    private PacManager mPacManager = null;
+
     private SettingsObserver mSettingsObserver;
 
     NetworkConfig[] mNetConfigs;
@@ -631,6 +633,8 @@
 
         mDataConnectionStats = new DataConnectionStats(mContext);
         mDataConnectionStats.startMonitoring();
+
+        mPacManager = new PacManager(mContext);
     }
 
     /**
@@ -3168,13 +3172,15 @@
         // of proxy info to all the JVMs.
         // enforceAccessPermission();
         synchronized (mProxyLock) {
-            if (mGlobalProxy != null) return mGlobalProxy;
-            return (mDefaultProxyDisabled ? null : mDefaultProxy);
+            ProxyProperties ret = mGlobalProxy;
+            if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy;
+            return ret;
         }
     }
 
     public void setGlobalProxy(ProxyProperties proxyProperties) {
         enforceConnectivityInternalPermission();
+
         synchronized (mProxyLock) {
             if (proxyProperties == mGlobalProxy) return;
             if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return;
@@ -3183,11 +3189,16 @@
             String host = "";
             int port = 0;
             String exclList = "";
-            if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
+            String pacFileUrl = "";
+            if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) ||
+                    !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) {
                 mGlobalProxy = new ProxyProperties(proxyProperties);
                 host = mGlobalProxy.getHost();
                 port = mGlobalProxy.getPort();
                 exclList = mGlobalProxy.getExclusionList();
+                if (proxyProperties.getPacFileUrl() != null) {
+                    pacFileUrl = proxyProperties.getPacFileUrl();
+                }
             } else {
                 mGlobalProxy = null;
             }
@@ -3198,6 +3209,7 @@
                 Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port);
                 Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
                         exclList);
+                Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -3215,8 +3227,14 @@
         int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0);
         String exclList = Settings.Global.getString(res,
                 Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
-        if (!TextUtils.isEmpty(host)) {
-            ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
+        String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC);
+        if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) {
+            ProxyProperties proxyProperties;
+            if (!TextUtils.isEmpty(pacFileUrl)) {
+                proxyProperties = new ProxyProperties(pacFileUrl);
+            } else {
+                proxyProperties = new ProxyProperties(host, port, exclList);
+            }
             synchronized (mProxyLock) {
                 mGlobalProxy = proxyProperties;
             }
@@ -3234,7 +3252,8 @@
     }
 
     private void handleApplyDefaultProxy(ProxyProperties proxy) {
-        if (proxy != null && TextUtils.isEmpty(proxy.getHost())) {
+        if (proxy != null && TextUtils.isEmpty(proxy.getHost())
+                && TextUtils.isEmpty(proxy.getPacFileUrl())) {
             proxy = null;
         }
         synchronized (mProxyLock) {
@@ -3276,6 +3295,7 @@
 
     private void sendProxyBroadcast(ProxyProperties proxy) {
         if (proxy == null) proxy = new ProxyProperties("", 0, "");
+        mPacManager.setCurrentProxyScriptUrl(proxy);
         if (DBG) log("sending Proxy Broadcast for " + proxy);
         Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION);
         intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |