Merge "Add Network-specific host name resolution API."
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 3e00250..2406cba 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1587,4 +1587,11 @@
         } catch (RemoteException e) {
         }
     }
+
+    /** {@hide} */
+    public void registerNetworkFactory(Messenger messenger) {
+        try {
+            mService.registerNetworkFactory(messenger);
+        } catch (RemoteException e) { }
+    }
 }
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index d53a856..b69797e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -150,4 +150,6 @@
     void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url);
 
     void setAirplaneMode(boolean enable);
+
+    void registerNetworkFactory(in Messenger messenger);
 }
diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java
index b40941f..991d9da 100644
--- a/core/java/android/net/ProxyInfo.java
+++ b/core/java/android/net/ProxyInfo.java
@@ -44,7 +44,7 @@
     private String mExclusionList;
     private String[] mParsedExclusionList;
 
-    private String mPacFileUrl;
+    private Uri mPacFileUrl;
     /**
      *@hide
      */
@@ -85,7 +85,7 @@
      * at the specified URL.
      */
     public static ProxyInfo buildPacProxy(Uri pacUri) {
-        return new ProxyInfo(pacUri.toString());
+        return new ProxyInfo(pacUri);
     }
 
     /**
@@ -96,6 +96,21 @@
         mHost = host;
         mPort = port;
         setExclusionList(exclList);
+        mPacFileUrl = Uri.EMPTY;
+    }
+
+    /**
+     * Create a ProxyProperties that points at a PAC URL.
+     * @hide
+     */
+    public ProxyInfo(Uri pacFileUrl) {
+        mHost = LOCAL_HOST;
+        mPort = LOCAL_PORT;
+        setExclusionList(LOCAL_EXCL_LIST);
+        if (pacFileUrl == null) {
+            throw new NullPointerException();
+        }
+        mPacFileUrl = pacFileUrl;
     }
 
     /**
@@ -106,17 +121,20 @@
         mHost = LOCAL_HOST;
         mPort = LOCAL_PORT;
         setExclusionList(LOCAL_EXCL_LIST);
-        mPacFileUrl = pacFileUrl;
+        mPacFileUrl = Uri.parse(pacFileUrl);
     }
 
     /**
      * Only used in PacManager after Local Proxy is bound.
      * @hide
      */
-    public ProxyInfo(String pacFileUrl, int localProxyPort) {
+    public ProxyInfo(Uri pacFileUrl, int localProxyPort) {
         mHost = LOCAL_HOST;
         mPort = localProxyPort;
         setExclusionList(LOCAL_EXCL_LIST);
+        if (pacFileUrl == null) {
+            throw new NullPointerException();
+        }
         mPacFileUrl = pacFileUrl;
     }
 
@@ -125,7 +143,7 @@
         mPort = port;
         mExclusionList = exclList;
         mParsedExclusionList = parsedExclList;
-        mPacFileUrl = null;
+        mPacFileUrl = Uri.EMPTY;
     }
 
     // copy constructor instead of clone
@@ -137,6 +155,9 @@
             mHost = source.getHost();
             mPort = source.getPort();
             mPacFileUrl = source.mPacFileUrl;
+            if (mPacFileUrl == null) {
+                mPacFileUrl = Uri.EMPTY;
+            }
             mExclusionList = source.getExclusionListAsString();
             mParsedExclusionList = source.mParsedExclusionList;
         }
@@ -158,10 +179,7 @@
      * no PAC script.
      */
     public Uri getPacFileUrl() {
-        if (TextUtils.isEmpty(mPacFileUrl)) {
-            return null;
-        }
-        return Uri.parse(mPacFileUrl);
+        return mPacFileUrl;
     }
 
     /**
@@ -210,7 +228,7 @@
      * @hide
      */
     public boolean isValid() {
-        if (!TextUtils.isEmpty(mPacFileUrl)) return true;
+        if (!Uri.EMPTY.equals(mPacFileUrl)) return true;
         return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost,
                                                 mPort == 0 ? "" : Integer.toString(mPort),
                                                 mExclusionList == null ? "" : mExclusionList);
@@ -234,7 +252,7 @@
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
-        if (mPacFileUrl != null) {
+        if (!Uri.EMPTY.equals(mPacFileUrl)) {
             sb.append("PAC Script: ");
             sb.append(mPacFileUrl);
         } else if (mHost != null) {
@@ -257,13 +275,15 @@
         ProxyInfo p = (ProxyInfo)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)) {
+        if (!Uri.EMPTY.equals(mPacFileUrl)) {
             return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort;
         }
-        if (!TextUtils.isEmpty(p.mPacFileUrl)) {
+        if (!Uri.EMPTY.equals(p.mPacFileUrl)) {
             return false;
         }
-        if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false;
+        if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) {
+            return false;
+        }
         if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) {
             return false;
         }
@@ -296,9 +316,9 @@
      * @hide
      */
     public void writeToParcel(Parcel dest, int flags) {
-        if (mPacFileUrl != null) {
+        if (!Uri.EMPTY.equals(mPacFileUrl)) {
             dest.writeByte((byte)1);
-            dest.writeString(mPacFileUrl);
+            mPacFileUrl.writeToParcel(dest, 0);
             dest.writeInt(mPort);
             return;
         } else {
@@ -325,7 +345,7 @@
                 String host = null;
                 int port = 0;
                 if (in.readByte() != 0) {
-                    String url = in.readString();
+                    Uri url = Uri.CREATOR.createFromParcel(in);
                     int localPort = in.readInt();
                     return new ProxyInfo(url, localPort);
                 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index c1ffd56..741bf95 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -29,6 +29,7 @@
 import static android.net.ConnectivityManager.TYPE_PROXY;
 import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol;
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
 
@@ -66,10 +67,12 @@
 import android.net.LinkQualityInfo;
 import android.net.MobileDataStateTracker;
 import android.net.Network;
+import android.net.NetworkCapabilities;
 import android.net.NetworkConfig;
 import android.net.NetworkInfo;
 import android.net.NetworkInfo.DetailedState;
 import android.net.NetworkQuotaInfo;
+import android.net.NetworkRequest;
 import android.net.NetworkState;
 import android.net.NetworkStateTracker;
 import android.net.NetworkUtils;
@@ -119,6 +122,7 @@
 import com.android.internal.telephony.Phone;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 import com.android.server.am.BatteryStatsService;
@@ -372,6 +376,12 @@
      */
     private static final int EVENT_PROXY_HAS_CHANGED = 16;
 
+    /**
+     * used internally when registering NetworkFactories
+     * obj = Messenger
+     */
+    private static final int EVENT_REGISTER_NETWORK_FACTORY = 17;
+
     /** Handler used for internal events. */
     private InternalHandler mHandler;
     /** Handler used for incoming {@link NetworkStateTracker} events. */
@@ -461,6 +471,12 @@
             NetworkFactory netFactory) {
         if (DBG) log("ConnectivityService starting up");
 
+        NetworkCapabilities netCap = new NetworkCapabilities();
+        netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+        netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
+        NetworkRequest netRequest = new NetworkRequest(netCap);
+        mNetworkRequests.append(netRequest.requestId, netRequest);
+
         HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
         handlerThread.start();
         mHandler = new InternalHandler(handlerThread.getLooper());
@@ -2084,7 +2100,7 @@
                     getConnectivityChangeDelay());
         }
         try {
-            mNetd.removeNetwork(thisNetId);
+//            mNetd.removeNetwork(thisNetId);
         } catch (Exception e) {
             loge("Exception removing network: " + e);
         } finally {
@@ -2388,7 +2404,7 @@
             int thisNetId = nextNetId();
             thisNet.setNetId(thisNetId);
             try {
-                mNetd.createNetwork(thisNetId, thisIface);
+//                mNetd.createNetwork(thisNetId, thisIface);
             } catch (Exception e) {
                 loge("Exception creating network :" + e);
                 teardown(thisNet);
@@ -2420,7 +2436,7 @@
             int thisNetId = nextNetId();
             thisNet.setNetId(thisNetId);
             try {
-                mNetd.createNetwork(thisNetId, thisIface);
+//                mNetd.createNetwork(thisNetId, thisIface);
             } catch (Exception e) {
                 loge("Exception creating network :" + e);
                 teardown(thisNet);
@@ -3048,6 +3064,22 @@
         public void handleMessage(Message msg) {
             NetworkInfo info;
             switch (msg.what) {
+                case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: {
+                    AsyncChannel ac = (AsyncChannel) msg.obj;
+                    if (mNetworkFactories.contains(ac)) {
+                        if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
+                            if (VDBG) log("NetworkFactory connected");
+                            for (int i = 0; i < mNetworkRequests.size(); i++) {
+                                ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK,
+                                    mNetworkRequests.valueAt(i));
+                            }
+                        } else {
+                            loge("Error connecting NetworkFactory");
+                            mNetworkFactories.remove((AsyncChannel) msg.obj);
+                        }
+                    }
+                    break;
+                }
                 case NetworkStateTracker.EVENT_STATE_CHANGED: {
                     info = (NetworkInfo) msg.obj;
                     NetworkInfo.State state = info.getState();
@@ -3241,6 +3273,10 @@
                     handleApplyDefaultProxy((ProxyInfo)msg.obj);
                     break;
                 }
+                case EVENT_REGISTER_NETWORK_FACTORY: {
+                    handleRegisterNetworkFactory((Messenger)msg.obj);
+                    break;
+                }
             }
         }
     }
@@ -5081,4 +5117,21 @@
         long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds;
         mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent);
     }
+
+    private final ArrayList<AsyncChannel> mNetworkFactories = new ArrayList<AsyncChannel>();
+
+    public void registerNetworkFactory(Messenger messenger) {
+        enforceConnectivityInternalPermission();
+
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger));
+    }
+
+    private void handleRegisterNetworkFactory(Messenger messenger) {
+        if (VDBG) log("Got NetworkFactory Messenger");
+        AsyncChannel ac = new AsyncChannel();
+        mNetworkFactories.add(ac);
+        ac.connect(mContext, mTrackerHandler, messenger);
+    }
+
+    private final SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<NetworkRequest>();
 }