Merge "IMS Connection Capabilities Update" into mm-wireless-dev
diff --git a/Android.mk b/Android.mk
index 70eda59..bfe85f6 100644
--- a/Android.mk
+++ b/Android.mk
@@ -189,6 +189,8 @@
 	core/java/android/hardware/usb/IUsbManager.aidl \
 	core/java/android/net/ICaptivePortal.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
+	core/java/android/net/IConnectivityMetricsLogger.aidl \
+	core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl \
 	core/java/android/net/IEthernetManager.aidl \
 	core/java/android/net/IEthernetServiceListener.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
@@ -406,13 +408,13 @@
 	telephony/java/com/android/internal/telephony/ISub.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
+	telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
-	wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
-	wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl \
+	wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl \
 	wifi/java/android/net/wifi/nan/IWifiNanManager.aidl \
-	wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl \
+	wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl \
 	wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
 	wifi/java/android/net/wifi/IWifiScanner.aidl \
 	wifi/java/android/net/wifi/IRttManager.aidl \
@@ -480,10 +482,8 @@
 	frameworks/base/media/java/android/media/browse/MediaBrowser.aidl \
 	frameworks/base/wifi/java/android/net/wifi/ScanSettings.aidl \
 	frameworks/base/wifi/java/android/net/wifi/nan/ConfigRequest.aidl \
-	frameworks/base/wifi/java/android/net/wifi/nan/PublishData.aidl \
-	frameworks/base/wifi/java/android/net/wifi/nan/SubscribeData.aidl \
-	frameworks/base/wifi/java/android/net/wifi/nan/PublishSettings.aidl \
-	frameworks/base/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl \
+	frameworks/base/wifi/java/android/net/wifi/nan/PublishConfig.aidl \
+	frameworks/base/wifi/java/android/net/wifi/nan/SubscribeConfig.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pInfo.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pDeviceList.aidl \
 	frameworks/base/wifi/java/android/net/wifi/p2p/WifiP2pConfig.aidl \
@@ -493,7 +493,7 @@
 	frameworks/base/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl \
 	frameworks/base/wifi/java/android/net/wifi/WpsInfo.aidl \
 	frameworks/base/wifi/java/android/net/wifi/ScanResult.aidl \
-        frameworks/base/wifi/java/android/net/wifi/ScanInfo.aidl \
+	frameworks/base/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl \
 	frameworks/base/wifi/java/android/net/wifi/WifiEnterpriseConfig.aidl \
 	frameworks/base/wifi/java/android/net/wifi/WifiConfiguration.aidl \
 	frameworks/base/wifi/java/android/net/wifi/WifiInfo.aidl \
diff --git a/api/current.txt b/api/current.txt
index 6f023c1..c9030a5 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -18207,6 +18207,17 @@
     method public abstract void onNetworkActive();
   }
 
+  public class ConnectivityMetricsEvent implements android.os.Parcelable {
+    ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
+    field public final int componentTag;
+    field public final android.os.Parcelable data;
+    field public final int eventTag;
+    field public final long timestamp;
+  }
+
   public class Credentials {
     ctor public Credentials(int, int, int);
     method public int getGid();
@@ -19078,22 +19089,6 @@
 
 package android.net.wifi {
 
-  public class ScanInfo implements android.os.Parcelable {
-    ctor public ScanInfo(android.net.wifi.ScanResult);
-    ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int);
-    method public int describeContents();
-    method public long getBssid();
-    method public byte[] getIconData();
-    method public java.lang.String getIconType();
-    method public java.lang.String getName();
-    method public int getOsuIdentity();
-    method public int getRssi();
-    method public android.net.wifi.ScanResult getScanResult();
-    method public java.lang.String getServiceDescription();
-    method public java.lang.String getSsid();
-    method public void writeToParcel(android.os.Parcel, int);
-  }
-
   public class ScanResult implements android.os.Parcelable {
     method public int describeContents();
     method public boolean is80211mcResponder();
@@ -19218,6 +19213,7 @@
     method public java.lang.String getAltSubjectMatch();
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
+    method public java.security.cert.X509Certificate[] getCaCertificates();
     method public java.security.cert.X509Certificate getClientCertificate();
     method public java.lang.String getDomainSuffixMatch();
     method public int getEapMethod();
@@ -19230,6 +19226,7 @@
     method public void setAltSubjectMatch(java.lang.String);
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setCaCertificates(java.security.cert.X509Certificate[]);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
     method public void setDomainSuffixMatch(java.lang.String);
     method public void setEapMethod(int);
@@ -19252,6 +19249,7 @@
     field public static final int SIM = 4; // 0x4
     field public static final int TLS = 1; // 0x1
     field public static final int TTLS = 2; // 0x2
+    field public static final int UNAUTH_TLS = 7; // 0x7
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
@@ -19294,7 +19292,6 @@
     method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
-    method public java.util.List<android.net.wifi.ScanInfo> getScanInfos();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
@@ -19310,7 +19307,6 @@
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean saveConfiguration();
-    method public void setOsuSelection(int);
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
@@ -30001,6 +29997,7 @@
     method public static boolean hasProperty(int, int);
     method public boolean hasProperty(int);
     method public static java.lang.String propertiesToString(int);
+    field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -30140,6 +30137,7 @@
     method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
     method public final void setVideoState(int);
     method public static java.lang.String stateToString(int);
+    field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
     field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -30578,9 +30576,11 @@
 package android.telephony {
 
   public class CarrierConfigManager {
+    method public android.os.PersistableBundle getConfig(int);
     method public android.os.PersistableBundle getConfig();
-    method public android.os.PersistableBundle getConfigForSubId(int);
-    method public void notifyConfigChangedForSubId(int);
+    method public deprecated android.os.PersistableBundle getConfigForSubId(int);
+    method public void notifyConfigChanged(int);
+    method public deprecated void notifyConfigChangedForSubId(int);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
     field public static final java.lang.String KEY_ADDITIONAL_CALL_SETTING_BOOL = "additional_call_setting_bool";
     field public static final java.lang.String KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
@@ -30673,6 +30673,8 @@
 
   public final class CellIdentityGsm implements android.os.Parcelable {
     method public int describeContents();
+    method public int getArfcn();
+    method public int getBsic();
     method public int getCid();
     method public int getLac();
     method public int getMcc();
@@ -30685,6 +30687,7 @@
   public final class CellIdentityLte implements android.os.Parcelable {
     method public int describeContents();
     method public int getCi();
+    method public int getEarfcn();
     method public int getMcc();
     method public int getMnc();
     method public int getPci();
@@ -30700,6 +30703,7 @@
     method public int getMcc();
     method public int getMnc();
     method public int getPsc();
+    method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR;
   }
@@ -31121,10 +31125,15 @@
     method public int getActiveSubscriptionInfoCountMax();
     method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
     method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+    method public static int getDefaultDataSubscriptionId();
+    method public static int getDefaultSmsSubscriptionId();
+    method public static int getDefaultSubscriptionId();
+    method public static int getDefaultVoiceSubscriptionId();
     method public boolean isNetworkRoaming(int);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+    field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
   }
 
   public static class SubscriptionManager.OnSubscriptionsChangedListener {
@@ -31136,50 +31145,79 @@
     method public boolean canChangeDtmfToneLength();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
+    method public int getCallState(int);
     method public android.telephony.CellLocation getCellLocation();
     method public int getDataActivity();
+    method public int getDataNetworkType(int);
     method public int getDataState();
     method public java.lang.String getDeviceId();
     method public java.lang.String getDeviceId(int);
     method public java.lang.String getDeviceSoftwareVersion();
     method public java.lang.String getGroupIdLevel1();
+    method public java.lang.String getGroupIdLevel1(int);
+    method public java.lang.String getLine1AlphaTag(int);
     method public java.lang.String getLine1Number();
+    method public java.lang.String getLine1Number(int);
     method public java.lang.String getMmsUAProfUrl();
     method public java.lang.String getMmsUserAgent();
     method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
     method public java.lang.String getNetworkCountryIso();
+    method public java.lang.String getNetworkCountryIso(int);
     method public java.lang.String getNetworkOperator();
+    method public java.lang.String getNetworkOperator(int);
     method public java.lang.String getNetworkOperatorName();
+    method public java.lang.String getNetworkOperatorName(int);
     method public int getNetworkType();
+    method public int getNetworkType(int);
     method public int getPhoneCount();
     method public int getPhoneType();
     method public java.lang.String getSimCountryIso();
+    method public java.lang.String getSimCountryIso(int);
     method public java.lang.String getSimOperator();
+    method public java.lang.String getSimOperator(int);
     method public java.lang.String getSimOperatorName();
+    method public java.lang.String getSimOperatorName(int);
     method public java.lang.String getSimSerialNumber();
+    method public java.lang.String getSimSerialNumber(int);
     method public int getSimState();
     method public java.lang.String getSubscriberId();
+    method public java.lang.String getSubscriberId(int);
     method public java.lang.String getVoiceMailAlphaTag();
+    method public java.lang.String getVoiceMailAlphaTag(int);
     method public java.lang.String getVoiceMailNumber();
+    method public java.lang.String getVoiceMailNumber(int);
+    method public int getVoiceNetworkType(int);
     method public boolean hasCarrierPrivileges();
+    method public boolean hasCarrierPrivileges(int);
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
+    method public boolean iccCloseLogicalChannel(int, int);
     method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
+    method public byte[] iccExchangeSimIO(int, int, int, int, int, int, java.lang.String);
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+    method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(int, java.lang.String);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, int, java.lang.String);
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isNetworkRoaming();
+    method public boolean isNetworkRoaming(int);
     method public boolean isSmsCapable();
     method public boolean isTtyModeSupported();
     method public boolean isVoiceCapable();
     method public boolean isWorldPhone();
     method public void listen(android.telephony.PhoneStateListener, int);
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+    method public java.lang.String sendEnvelopeWithStatus(int, java.lang.String);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
+    method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
+    method public boolean setOperatorBrandOverride(int, java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
+    method public boolean setPreferredNetworkTypeToGlobal(int);
     method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
+    method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
     field public static final java.lang.String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
     field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
diff --git a/api/system-current.txt b/api/system-current.txt
index c91a967..6bc4208 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -19720,6 +19720,17 @@
     method public abstract void onNetworkActive();
   }
 
+  public class ConnectivityMetricsEvent implements android.os.Parcelable {
+    ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
+    field public final int componentTag;
+    field public final android.os.Parcelable data;
+    field public final int eventTag;
+    field public final long timestamp;
+  }
+
   public class Credentials {
     ctor public Credentials(int, int, int);
     method public int getGid();
@@ -20666,12 +20677,18 @@
   }
 
   public class RttManager {
+    method public void disableResponder(android.net.wifi.RttManager.ResponderCallback);
+    method public void enableResponder(android.net.wifi.RttManager.ResponderCallback);
     method public deprecated android.net.wifi.RttManager.Capabilities getCapabilities();
     method public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
     method public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
     method public void stopRanging(android.net.wifi.RttManager.RttListener);
     field public static final int BASE = 160256; // 0x27200
     field public static final int CMD_OP_ABORTED = 160260; // 0x27204
+    field public static final int CMD_OP_DISABLE_RESPONDER = 160262; // 0x27206
+    field public static final int CMD_OP_ENABLE_RESPONDER = 160261; // 0x27205
+    field public static final int CMD_OP_ENALBE_RESPONDER_FAILED = 160264; // 0x27208
+    field public static final int CMD_OP_ENALBE_RESPONDER_SUCCEEDED = 160263; // 0x27207
     field public static final int CMD_OP_FAILED = 160258; // 0x27202
     field public static final int CMD_OP_START_RANGING = 160256; // 0x27200
     field public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
@@ -20680,6 +20697,7 @@
     field public static final int PREAMBLE_HT = 2; // 0x2
     field public static final int PREAMBLE_LEGACY = 1; // 0x1
     field public static final int PREAMBLE_VHT = 4; // 0x4
+    field public static final int REASON_INITIATOR_NOT_ALLOWED_WHEN_RESPONDER_ON = -6; // 0xfffffffa
     field public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
     field public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
     field public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
@@ -20747,6 +20765,25 @@
     field public android.net.wifi.RttManager.RttResult[] mResults;
   }
 
+  public static abstract class RttManager.ResponderCallback {
+    ctor public RttManager.ResponderCallback();
+    method public abstract void onResponderEnableFailure(int);
+    method public abstract void onResponderEnabled(android.net.wifi.RttManager.ResponderConfig);
+  }
+
+  public static class RttManager.ResponderConfig implements android.os.Parcelable {
+    ctor public RttManager.ResponderConfig();
+    method public int describeContents();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.net.wifi.RttManager.ResponderConfig> CREATOR;
+    field public int centerFreq0;
+    field public int centerFreq1;
+    field public int channelWidth;
+    field public int frequency;
+    field public java.lang.String macAddress;
+    field public int preamble;
+  }
+
   public static class RttManager.RttCapabilities implements android.os.Parcelable {
     ctor public RttManager.RttCapabilities();
     method public int describeContents();
@@ -20756,6 +20793,7 @@
     field public boolean lcrSupported;
     field public boolean oneSidedRttSupported;
     field public int preambleSupported;
+    field public boolean responderSupported;
     field public deprecated boolean supportedPeerType;
     field public deprecated boolean supportedType;
     field public boolean twoSided11McRttSupported;
@@ -20788,6 +20826,7 @@
     field public int numberBurst;
     field public int preamble;
     field public int requestType;
+    field public boolean secure;
   }
 
   public static class RttManager.RttResult {
@@ -20819,6 +20858,7 @@
     field public deprecated long rtt_sd_ns;
     field public deprecated long rtt_spread_ns;
     field public int rxRate;
+    field public boolean secure;
     field public int status;
     field public int successMeasurementFrameNumber;
     field public long ts;
@@ -20832,22 +20872,6 @@
     field public byte id;
   }
 
-  public class ScanInfo implements android.os.Parcelable {
-    ctor public ScanInfo(android.net.wifi.ScanResult);
-    ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int);
-    method public int describeContents();
-    method public long getBssid();
-    method public byte[] getIconData();
-    method public java.lang.String getIconType();
-    method public java.lang.String getName();
-    method public int getOsuIdentity();
-    method public int getRssi();
-    method public android.net.wifi.ScanResult getScanResult();
-    method public java.lang.String getServiceDescription();
-    method public java.lang.String getSsid();
-    method public void writeToParcel(android.os.Parcel, int);
-  }
-
   public class ScanResult implements android.os.Parcelable {
     method public int describeContents();
     method public boolean is80211mcResponder();
@@ -20994,6 +21018,7 @@
     method public java.lang.String getAltSubjectMatch();
     method public java.lang.String getAnonymousIdentity();
     method public java.security.cert.X509Certificate getCaCertificate();
+    method public java.security.cert.X509Certificate[] getCaCertificates();
     method public java.security.cert.X509Certificate getClientCertificate();
     method public java.lang.String getDomainSuffixMatch();
     method public int getEapMethod();
@@ -21006,6 +21031,7 @@
     method public void setAltSubjectMatch(java.lang.String);
     method public void setAnonymousIdentity(java.lang.String);
     method public void setCaCertificate(java.security.cert.X509Certificate);
+    method public void setCaCertificates(java.security.cert.X509Certificate[]);
     method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
     method public void setDomainSuffixMatch(java.lang.String);
     method public void setEapMethod(int);
@@ -21028,6 +21054,7 @@
     field public static final int SIM = 4; // 0x4
     field public static final int TLS = 1; // 0x1
     field public static final int TTLS = 2; // 0x2
+    field public static final int UNAUTH_TLS = 7; // 0x7
   }
 
   public static final class WifiEnterpriseConfig.Phase2 {
@@ -21073,7 +21100,6 @@
     method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
     method public android.net.DhcpInfo getDhcpInfo();
     method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
-    method public java.util.List<android.net.wifi.ScanInfo> getScanInfos();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
@@ -21093,7 +21119,7 @@
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean saveConfiguration();
-    method public void setOsuSelection(int);
+    method public boolean setMetered(int, boolean);
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
@@ -21196,6 +21222,7 @@
     method public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
     field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
     field public static final int MIN_SCAN_PERIOD_MS = 1000; // 0x3e8
+    field public static final int REASON_DUPLICATE_REQEUST = -5; // 0xfffffffb
     field public static final int REASON_INVALID_LISTENER = -2; // 0xfffffffe
     field public static final int REASON_INVALID_REQUEST = -3; // 0xfffffffd
     field public static final int REASON_NOT_AUTHORIZED = -4; // 0xfffffffc
@@ -32176,6 +32203,7 @@
     method public static boolean hasProperty(int, int);
     method public boolean hasProperty(int);
     method public static java.lang.String propertiesToString(int);
+    field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 4194304; // 0x400000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
     field public static final int CAPABILITY_HOLD = 1; // 0x1
@@ -32326,6 +32354,7 @@
     method public final void setVideoProvider(android.telecom.Connection.VideoProvider);
     method public final void setVideoState(int);
     method public static java.lang.String stateToString(int);
+    field public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 8388608; // 0x800000
     field public static final int CAPABILITY_CAN_PAUSE_VIDEO = 1048576; // 0x100000
     field public static final int CAPABILITY_CAN_UPGRADE_TO_VIDEO = 524288; // 0x80000
     field public static final int CAPABILITY_DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000
@@ -32820,10 +32849,12 @@
 package android.telephony {
 
   public class CarrierConfigManager {
+    method public android.os.PersistableBundle getConfig(int);
     method public android.os.PersistableBundle getConfig();
-    method public android.os.PersistableBundle getConfigForSubId(int);
+    method public deprecated android.os.PersistableBundle getConfigForSubId(int);
     method public static android.os.PersistableBundle getDefaultConfig();
-    method public void notifyConfigChangedForSubId(int);
+    method public void notifyConfigChanged(int);
+    method public deprecated void notifyConfigChangedForSubId(int);
     method public void updateConfigForPhoneId(int, java.lang.String);
     field public static final java.lang.String ACTION_CARRIER_CONFIG_CHANGED = "android.telephony.action.CARRIER_CONFIG_CHANGED";
     field public static final java.lang.String BOOL_ALLOW_EMERGENCY_VIDEO_CALLS = "bool_allow_emergency_video_calls";
@@ -32919,6 +32950,8 @@
 
   public final class CellIdentityGsm implements android.os.Parcelable {
     method public int describeContents();
+    method public int getArfcn();
+    method public int getBsic();
     method public int getCid();
     method public int getLac();
     method public int getMcc();
@@ -32931,6 +32964,7 @@
   public final class CellIdentityLte implements android.os.Parcelable {
     method public int describeContents();
     method public int getCi();
+    method public int getEarfcn();
     method public int getMcc();
     method public int getMnc();
     method public int getPci();
@@ -32946,6 +32980,7 @@
     method public int getMcc();
     method public int getMnc();
     method public int getPsc();
+    method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR;
   }
@@ -33367,10 +33402,15 @@
     method public int getActiveSubscriptionInfoCountMax();
     method public android.telephony.SubscriptionInfo getActiveSubscriptionInfoForSimSlotIndex(int);
     method public java.util.List<android.telephony.SubscriptionInfo> getActiveSubscriptionInfoList();
+    method public static int getDefaultDataSubscriptionId();
+    method public static int getDefaultSmsSubscriptionId();
+    method public static int getDefaultSubscriptionId();
+    method public static int getDefaultVoiceSubscriptionId();
     method public boolean isNetworkRoaming(int);
     method public void removeOnSubscriptionsChangedListener(android.telephony.SubscriptionManager.OnSubscriptionsChangedListener);
     field public static final int DATA_ROAMING_DISABLE = 0; // 0x0
     field public static final int DATA_ROAMING_ENABLE = 1; // 0x1
+    field public static final int INVALID_SUBSCRIPTION_ID = -1; // 0xffffffff
   }
 
   public static class SubscriptionManager.OnSubscriptionsChangedListener {
@@ -33391,6 +33431,7 @@
     method public boolean endCall();
     method public java.util.List<android.telephony.CellInfo> getAllCellInfo();
     method public int getCallState();
+    method public int getCallState(int);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntent(android.content.Intent);
     method public java.util.List<java.lang.String> getCarrierPackageNamesForIntentAndPhone(android.content.Intent, int);
     method public java.lang.String getCdmaMdn();
@@ -33403,42 +33444,65 @@
     method public int getDataActivity();
     method public boolean getDataEnabled();
     method public boolean getDataEnabled(int);
+    method public int getDataNetworkType(int);
     method public int getDataState();
     method public java.lang.String getDeviceId();
     method public java.lang.String getDeviceId(int);
     method public java.lang.String getDeviceSoftwareVersion();
     method public java.lang.String getGroupIdLevel1();
+    method public java.lang.String getGroupIdLevel1(int);
+    method public java.lang.String getLine1AlphaTag(int);
     method public java.lang.String getLine1Number();
+    method public java.lang.String getLine1Number(int);
     method public java.lang.String getMmsUAProfUrl();
     method public java.lang.String getMmsUserAgent();
     method public deprecated java.util.List<android.telephony.NeighboringCellInfo> getNeighboringCellInfo();
     method public java.lang.String getNetworkCountryIso();
+    method public java.lang.String getNetworkCountryIso(int);
     method public java.lang.String getNetworkOperator();
+    method public java.lang.String getNetworkOperator(int);
     method public java.lang.String getNetworkOperatorName();
+    method public java.lang.String getNetworkOperatorName(int);
     method public int getNetworkType();
+    method public int getNetworkType(int);
     method public int getPhoneCount();
     method public int getPhoneType();
     method public java.lang.String getSimCountryIso();
+    method public java.lang.String getSimCountryIso(int);
     method public java.lang.String getSimOperator();
+    method public java.lang.String getSimOperator(int);
     method public java.lang.String getSimOperatorName();
+    method public java.lang.String getSimOperatorName(int);
     method public java.lang.String getSimSerialNumber();
+    method public java.lang.String getSimSerialNumber(int);
     method public int getSimState();
     method public java.lang.String getSubscriberId();
+    method public java.lang.String getSubscriberId(int);
     method public java.lang.String getVoiceMailAlphaTag();
+    method public java.lang.String getVoiceMailAlphaTag(int);
     method public java.lang.String getVoiceMailNumber();
+    method public java.lang.String getVoiceMailNumber(int);
+    method public int getVoiceNetworkType(int);
     method public boolean handlePinMmi(java.lang.String);
     method public boolean handlePinMmiForSubscriber(int, java.lang.String);
     method public boolean hasCarrierPrivileges();
+    method public boolean hasCarrierPrivileges(int);
     method public boolean hasIccCard();
     method public boolean iccCloseLogicalChannel(int);
+    method public boolean iccCloseLogicalChannel(int, int);
     method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String);
+    method public byte[] iccExchangeSimIO(int, int, int, int, int, int, java.lang.String);
     method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String);
+    method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(int, java.lang.String);
     method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, int, java.lang.String);
     method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+    method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, int, java.lang.String);
     method public boolean isDataConnectivityPossible();
     method public boolean isHearingAidCompatibilitySupported();
     method public boolean isIdle();
     method public boolean isNetworkRoaming();
+    method public boolean isNetworkRoaming(int);
     method public boolean isOffhook();
     method public boolean isRadioOn();
     method public boolean isRinging();
@@ -33451,14 +33515,19 @@
     method public void listen(android.telephony.PhoneStateListener, int);
     method public boolean needsOtaServiceProvisioning();
     method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+    method public java.lang.String sendEnvelopeWithStatus(int, java.lang.String);
     method public void setDataEnabled(boolean);
     method public void setDataEnabled(int, boolean);
     method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
+    method public boolean setLine1NumberForDisplay(int, java.lang.String, java.lang.String);
     method public boolean setOperatorBrandOverride(java.lang.String);
+    method public boolean setOperatorBrandOverride(int, java.lang.String);
     method public boolean setPreferredNetworkTypeToGlobal();
+    method public boolean setPreferredNetworkTypeToGlobal(int);
     method public boolean setRadio(boolean);
     method public boolean setRadioPower(boolean);
     method public boolean setVoiceMailNumber(java.lang.String, java.lang.String);
+    method public boolean setVoiceMailNumber(int, java.lang.String, java.lang.String);
     method public void silenceRinger();
     method public boolean supplyPin(java.lang.String);
     method public int[] supplyPinReportResult(java.lang.String);
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 3eb1b91..687fe4c 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -82,8 +82,6 @@
 import android.net.wifi.nan.WifiNanManager;
 import android.net.wifi.p2p.IWifiP2pManager;
 import android.net.wifi.p2p.WifiP2pManager;
-import android.net.wifi.passpoint.IWifiPasspointManager;
-import android.net.wifi.passpoint.WifiPasspointManager;
 import android.nfc.NfcManager;
 import android.os.BatteryManager;
 import android.os.DropBoxManager;
@@ -483,15 +481,6 @@
                 return new WifiManager(ctx.getOuterContext(), service);
             }});
 
-        registerService(Context.WIFI_PASSPOINT_SERVICE, WifiPasspointManager.class,
-                new CachedServiceFetcher<WifiPasspointManager>() {
-            @Override
-            public WifiPasspointManager createService(ContextImpl ctx) {
-                IBinder b = ServiceManager.getService(Context.WIFI_PASSPOINT_SERVICE);
-                IWifiPasspointManager service = IWifiPasspointManager.Stub.asInterface(b);
-                return new WifiPasspointManager(ctx.getOuterContext(), service);
-            }});
-
         registerService(Context.WIFI_P2P_SERVICE, WifiP2pManager.class,
                 new StaticServiceFetcher<WifiP2pManager>() {
             @Override
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 43d4ff2..4d1705b 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2461,7 +2461,6 @@
             //@hide: NETWORK_POLICY_SERVICE,
             WIFI_SERVICE,
             WIFI_NAN_SERVICE,
-            WIFI_PASSPOINT_SERVICE,
             WIFI_P2P_SERVICE,
             WIFI_SCANNING_SERVICE,
             //@hide: WIFI_RTT_SERVICE,
@@ -2903,17 +2902,6 @@
 
     /**
      * Use with {@link #getSystemService} to retrieve a {@link
-     * android.net.wifi.passpoint.WifiPasspointManager} for handling management of
-     * Wi-Fi passpoint access.
-     *
-     * @see #getSystemService
-     * @see android.net.wifi.passpoint.WifiPasspointManager
-     * @hide
-     */
-    public static final String WIFI_PASSPOINT_SERVICE = "wifipasspoint";
-
-    /**
-     * Use with {@link #getSystemService} to retrieve a {@link
      * android.net.wifi.p2p.WifiP2pManager} for handling management of
      * Wi-Fi peer-to-peer connections.
      *
diff --git a/core/java/android/net/BaseDhcpStateMachine.java b/core/java/android/net/BaseDhcpStateMachine.java
deleted file mode 100644
index a25847d..0000000
--- a/core/java/android/net/BaseDhcpStateMachine.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import com.android.internal.util.StateMachine;
-
-/**
- * Interface that must be implemented by DHCP state machines.
- *
- * This is an abstract class instead of a Java interface so that callers can just declare an object
- * of this type and be able to call all the methods defined by either StateMachine or this class.
- *
- * @hide
- */
-public abstract class BaseDhcpStateMachine extends StateMachine {
-    protected BaseDhcpStateMachine(String tag) {
-        super(tag);
-    }
-    public abstract void registerForPreDhcpNotification();
-    public abstract void doQuit();
-}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ad9058f..8e91d2e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1460,7 +1460,7 @@
         if (b != null) {
             try {
                 ITelephony it = ITelephony.Stub.asInterface(b);
-                int subId = SubscriptionManager.getDefaultDataSubId();
+                int subId = SubscriptionManager.getDefaultDataSubscriptionId();
                 Log.d("ConnectivityManager", "getMobileDataEnabled()+ subId=" + subId);
                 boolean retVal = it.getDataEnabled(subId);
                 Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl b/core/java/android/net/ConnectivityMetricsEvent.aidl
similarity index 90%
copy from wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
copy to core/java/android/net/ConnectivityMetricsEvent.aidl
index 44849bc..da17561 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
+++ b/core/java/android/net/ConnectivityMetricsEvent.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net;
 
-parcelable SubscribeSettings;
+parcelable ConnectivityMetricsEvent;
diff --git a/core/java/android/net/ConnectivityMetricsEvent.java b/core/java/android/net/ConnectivityMetricsEvent.java
new file mode 100644
index 0000000..d040a85
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsEvent.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+@SystemApi
+public class ConnectivityMetricsEvent implements Parcelable {
+
+    /**  The time when this event was collected, as returned by System.currentTimeMillis(). */
+    final public long timestamp;
+
+    /** The subsystem that generated the event. One of the COMPONENT_TAG_xxx constants. */
+    final public int componentTag;
+
+    /** The subsystem-specific event ID. */
+    final public int eventTag;
+
+    /** Opaque event-specific data. */
+    final public Parcelable data;
+
+    public ConnectivityMetricsEvent(long timestamp, int componentTag,
+                                    int eventTag, Parcelable data) {
+        this.timestamp = timestamp;
+        this.componentTag = componentTag;
+        this.eventTag = eventTag;
+        this.data = data;
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Parcelable.Creator<ConnectivityMetricsEvent> CREATOR
+            = new Parcelable.Creator<ConnectivityMetricsEvent> (){
+        public ConnectivityMetricsEvent createFromParcel(Parcel source) {
+            final long timestamp = source.readLong();
+            final int componentTag = source.readInt();
+            final int eventTag = source.readInt();
+            final Parcelable data = source.readParcelable(null);
+            return new ConnectivityMetricsEvent(timestamp, componentTag,
+                    eventTag, data);
+        }
+
+        public ConnectivityMetricsEvent[] newArray(int size) {
+            return new ConnectivityMetricsEvent[size];
+        }
+    };
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(timestamp);
+        dest.writeInt(componentTag);
+        dest.writeInt(eventTag);
+        dest.writeParcelable(data, 0);
+    }
+
+    public String toString() {
+        return String.format("ConnectivityMetricsEvent(%d, %d, %d)", timestamp,
+                componentTag, eventTag);
+    }
+}
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
new file mode 100644
index 0000000..3ef8050
--- /dev/null
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/** {@hide} */
+public class ConnectivityMetricsLogger {
+    private static String TAG = "ConnectivityMetricsLogger";
+    private static final boolean DBG = true;
+
+    public static final String CONNECTIVITY_METRICS_LOGGER_SERVICE = "connectivity_metrics_logger";
+
+    // Component Tags
+    public static final int COMPONENT_TAG_CONNECTIVITY = 1;
+    public static final int COMPONENT_TAG_BLUETOOTH = 2;
+    public static final int COMPONENT_TAG_WIFI = 3;
+    public static final int COMPONENT_TAG_TELECOM = 4;
+    public static final int COMPONENT_TAG_TELEPHONY = 5;
+
+    private IConnectivityMetricsLogger mService;
+
+    public ConnectivityMetricsLogger() {
+        mService = IConnectivityMetricsLogger.Stub.asInterface(ServiceManager.getService(
+                CONNECTIVITY_METRICS_LOGGER_SERVICE));
+    }
+
+    public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
+        if (mService == null) {
+            if (DBG) {
+                Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
+            }
+        } else {
+            try {
+                mService.logEvent(new ConnectivityMetricsEvent(timestamp, componentTag, eventTag, data));
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error logging event " + e.getMessage());
+            }
+        }
+    }
+}
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
deleted file mode 100644
index 73ef78e..0000000
--- a/core/java/android/net/DhcpStateMachine.java
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net;
-
-import com.android.internal.util.Protocol;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
-import android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.DhcpResults;
-import android.net.NetworkUtils;
-import android.os.Message;
-import android.os.PowerManager;
-import android.os.SystemClock;
-import android.util.Log;
-
-/**
- * StateMachine that interacts with the native DHCP client and can talk to
- * a controller that also needs to be a StateMachine
- *
- * The DhcpStateMachine provides the following features:
- * - Wakeup and renewal using the native DHCP client  (which will not renew
- *   on its own when the device is in suspend state and this can lead to device
- *   holding IP address beyond expiry)
- * - A notification right before DHCP request or renewal is started. This
- *   can be used for any additional setup before DHCP. For example, wifi sets
- *   BT-Wifi coex settings right before DHCP is initiated
- *
- * @hide
- */
-public class DhcpStateMachine extends BaseDhcpStateMachine {
-
-    private static final String TAG = "DhcpStateMachine";
-    private static final boolean DBG = false;
-
-
-    /* A StateMachine that controls the DhcpStateMachine */
-    private StateMachine mController;
-
-    private Context mContext;
-    private BroadcastReceiver mBroadcastReceiver;
-    private AlarmManager mAlarmManager;
-    private PendingIntent mDhcpRenewalIntent;
-    private PowerManager.WakeLock mDhcpRenewWakeLock;
-    private static final String WAKELOCK_TAG = "DHCP";
-
-    //Remember DHCP configuration from first request
-    private DhcpResults mDhcpResults;
-
-    private static final int DHCP_RENEW = 0;
-    private static final String ACTION_DHCP_RENEW = "android.net.wifi.DHCP_RENEW";
-
-    //Used for sanity check on setting up renewal
-    private static final int MIN_RENEWAL_TIME_SECS = 5 * 60;  // 5 minutes
-
-    private final String mInterfaceName;
-    private boolean mRegisteredForPreDhcpNotification = false;
-
-    private static final int BASE = Protocol.BASE_DHCP;
-
-    /* Commands from controller to start/stop DHCP */
-    public static final int CMD_START_DHCP                  = BASE + 1;
-    public static final int CMD_STOP_DHCP                   = BASE + 2;
-    public static final int CMD_RENEW_DHCP                  = BASE + 3;
-
-    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
-    public static final int CMD_PRE_DHCP_ACTION             = BASE + 4;
-    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
-     * success/failure */
-    public static final int CMD_POST_DHCP_ACTION            = BASE + 5;
-    /* Notification from DHCP state machine before quitting */
-    public static final int CMD_ON_QUIT                     = BASE + 6;
-
-    /* Command from controller to indicate DHCP discovery/renewal can continue
-     * after pre DHCP action is complete */
-    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = BASE + 7;
-
-    /* Command from ourselves to see if DHCP results are available */
-    private static final int CMD_GET_DHCP_RESULTS           = BASE + 8;
-
-    /* Message.arg1 arguments to CMD_POST_DHCP notification */
-    public static final int DHCP_SUCCESS = 1;
-    public static final int DHCP_FAILURE = 2;
-
-    private State mDefaultState = new DefaultState();
-    private State mStoppedState = new StoppedState();
-    private State mWaitBeforeStartState = new WaitBeforeStartState();
-    private State mRunningState = new RunningState();
-    private State mWaitBeforeRenewalState = new WaitBeforeRenewalState();
-    private State mPollingState = new PollingState();
-
-    private DhcpStateMachine(Context context, StateMachine controller, String intf) {
-        super(TAG);
-
-        mContext = context;
-        mController = controller;
-        mInterfaceName = intf;
-
-        mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE);
-        Intent dhcpRenewalIntent = new Intent(ACTION_DHCP_RENEW, null);
-        mDhcpRenewalIntent = PendingIntent.getBroadcast(mContext, DHCP_RENEW, dhcpRenewalIntent, 0);
-
-        PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        mDhcpRenewWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
-        mDhcpRenewWakeLock.setReferenceCounted(false);
-
-        mBroadcastReceiver = new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                //DHCP renew
-                if (DBG) Log.d(TAG, "Sending a DHCP renewal " + this);
-                //Lock released after 40s in worst case scenario
-                mDhcpRenewWakeLock.acquire(40000);
-                sendMessage(CMD_RENEW_DHCP);
-            }
-        };
-        mContext.registerReceiver(mBroadcastReceiver, new IntentFilter(ACTION_DHCP_RENEW));
-
-        addState(mDefaultState);
-            addState(mStoppedState, mDefaultState);
-            addState(mWaitBeforeStartState, mDefaultState);
-            addState(mPollingState, mDefaultState);
-            addState(mRunningState, mDefaultState);
-            addState(mWaitBeforeRenewalState, mDefaultState);
-
-        setInitialState(mStoppedState);
-    }
-
-    public static DhcpStateMachine makeDhcpStateMachine(Context context, StateMachine controller,
-            String intf) {
-        DhcpStateMachine dsm = new DhcpStateMachine(context, controller, intf);
-        dsm.start();
-        return dsm;
-    }
-
-    /**
-     * This sends a notification right before DHCP request/renewal so that the
-     * controller can do certain actions before DHCP packets are sent out.
-     * When the controller is ready, it sends a CMD_PRE_DHCP_ACTION_COMPLETE message
-     * to indicate DHCP can continue
-     *
-     * This is used by Wifi at this time for the purpose of doing BT-Wifi coex
-     * handling during Dhcp
-     */
-    @Override
-    public void registerForPreDhcpNotification() {
-        mRegisteredForPreDhcpNotification = true;
-    }
-
-    /**
-     * Quit the DhcpStateMachine.
-     *
-     * @hide
-     */
-    @Override
-    public void doQuit() {
-        quit();
-    }
-
-    protected void onQuitting() {
-        mController.sendMessage(CMD_ON_QUIT);
-    }
-
-    class DefaultState extends State {
-        @Override
-        public void exit() {
-            mContext.unregisterReceiver(mBroadcastReceiver);
-        }
-        @Override
-        public boolean processMessage(Message message) {
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_RENEW_DHCP:
-                    Log.e(TAG, "Error! Failed to handle a DHCP renewal on " + mInterfaceName);
-                    mDhcpRenewWakeLock.release();
-                    break;
-                default:
-                    Log.e(TAG, "Error! unhandled message  " + message);
-                    break;
-            }
-            return HANDLED;
-        }
-    }
-
-
-    class StoppedState extends State {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-            if (!NetworkUtils.stopDhcp(mInterfaceName)) {
-                Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName);
-            }
-            mDhcpResults = null;
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_START_DHCP:
-                    if (mRegisteredForPreDhcpNotification) {
-                        /* Notify controller before starting DHCP */
-                        mController.sendMessage(CMD_PRE_DHCP_ACTION);
-                        transitionTo(mWaitBeforeStartState);
-                    } else {
-                        if (runDhcpStart()) {
-                            transitionTo(mRunningState);
-                        }
-                    }
-                    break;
-                case CMD_STOP_DHCP:
-                    //ignore
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-                    break;
-            }
-            return retValue;
-        }
-    }
-
-    class WaitBeforeStartState extends State {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_PRE_DHCP_ACTION_COMPLETE:
-                    if (runDhcpStart()) {
-                        transitionTo(mRunningState);
-                    } else {
-                        transitionTo(mPollingState);
-                    }
-                    break;
-                case CMD_STOP_DHCP:
-                    transitionTo(mStoppedState);
-                    break;
-                case CMD_START_DHCP:
-                    //ignore
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-                    break;
-            }
-            return retValue;
-        }
-    }
-
-    class PollingState extends State {
-        private static final long MAX_DELAY_SECONDS = 32;
-        private long delaySeconds;
-
-        private void scheduleNextResultsCheck() {
-            sendMessageDelayed(obtainMessage(CMD_GET_DHCP_RESULTS), delaySeconds * 1000);
-            delaySeconds *= 2;
-            if (delaySeconds > MAX_DELAY_SECONDS) {
-                delaySeconds = MAX_DELAY_SECONDS;
-            }
-        }
-
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, "Entering " + getName() + "\n");
-            delaySeconds = 1;
-            scheduleNextResultsCheck();
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_GET_DHCP_RESULTS:
-                    if (DBG) Log.d(TAG, "GET_DHCP_RESULTS on " + mInterfaceName);
-                    if (dhcpSucceeded()) {
-                        transitionTo(mRunningState);
-                    } else {
-                        scheduleNextResultsCheck();
-                    }
-                    break;
-                case CMD_STOP_DHCP:
-                    transitionTo(mStoppedState);
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-                    break;
-            }
-            return retValue;
-        }
-
-        @Override
-        public void exit() {
-            if (DBG) Log.d(TAG, "Exiting " + getName() + "\n");
-            removeMessages(CMD_GET_DHCP_RESULTS);
-        }
-    }
-
-    class RunningState extends State {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_STOP_DHCP:
-                    mAlarmManager.cancel(mDhcpRenewalIntent);
-                    transitionTo(mStoppedState);
-                    break;
-                case CMD_RENEW_DHCP:
-                    if (mRegisteredForPreDhcpNotification) {
-                        /* Notify controller before starting DHCP */
-                        mController.sendMessage(CMD_PRE_DHCP_ACTION);
-                        transitionTo(mWaitBeforeRenewalState);
-                        //mDhcpRenewWakeLock is released in WaitBeforeRenewalState
-                    } else {
-                        if (!runDhcpRenew()) {
-                            transitionTo(mStoppedState);
-                        }
-                        mDhcpRenewWakeLock.release();
-                    }
-                    break;
-                case CMD_START_DHCP:
-                    //ignore
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-            }
-            return retValue;
-        }
-    }
-
-    class WaitBeforeRenewalState extends State {
-        @Override
-        public void enter() {
-            if (DBG) Log.d(TAG, getName() + "\n");
-        }
-
-        @Override
-        public boolean processMessage(Message message) {
-            boolean retValue = HANDLED;
-            if (DBG) Log.d(TAG, getName() + message.toString() + "\n");
-            switch (message.what) {
-                case CMD_STOP_DHCP:
-                    mAlarmManager.cancel(mDhcpRenewalIntent);
-                    transitionTo(mStoppedState);
-                    break;
-                case CMD_PRE_DHCP_ACTION_COMPLETE:
-                    if (runDhcpRenew()) {
-                       transitionTo(mRunningState);
-                    } else {
-                       transitionTo(mStoppedState);
-                    }
-                    break;
-                case CMD_START_DHCP:
-                    //ignore
-                    break;
-                default:
-                    retValue = NOT_HANDLED;
-                    break;
-            }
-            return retValue;
-        }
-        @Override
-        public void exit() {
-            mDhcpRenewWakeLock.release();
-        }
-    }
-
-    private boolean dhcpSucceeded() {
-        DhcpResults dhcpResults = new DhcpResults();
-        if (!NetworkUtils.getDhcpResults(mInterfaceName, dhcpResults)) {
-            return false;
-        }
-
-        if (DBG) Log.d(TAG, "DHCP results found for " + mInterfaceName);
-        long leaseDuration = dhcpResults.leaseDuration; //int to long conversion
-
-        //Sanity check for renewal
-        if (leaseDuration >= 0) {
-            //TODO: would be good to notify the user that his network configuration is
-            //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS
-            if (leaseDuration < MIN_RENEWAL_TIME_SECS) {
-                leaseDuration = MIN_RENEWAL_TIME_SECS;
-            }
-            //Do it a bit earlier than half the lease duration time
-            //to beat the native DHCP client and avoid extra packets
-            //48% for one hour lease time = 29 minutes
-            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
-                    SystemClock.elapsedRealtime() +
-                    leaseDuration * 480, //in milliseconds
-                    mDhcpRenewalIntent);
-        } else {
-            //infinite lease time, no renewal needed
-        }
-
-        // Fill in any missing fields in dhcpResults from the previous results.
-        // If mDhcpResults is null (i.e. this is the first server response),
-        // this is a noop.
-        dhcpResults.updateFromDhcpRequest(mDhcpResults);
-        mDhcpResults = dhcpResults;
-        mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults)
-            .sendToTarget();
-        return true;
-    }
-
-    private boolean runDhcpStart() {
-        /* Stop any existing DHCP daemon before starting new */
-        NetworkUtils.stopDhcp(mInterfaceName);
-        mDhcpResults = null;
-
-        if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName);
-        if (!NetworkUtils.startDhcp(mInterfaceName) || !dhcpSucceeded()) {
-            Log.e(TAG, "DHCP request failed on " + mInterfaceName + ": " +
-                    NetworkUtils.getDhcpError());
-            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
-                    .sendToTarget();
-            return false;
-        }
-        return true;
-    }
-
-    private boolean runDhcpRenew() {
-        if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName);
-        if (!NetworkUtils.startDhcpRenew(mInterfaceName) || !dhcpSucceeded()) {
-            Log.e(TAG, "DHCP renew failed on " + mInterfaceName + ": " +
-                    NetworkUtils.getDhcpError());
-            mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0)
-                    .sendToTarget();
-            return false;
-        }
-        return true;
-    }
-}
diff --git a/core/java/android/net/IConnectivityMetricsLogger.aidl b/core/java/android/net/IConnectivityMetricsLogger.aidl
new file mode 100644
index 0000000..2778671
--- /dev/null
+++ b/core/java/android/net/IConnectivityMetricsLogger.aidl
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.net.ConnectivityMetricsEvent;
+import android.net.IConnectivityMetricsLoggerSubscriber;
+
+/** {@hide} */
+interface IConnectivityMetricsLogger {
+
+    void logEvent(in ConnectivityMetricsEvent event);
+    void logEvents(in ConnectivityMetricsEvent[] events);
+
+    boolean subscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
+    void unsubscribe(in IConnectivityMetricsLoggerSubscriber subscriber);
+}
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl b/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
similarity index 75%
copy from wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
copy to core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
index 44849bc..a2c62cd 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
+++ b/core/java/android/net/IConnectivityMetricsLoggerSubscriber.aidl
@@ -14,6 +14,12 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package android.net;
 
-parcelable SubscribeSettings;
+import android.net.ConnectivityMetricsEvent;
+
+/** {@hide} */
+oneway interface IConnectivityMetricsLoggerSubscriber {
+
+    void onEvents(in ConnectivityMetricsEvent[] events);
+}
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 3bd12c0..e27c0fb 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -197,6 +197,19 @@
             (1 << NET_CAPABILITY_CAPTIVE_PORTAL);
 
     /**
+     * Network specifier for factories which want to match any network specifier
+     * (NS) in a request. Behavior:
+     * <li>Empty NS in request matches any network factory NS</li>
+     * <li>Empty NS in the network factory NS only matches a request with an
+     * empty NS</li>
+     * <li>"*" (this constant) NS in the network factory matches requests with
+     * any NS</li>
+     *
+     * @hide
+     */
+    public static final String MATCH_ALL_REQUESTS_NETWORK_SPECIFIER = "*";
+
+    /**
      * Network capabilities that are not allowed in NetworkRequests. This exists because the
      * NetworkFactory / NetworkAgent model does not deal well with the situation where a
      * capability's presence cannot be known in advance. If such a capability is requested, then we
@@ -596,7 +609,8 @@
     }
     private boolean satisfiedBySpecifier(NetworkCapabilities nc) {
         return (TextUtils.isEmpty(mNetworkSpecifier) ||
-                mNetworkSpecifier.equals(nc.mNetworkSpecifier));
+                mNetworkSpecifier.equals(nc.mNetworkSpecifier) ||
+                MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(nc.mNetworkSpecifier));
     }
     private boolean equalsSpecifier(NetworkCapabilities nc) {
         if (TextUtils.isEmpty(mNetworkSpecifier)) {
diff --git a/core/java/android/net/NetworkPolicy.java b/core/java/android/net/NetworkPolicy.java
index e88bc26..9870e7b 100644
--- a/core/java/android/net/NetworkPolicy.java
+++ b/core/java/android/net/NetworkPolicy.java
@@ -20,7 +20,12 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.BackupUtils;
 
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
 import java.util.Objects;
 
 /**
@@ -30,6 +35,11 @@
  * @hide
  */
 public class NetworkPolicy implements Parcelable, Comparable<NetworkPolicy> {
+    /**
+     * Current Version of the Backup Serializer.
+     */
+    private static final int BACKUP_VERSION = 1;
+
     public static final int CYCLE_NONE = -1;
     public static final long WARNING_DISABLED = -1;
     public static final long LIMIT_DISABLED = -1;
@@ -191,4 +201,41 @@
             return new NetworkPolicy[size];
         }
     };
+
+    public byte[] getBytesForBackup() throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+
+        out.writeInt(BACKUP_VERSION);
+        out.write(template.getBytesForBackup());
+        out.writeInt(cycleDay);
+        BackupUtils.writeString(out, cycleTimezone);
+        out.writeLong(warningBytes);
+        out.writeLong(limitBytes);
+        out.writeLong(lastWarningSnooze);
+        out.writeLong(lastLimitSnooze);
+        out.writeInt(metered ? 1 : 0);
+        out.writeInt(inferred ? 1 : 0);
+        return baos.toByteArray();
+    }
+
+    public static NetworkPolicy getNetworkPolicyFromBackup(DataInputStream in) throws IOException,
+            BackupUtils.BadVersionException {
+        int version = in.readInt();
+        if (version < 1 || version > BACKUP_VERSION) {
+            throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+        }
+
+        NetworkTemplate template = NetworkTemplate.getNetworkTemplateFromBackup(in);
+        int cycleDay = in.readInt();
+        String cycleTimeZone = BackupUtils.readString(in);
+        long warningBytes = in.readLong();
+        long limitBytes = in.readLong();
+        long lastWarningSnooze = in.readLong();
+        long lastLimitSnooze = in.readLong();
+        boolean metered = in.readInt() == 1;
+        boolean inferred = in.readInt() == 1;
+        return new NetworkPolicy(template, cycleDay, cycleTimeZone, warningBytes, limitBytes,
+                lastWarningSnooze, lastLimitSnooze, metered, inferred);
+    }
 }
diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java
index 7da4818..f1edcbe 100644
--- a/core/java/android/net/NetworkRequest.java
+++ b/core/java/android/net/NetworkRequest.java
@@ -188,6 +188,10 @@
          *                         networks.
          */
         public Builder setNetworkSpecifier(String networkSpecifier) {
+            if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER.equals(networkSpecifier)) {
+                throw new IllegalArgumentException("Invalid network specifier - must not be '"
+                        + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'");
+            }
             mNetworkCapabilities.setNetworkSpecifier(networkSpecifier);
             return this;
         }
diff --git a/core/java/android/net/NetworkTemplate.java b/core/java/android/net/NetworkTemplate.java
index b7a411e..5761d66 100644
--- a/core/java/android/net/NetworkTemplate.java
+++ b/core/java/android/net/NetworkTemplate.java
@@ -28,15 +28,21 @@
 import static android.telephony.TelephonyManager.NETWORK_CLASS_4_G;
 import static android.telephony.TelephonyManager.NETWORK_CLASS_UNKNOWN;
 import static android.telephony.TelephonyManager.getNetworkClass;
+
 import static com.android.internal.util.ArrayUtils.contains;
 
 import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.BackupUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.Objects;
 
@@ -47,6 +53,10 @@
  * @hide
  */
 public class NetworkTemplate implements Parcelable {
+    /**
+     * Current Version of the Backup Serializer.
+     */
+    private static final int BACKUP_VERSION = 1;
 
     public static final int MATCH_MOBILE_ALL = 1;
     @Deprecated
@@ -443,4 +453,31 @@
             return new NetworkTemplate[size];
         }
     };
+
+    public byte[] getBytesForBackup() throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+
+        out.writeInt(BACKUP_VERSION);
+
+        out.writeInt(mMatchRule);
+        BackupUtils.writeString(out, mSubscriberId);
+        BackupUtils.writeString(out, mNetworkId);
+
+        return baos.toByteArray();
+    }
+
+    public static NetworkTemplate getNetworkTemplateFromBackup(DataInputStream in)
+            throws IOException, BackupUtils.BadVersionException {
+        int version = in.readInt();
+        if (version < 1 || version > BACKUP_VERSION) {
+            throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+        }
+
+        int matchRule = in.readInt();
+        String subscriberId = BackupUtils.readString(in);
+        String networkId = BackupUtils.readString(in);
+
+        return new NetworkTemplate(matchRule, subscriberId, networkId);
+    }
 }
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 4487cab..c6d919f 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -57,90 +57,6 @@
     public native static int resetConnections(String interfaceName, int mask);
 
     /**
-     * Start the DHCP client daemon, in order to have it request addresses
-     * for the named interface.  This returns {@code true} if the DHCPv4 daemon
-     * starts, {@code false} otherwise.  This call blocks until such time as a
-     * result is available or the default discovery timeout has been reached.
-     * Callers should check {@link #getDhcpResults} to determine whether DHCP
-     * succeeded or failed, and if it succeeded, to fetch the {@link DhcpResults}.
-     * @param interfaceName the name of the interface to configure
-     * @return {@code true} for success, {@code false} for failure
-     */
-    public native static boolean startDhcp(String interfaceName);
-
-    /**
-     * Initiate renewal on the DHCP client daemon for the named interface.  This
-     * returns {@code true} if the DHCPv4 daemon has been notified, {@code false}
-     * otherwise.  This call blocks until such time as a result is available or
-     * the default renew timeout has been reached.  Callers should check
-     * {@link #getDhcpResults} to determine whether DHCP succeeded or failed,
-     * and if it succeeded, to fetch the {@link DhcpResults}.
-     * @param interfaceName the name of the interface to configure
-     * @return {@code true} for success, {@code false} for failure
-     */
-    public native static boolean startDhcpRenew(String interfaceName);
-
-    /**
-     * Start the DHCP client daemon, in order to have it request addresses
-     * for the named interface, and then configure the interface with those
-     * addresses. This call blocks until it obtains a result (either success
-     * or failure) from the daemon.
-     * @param interfaceName the name of the interface to configure
-     * @param dhcpResults if the request succeeds, this object is filled in with
-     * the IP address information.
-     * @return {@code true} for success, {@code false} for failure
-     */
-    public static boolean runDhcp(String interfaceName, DhcpResults dhcpResults) {
-        return startDhcp(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
-    }
-
-    /**
-     * Initiate renewal on the DHCP client daemon. This call blocks until it obtains
-     * a result (either success or failure) from the daemon.
-     * @param interfaceName the name of the interface to configure
-     * @param dhcpResults if the request succeeds, this object is filled in with
-     * the IP address information.
-     * @return {@code true} for success, {@code false} for failure
-     */
-    public static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults) {
-        return startDhcpRenew(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
-    }
-
-    /**
-     * Fetch results from the DHCP client daemon. This call returns {@code true} if
-     * if there are results available to be read, {@code false} otherwise.
-     * @param interfaceName the name of the interface to configure
-     * @param dhcpResults if the request succeeds, this object is filled in with
-     * the IP address information.
-     * @return {@code true} for success, {@code false} for failure
-     */
-    public native static boolean getDhcpResults(String interfaceName, DhcpResults dhcpResults);
-
-    /**
-     * Shut down the DHCP client daemon.
-     * @param interfaceName the name of the interface for which the daemon
-     * should be stopped
-     * @return {@code true} for success, {@code false} for failure
-     */
-    public native static boolean stopDhcp(String interfaceName);
-
-    /**
-     * Release the current DHCP lease.
-     * @param interfaceName the name of the interface for which the lease should
-     * be released
-     * @return {@code true} for success, {@code false} for failure
-     */
-    public native static boolean releaseDhcpLease(String interfaceName);
-
-    /**
-     * Return the last DHCP-related error message that was recorded.
-     * <p/>NOTE: This string is not localized, but currently it is only
-     * used in logging.
-     * @return the most recent error message, if any
-     */
-    public native static String getDhcpError();
-
-    /**
      * Attaches a socket filter that accepts DHCP packets to the given socket.
      */
     public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
diff --git a/core/java/android/util/BackupUtils.java b/core/java/android/util/BackupUtils.java
new file mode 100644
index 0000000..474ceda
--- /dev/null
+++ b/core/java/android/util/BackupUtils.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+
+/**
+ * Utility methods for Backup/Restore
+ * @hide
+ */
+public class BackupUtils {
+
+    public static final int NULL = 0;
+    public static final int NOT_NULL = 1;
+
+    /**
+     * Thrown when there is a backup version mismatch
+     * between the data received and what the system can handle
+     */
+    public static class BadVersionException extends Exception {
+        public BadVersionException(String message) {
+            super(message);
+        }
+    }
+
+    public static String readString(DataInputStream in) throws IOException {
+        return (in.readByte() == NOT_NULL) ? in.readUTF() : null;
+    }
+
+    public static void writeString(DataOutputStream out, String val) throws IOException {
+        if (val != null) {
+            out.writeByte(NOT_NULL);
+            out.writeUTF(val);
+        } else {
+            out.writeByte(NULL);
+        }
+    }
+}
\ No newline at end of file
diff --git a/core/java/com/android/internal/util/MessageUtils.java b/core/java/com/android/internal/util/MessageUtils.java
new file mode 100644
index 0000000..184245e
--- /dev/null
+++ b/core/java/com/android/internal/util/MessageUtils.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.os.Message;
+import android.util.Log;
+import android.util.SparseArray;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
+/**
+ * Static utility class for dealing with {@link Message} objects.
+ */
+public class MessageUtils {
+
+    private static final String TAG = MessageUtils.class.getSimpleName();
+    private static final boolean DBG = false;
+
+    /** Thrown when two different constants have the same value. */
+    public static class DuplicateConstantError extends Error {
+        private DuplicateConstantError() {}
+        public DuplicateConstantError(String name1, String name2, int value) {
+            super(String.format("Duplicate constant value: both %s and %s = %d",
+                name1, name2, value));
+        }
+    }
+
+    /**
+     * Finds the names of integer constants. Searches the specified {@code classes}, looking for
+     * accessible static integer fields whose names begin with one of the specified {@prefixes}.
+     *
+     * @param classes the classes to examine.
+     * @prefixes only consider fields names starting with one of these prefixes.
+     * @return a {@link SparseArray} mapping integer constants to their names.
+     */
+    public static SparseArray<String> findMessageNames(Class[] classes, String[] prefixes) {
+        SparseArray<String> messageNames = new SparseArray<>();
+        for (Class c : classes) {
+            String className = c.getName();
+            if (DBG) Log.d(TAG, "Examining class " + className);
+
+            Field[] fields;
+            try {
+                fields = c.getDeclaredFields();
+            } catch (SecurityException e) {
+                Log.e(TAG, "Can't list fields of class " + className);
+                continue;
+            }
+
+            for (Field field : fields) {
+                int modifiers = field.getModifiers();
+                if (!Modifier.isStatic(modifiers) | !Modifier.isFinal(modifiers)) {
+                    continue;
+                }
+
+                String name = field.getName();
+                for (String prefix : prefixes) {
+                    // Does this look like a constant?
+                    if (!name.startsWith(prefix)) {
+                        continue;
+                    }
+
+                    try {
+                        // TODO: can we have the caller try to access the field instead, so we don't
+                        // expose constants it does not have access to?
+                        field.setAccessible(true);
+
+                        // Fetch the constant's value.
+                        int value;
+                        try {
+                            value = field.getInt(null);
+                        } catch (IllegalArgumentException | ExceptionInInitializerError e) {
+                            // The field is not an integer (or short or byte), or c's static
+                            // initializer failed and we have no idea what its value is.
+                            // Either way, give up on this field.
+                            break;
+                        }
+
+                        // Check for duplicate values.
+                        String previousName = messageNames.get(value);
+                        if (previousName != null && !previousName.equals(name)) {
+                            throw new DuplicateConstantError(name, previousName, value);
+                        }
+
+                        messageNames.put(value, name);
+                        if (DBG) {
+                            Log.d(TAG, String.format("Found constant: %s.%s = %d",
+                                    className, name, value));
+                        }
+                    } catch (SecurityException | IllegalAccessException e) {
+                        // Not allowed to make the field accessible, or no access. Ignore.
+                        continue;
+                    }
+                }
+            }
+        }
+        return messageNames;
+    }
+
+    /**
+     * Default prefixes for constants.
+     */
+    public static final String[] DEFAULT_PREFIXES = {"CMD_", "EVENT_"};
+
+    /**
+     * Finds the names of integer constants. Searches the specified {@code classes}, looking for
+     * accessible static integer values whose names begin with {@link #DEFAULT_PREFIXES}.
+     *
+     * @param classNames the classes to examine.
+     * @prefixes only consider fields names starting with one of these prefixes.
+     * @return a {@link SparseArray} mapping integer constants to their names.
+     */
+    public static SparseArray<String> findMessageNames(Class[] classNames) {
+        return findMessageNames(classNames, DEFAULT_PREFIXES);
+    }
+}
+
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index a106f48..5992f7a 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -64,5 +64,6 @@
     public static final int BASE_NETWORK_AGENT                                      = 0x00081000;
     public static final int BASE_NETWORK_MONITOR                                    = 0x00082000;
     public static final int BASE_NETWORK_FACTORY                                    = 0x00083000;
+    public static final int BASE_ETHERNET                                           = 0x00084000;
     //TODO: define all used protocols
 }
diff --git a/core/java/com/android/internal/util/WakeupMessage.java b/core/java/com/android/internal/util/WakeupMessage.java
new file mode 100644
index 0000000..451078b
--- /dev/null
+++ b/core/java/com/android/internal/util/WakeupMessage.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+
+/**
+ * An AlarmListener that sends the specified message to a Handler and keeps the system awake until
+ * the message is processed.
+ *
+ * This is useful when using the AlarmManager direct callback interface to wake up the system and
+ * request that an object whose API consists of messages (such as a StateMachine) perform some
+ * action.
+ *
+ * In this situation, using AlarmManager.onAlarmListener by itself will wake up the system to send
+ * the message, but does not guarantee that the system will be awake until the target object has
+ * processed it. This is because as soon as the onAlarmListener sends the message and returns, the
+ * AlarmManager releases its wakelock and the system is free to go to sleep again.
+ */
+public class WakeupMessage implements AlarmManager.OnAlarmListener {
+    private final AlarmManager mAlarmManager;
+    private final Handler mHandler;
+    private final String mCmdName;
+    private final int mCmd, mArg1, mArg2;
+    private boolean mScheduled;
+
+    public WakeupMessage(Context context, Handler handler,
+            String cmdName, int cmd, int arg1, int arg2) {
+        mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+        mHandler = handler;
+        mCmdName = cmdName;
+        mCmd = cmd;
+        mArg1 = arg1;
+        mArg2 = arg2;
+    }
+
+    public WakeupMessage(Context context, Handler handler, String cmdName, int cmd, int arg1) {
+        this(context, handler, cmdName, cmd, arg1, 0);
+    }
+
+    public WakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
+        this(context, handler, cmdName, cmd, 0, 0);
+    }
+
+    /**
+     * Schedule the message to be delivered at the time in milliseconds of the
+     * {@link android.os.SystemClock#elapsedRealtime SystemClock.elapsedRealtime()} clock and wakeup
+     * the device when it goes off. If schedule is called multiple times without the message being
+     * dispatched then the alarm is rescheduled to the new time.
+     */
+    public synchronized void schedule(long when) {
+        mAlarmManager.setExact(
+                AlarmManager.ELAPSED_REALTIME_WAKEUP, when, mCmdName, this, mHandler);
+        mScheduled = true;
+    }
+
+    /**
+     * Cancel all pending messages. This includes alarms that may have been fired, but have not been
+     * run on the handler yet.
+     */
+    public synchronized void cancel() {
+        if (mScheduled) {
+            mAlarmManager.cancel(this);
+            mScheduled = false;
+        }
+    }
+
+    @Override
+    public void onAlarm() {
+        // Once this method is called the alarm has already been fired and removed from
+        // AlarmManager (it is still partially tracked, but only for statistics). The alarm can now
+        // be marked as unscheduled so that it can be rescheduled in the message handler.
+        final boolean stillScheduled;
+        synchronized (this) {
+            stillScheduled = mScheduled;
+            mScheduled = false;
+        }
+        if (stillScheduled) {
+            Message msg = mHandler.obtainMessage(mCmd, mArg1, mArg2);
+            mHandler.handleMessage(msg);
+            msg.recycle();
+        }
+    }
+}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index ba0876d..defb88a 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -39,23 +39,6 @@
 int ifc_enable(const char *ifname);
 int ifc_disable(const char *ifname);
 int ifc_reset_connections(const char *ifname, int reset_mask);
-
-int dhcp_start(const char * const ifname);
-int dhcp_start_renew(const char * const ifname);
-int dhcp_get_results(const char * const ifname,
-                     const char *ipaddr,
-                     const char *gateway,
-                     uint32_t *prefixLength,
-                     const char *dns[],
-                     const char *server,
-                     uint32_t *lease,
-                     const char *vendorInfo,
-                     const char *domains,
-                     const char *mtu);
-
-int dhcp_stop(const char *ifname);
-int dhcp_release_lease(const char *ifname);
-char *dhcp_get_errmsg();
 }
 
 #define NETUTILS_PKG_NAME "android/net/NetworkUtils"
@@ -64,22 +47,6 @@
 
 static const uint16_t kDhcpClientPort = 68;
 
-/*
- * The following remembers the jfieldID's of the fields
- * of the DhcpInfo Java object, so that we don't have
- * to look them up every time.
- */
-static struct fieldIds {
-    jmethodID clear;
-    jmethodID setIpAddress;
-    jmethodID setGateway;
-    jmethodID addDns;
-    jmethodID setDomains;
-    jmethodID setServerAddress;
-    jmethodID setLeaseDuration;
-    jmethodID setVendorInfo;
-} dhcpResultsFieldIds;
-
 static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
       jstring ifname, jint mask)
 {
@@ -95,137 +62,6 @@
     return (jint)result;
 }
 
-static jboolean android_net_utils_getDhcpResults(JNIEnv* env, jobject clazz, jstring ifname,
-        jobject dhcpResults)
-{
-    int result;
-    char  ipaddr[PROPERTY_VALUE_MAX];
-    uint32_t prefixLength;
-    char gateway[PROPERTY_VALUE_MAX];
-    char    dns1[PROPERTY_VALUE_MAX];
-    char    dns2[PROPERTY_VALUE_MAX];
-    char    dns3[PROPERTY_VALUE_MAX];
-    char    dns4[PROPERTY_VALUE_MAX];
-    const char *dns[5] = {dns1, dns2, dns3, dns4, NULL};
-    char  server[PROPERTY_VALUE_MAX];
-    uint32_t lease;
-    char vendorInfo[PROPERTY_VALUE_MAX];
-    char domains[PROPERTY_VALUE_MAX];
-    char mtu[PROPERTY_VALUE_MAX];
-
-    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-    if (nameStr == NULL) return (jboolean)false;
-
-    result = ::dhcp_get_results(nameStr, ipaddr, gateway, &prefixLength,
-            dns, server, &lease, vendorInfo, domains, mtu);
-    if (result != 0) {
-        ALOGD("dhcp_get_results failed : %s (%s)", nameStr, ::dhcp_get_errmsg());
-    }
-
-    env->ReleaseStringUTFChars(ifname, nameStr);
-    if (result == 0) {
-        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear);
-
-        // set the linkAddress
-        // dhcpResults->addLinkAddress(inetAddress, prefixLength)
-        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setIpAddress,
-                env->NewStringUTF(ipaddr), prefixLength);
-    }
-
-    if (result == 0) {
-        // set the gateway
-        result = env->CallBooleanMethod(dhcpResults,
-                dhcpResultsFieldIds.setGateway, env->NewStringUTF(gateway));
-    }
-
-    if (result == 0) {
-        // dhcpResults->addDns(new InetAddress(dns1))
-        result = env->CallBooleanMethod(dhcpResults,
-                dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1));
-    }
-
-    if (result == 0) {
-        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains,
-                env->NewStringUTF(domains));
-
-        result = env->CallBooleanMethod(dhcpResults,
-                dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2));
-
-        if (result == 0) {
-            result = env->CallBooleanMethod(dhcpResults,
-                    dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3));
-            if (result == 0) {
-                result = env->CallBooleanMethod(dhcpResults,
-                        dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4));
-            }
-        }
-    }
-
-    if (result == 0) {
-        // dhcpResults->setServerAddress(new InetAddress(server))
-        result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress,
-                env->NewStringUTF(server));
-    }
-
-    if (result == 0) {
-        // dhcpResults->setLeaseDuration(lease)
-        env->CallVoidMethod(dhcpResults,
-                dhcpResultsFieldIds.setLeaseDuration, lease);
-
-        // dhcpResults->setVendorInfo(vendorInfo)
-        env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo,
-                env->NewStringUTF(vendorInfo));
-    }
-    return (jboolean)(result == 0);
-}
-
-static jboolean android_net_utils_startDhcp(JNIEnv* env, jobject clazz, jstring ifname)
-{
-    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-    if (nameStr == NULL) return (jboolean)false;
-    if (::dhcp_start(nameStr) != 0) {
-        ALOGD("dhcp_start failed : %s", nameStr);
-        return (jboolean)false;
-    }
-    return (jboolean)true;
-}
-
-static jboolean android_net_utils_startDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname)
-{
-    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-    if (nameStr == NULL) return (jboolean)false;
-    if (::dhcp_start_renew(nameStr) != 0) {
-        ALOGD("dhcp_start_renew failed : %s", nameStr);
-        return (jboolean)false;
-    }
-    return (jboolean)true;
-}
-
-static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
-{
-    int result;
-
-    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-    result = ::dhcp_stop(nameStr);
-    env->ReleaseStringUTFChars(ifname, nameStr);
-    return (jboolean)(result == 0);
-}
-
-static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname)
-{
-    int result;
-
-    const char *nameStr = env->GetStringUTFChars(ifname, NULL);
-    result = ::dhcp_release_lease(nameStr);
-    env->ReleaseStringUTFChars(ifname, nameStr);
-    return (jboolean)(result == 0);
-}
-
-static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz)
-{
-    return env->NewStringUTF(::dhcp_get_errmsg());
-}
-
 static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
@@ -305,12 +141,6 @@
 static const JNINativeMethod gNetworkUtilMethods[] = {
     /* name, signature, funcPtr */
     { "resetConnections", "(Ljava/lang/String;I)I",  (void *)android_net_utils_resetConnections },
-    { "startDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_startDhcp },
-    { "startDhcpRenew", "(Ljava/lang/String;)Z",  (void *)android_net_utils_startDhcpRenew },
-    { "getDhcpResults", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z",  (void *)android_net_utils_getDhcpResults },
-    { "stopDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_stopDhcp },
-    { "releaseDhcpLease", "(Ljava/lang/String;)Z",  (void *)android_net_utils_releaseDhcpLease },
-    { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
     { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork },
     { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess },
     { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
@@ -322,24 +152,6 @@
 
 int register_android_net_NetworkUtils(JNIEnv* env)
 {
-    jclass dhcpResultsClass = FindClassOrDie(env, "android/net/DhcpResults");
-
-    dhcpResultsFieldIds.clear = GetMethodIDOrDie(env, dhcpResultsClass, "clear", "()V");
-    dhcpResultsFieldIds.setIpAddress =GetMethodIDOrDie(env, dhcpResultsClass, "setIpAddress",
-            "(Ljava/lang/String;I)Z");
-    dhcpResultsFieldIds.setGateway = GetMethodIDOrDie(env, dhcpResultsClass, "setGateway",
-            "(Ljava/lang/String;)Z");
-    dhcpResultsFieldIds.addDns = GetMethodIDOrDie(env, dhcpResultsClass, "addDns",
-            "(Ljava/lang/String;)Z");
-    dhcpResultsFieldIds.setDomains = GetMethodIDOrDie(env, dhcpResultsClass, "setDomains",
-            "(Ljava/lang/String;)V");
-    dhcpResultsFieldIds.setServerAddress = GetMethodIDOrDie(env, dhcpResultsClass,
-            "setServerAddress", "(Ljava/lang/String;)Z");
-    dhcpResultsFieldIds.setLeaseDuration = GetMethodIDOrDie(env, dhcpResultsClass,
-            "setLeaseDuration", "(I)V");
-    dhcpResultsFieldIds.setVendorInfo = GetMethodIDOrDie(env, dhcpResultsClass, "setVendorInfo",
-            "(Ljava/lang/String;)V");
-
     return RegisterMethodsOrDie(env, NETUTILS_PKG_NAME, gNetworkUtilMethods,
                                 NELEM(gNetworkUtilMethods));
 }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b081568..8a77f82 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -610,6 +610,10 @@
         // Grant CAP_WAKE_ALARM and CAP_BLOCK_SUSPEND to the Bluetooth process.
         capabilities |= (1LL << CAP_WAKE_ALARM);
         capabilities |= (1LL << CAP_BLOCK_SUSPEND);
+        // Allow bluetooth to open packet sockets so it can start the DHCP client.
+        // TODO: consider making such functionality an RPC to netd.
+        capabilities |= (1LL << CAP_NET_RAW);
+        capabilities |= (1LL << CAP_NET_BIND_SERVICE);
 
         // Add the Bluetooth process to the system group.
         jsize length = env->GetArrayLength(reinterpret_cast<jarray>(gids));
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0793905..8036e58 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -185,8 +185,6 @@
     <!-- Displayed to tell the user that they cannot change the caller ID setting. -->
     <string name="CLIRPermanent">You can\'t change the caller ID setting.</string>
 
-    <!-- Notification title to tell the user that restricted state is changed by access control. -->
-    <string name="RestrictedChangedTitle">Restricted access changed</string>
     <!-- Displayed to tell the user that data service is blocked by access control. -->
     <string name="RestrictedOnData">Data service is blocked.</string>
     <!-- Displayed to tell the user that emergency service is blocked by access control. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3185ce7..885b80a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -488,7 +488,6 @@
   <java-symbol type="string" name="Noon" />
   <java-symbol type="string" name="PinMmi" />
   <java-symbol type="string" name="PwdMmi" />
-  <java-symbol type="string" name="RestrictedChangedTitle" />
   <java-symbol type="string" name="RestrictedOnAllVoice" />
   <java-symbol type="string" name="RestrictedOnData" />
   <java-symbol type="string" name="RestrictedOnEmergency" />
diff --git a/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java b/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java
deleted file mode 100644
index 7088650..0000000
--- a/core/tests/coretests/src/com/android/internal/util/AsyncChannelTest.java
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.os.Debug;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import junit.framework.TestCase;
-
-/**
- * Test for AsyncChannel.
- */
-public class AsyncChannelTest extends TestCase {
-    private static final boolean DBG = true;
-    private static final boolean WAIT_FOR_DEBUGGER = false;
-    private static final String TAG = "AsyncChannelTest";
-
-    @SmallTest
-    public void test1() throws Exception {
-        if (DBG) log("test1");
-        if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger();
-        assertTrue(1 == 1);
-    }
-
-    protected void log(String s) {
-        Log.d(TAG, s);
-    }
-}
diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk
new file mode 100644
index 0000000..3c6c32e
--- /dev/null
+++ b/core/tests/utiltests/Android.mk
@@ -0,0 +1,24 @@
+#########################################################################
+# Build FrameworksUtilTests package
+#########################################################################
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    android-support-test \
+    mockito-target
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := FrameworksUtilTests
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/utiltests/AndroidManifest.xml b/core/tests/utiltests/AndroidManifest.xml
new file mode 100644
index 0000000..fecaf8e
--- /dev/null
+++ b/core/tests/utiltests/AndroidManifest.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="com.android.frameworks.utiltests">
+
+    <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
+    <uses-permission android:name="android.permission.MANAGE_APP_TOKENS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+    <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+    <uses-permission android:name="android.permission.READ_NETWORK_USAGE_HISTORY" />
+    <uses-permission android:name="android.permission.MODIFY_NETWORK_ACCOUNTING" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.MANAGE_DEVICE_ADMINS" />
+    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <instrumentation
+        android:name="android.support.test.runner.AndroidJUnitRunner"
+        android:targetPackage="com.android.frameworks.utiltests"
+        android:label="Frameworks Utility Tests" />
+
+</manifest>
diff --git a/core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/ArrayUtilsTest.java
rename to core/tests/utiltests/src/com/android/internal/util/ArrayUtilsTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/BitwiseStreamsTest.java b/core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/BitwiseStreamsTest.java
rename to core/tests/utiltests/src/com/android/internal/util/BitwiseStreamsTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/CallbackRegistryTest.java b/core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/CallbackRegistryTest.java
rename to core/tests/utiltests/src/com/android/internal/util/CallbackRegistryTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/CharSequencesTest.java b/core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/CharSequencesTest.java
rename to core/tests/utiltests/src/com/android/internal/util/CharSequencesTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
similarity index 94%
rename from core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java
rename to core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
index be7116d..5f36c2d 100644
--- a/core/tests/coretests/src/com/android/internal/util/FastXmlSerializerTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/FastXmlSerializerTest.java
@@ -42,6 +42,6 @@
         out.endDocument();
 
         assertEquals("<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
-                + "<string name=\"meow\"></string>", stream.toString());
+                + "<string name=\"meow\"></string>\n", stream.toString());
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java b/core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/FileRotatorTest.java
rename to core/tests/utiltests/src/com/android/internal/util/FileRotatorTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java b/core/tests/utiltests/src/com/android/internal/util/IndentingPrintWriterTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/IndentingPrintWriterTest.java
rename to core/tests/utiltests/src/com/android/internal/util/IndentingPrintWriterTest.java
diff --git a/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
new file mode 100644
index 0000000..32b969a
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/MessageUtilsTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static org.junit.Assert.*;
+
+import com.android.internal.util.MessageUtils;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.SparseArray;
+
+import org.junit.Test;
+
+
+class A {
+    // Should not see these.
+    private int mMember;
+    public final int CMD_NOT_STATIC = 7;
+    private static final String CMD_NOT_INT = "not an integer";
+    public static int CMD_NOT_FINAL = 34;
+    public static final int kWrongPrefix = 99;
+
+    // Should see these.
+    private static final int CMD_DO_SOMETHING = 12;
+    public static final int EVENT_SOMETHING_HAPPENED = 45;
+}
+
+class B {
+    public static final int CMD_FOO = 56;
+    public static final int EVENT_BAR = 55;
+    public static final int NOTIFICATION_BAZ = 12;
+}
+
+/**
+ * Unit tests for {@link com.android.util.MessageUtils}.
+ */
+@SmallTest
+public class MessageUtilsTest {
+
+    private static final Class[] CLASSES = { A.class, B.class };
+
+    private SparseArray<String> makeSparseArray(int[] keys, String[] values) throws Exception {
+        assertEquals("Must specify same number of keys and values", keys.length, values.length);
+        SparseArray<String> out = new SparseArray<>();
+        for (int i = 0; i < keys.length; i++) {
+            out.put(keys[i], values[i]);
+        }
+        return out;
+    }
+
+    private void assertSparseArrayEquals(
+            SparseArray<String> a1, SparseArray<String> a2) throws Exception {
+        String msg = String.format("%s != %s", a1.toString(), a2.toString());
+        assertEquals(msg, a1.size(), a2.size());
+        int size = a1.size();
+        for (int i = 0; i < size; i++) {
+            assertEquals(msg, a1.keyAt(i), a2.keyAt(i));
+            assertEquals(msg, a1.valueAt(i), a2.valueAt(i));
+        }
+    }
+
+    @Test
+    public void basicOperation() throws Exception {
+        SparseArray<String> expected = makeSparseArray(
+            new int[]{12, 45, 55, 56},
+            new String[]{"CMD_DO_SOMETHING", "EVENT_SOMETHING_HAPPENED", "EVENT_BAR", "CMD_FOO"});
+        assertSparseArrayEquals(expected, MessageUtils.findMessageNames(CLASSES));
+    }
+
+    @Test
+    public void withPrefixes() throws Exception {
+        SparseArray<String> expected = makeSparseArray(
+            new int[]{45, 55},
+            new String[]{"EVENT_SOMETHING_HAPPENED", "EVENT_BAR"});
+        assertSparseArrayEquals(expected, MessageUtils.findMessageNames(CLASSES,
+                new String[]{"EVENT_"}));
+    }
+
+    @Test(expected=MessageUtils.DuplicateConstantError.class)
+    public void duplicateConstants() {
+        MessageUtils.findMessageNames(CLASSES, new String[]{"CMD_", "NOTIFICATION_"});
+    }
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/PredicatesTest.java b/core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/PredicatesTest.java
rename to core/tests/utiltests/src/com/android/internal/util/PredicatesTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/ProcFileReaderTest.java b/core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/ProcFileReaderTest.java
rename to core/tests/utiltests/src/com/android/internal/util/ProcFileReaderTest.java
diff --git a/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
similarity index 99%
rename from core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
rename to core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
index 2a2c24e..302aa87 100644
--- a/core/tests/coretests/src/com/android/internal/util/StateMachineTest.java
+++ b/core/tests/utiltests/src/com/android/internal/util/StateMachineTest.java
@@ -25,6 +25,7 @@
 import android.os.Message;
 import android.os.SystemClock;
 
+import android.test.suitebuilder.annotation.Suppress;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
 import com.android.internal.util.StateMachine.LogRec;
@@ -38,6 +39,7 @@
 /**
  * Test for StateMachine.
  */
+@Suppress // Failing
 public class StateMachineTest extends TestCase {
     private static final String ENTER = "enter";
     private static final String EXIT = "exit";
diff --git a/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
new file mode 100644
index 0000000..da8bc1d
--- /dev/null
+++ b/core/tests/utiltests/src/com/android/internal/util/WakeupMessageTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+/**
+ * Unit tests for {@link com.android.internal.util.WakeupMessage}.
+ */
+@SmallTest
+public class WakeupMessageTest {
+    private static final String TEST_CMD_NAME = "TEST cmd Name";
+    private static final int TEST_CMD = 18;
+    private static final int TEST_ARG1 = 33;
+    private static final int TEST_ARG2 = 182;
+
+    @Mock AlarmManager mAlarmManager;
+    WakeupMessage mMessage;
+    // Make a spy so that we can verify calls to it
+    @Spy MessageCapturingHandler mHandler = new MessageCapturingHandler();
+
+    ArgumentCaptor<AlarmManager.OnAlarmListener> mListenerCaptor =
+            ArgumentCaptor.forClass(AlarmManager.OnAlarmListener.class);
+
+    /**
+     * A Handler that will capture the most recent message sent to it.
+     *
+     * This handler is setup on the main Looper
+     */
+    public static class MessageCapturingHandler extends Handler {
+        private Message mLastMessage;
+
+        public MessageCapturingHandler() {
+            super(Looper.getMainLooper(), /* Nothing is actually dispatched on this Looper */
+                    null, false);
+        }
+
+        @Override
+        public void handleMessage(Message m) {
+            // need to copy since it will be recycled after this method returns
+            mLastMessage = Message.obtain(m);
+        }
+
+        public Message getLastMessage() {
+            return mLastMessage;
+        }
+    }
+
+    /**
+     * Sets up the test.
+     */
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        Context context = mock(Context.class);
+        when(context.getSystemService(Context.ALARM_SERVICE)).thenReturn(mAlarmManager);
+        // capture the listener for each AlarmManager.setExact call
+        doNothing().when(mAlarmManager).setExact(anyInt(), anyLong(), any(String.class),
+                mListenerCaptor.capture(), any(Handler.class));
+
+        mMessage = new WakeupMessage(context, mHandler, TEST_CMD_NAME, TEST_CMD, TEST_ARG1,
+                TEST_ARG2);
+    }
+
+    /**
+     * Ensure the test is cleaned up and ready for the next test.
+     */
+    @After
+    public void cleanup() {
+        validateMockitoUsage();
+    }
+
+    private void scheduleAndVerifyAlarm(long when) {
+        mMessage.schedule(when);
+        verify(mAlarmManager).setExact(eq(AlarmManager.ELAPSED_REALTIME_WAKEUP), eq(when),
+                eq(TEST_CMD_NAME), any(AlarmManager.OnAlarmListener.class), eq(mHandler));
+    }
+
+    private void verifyMessageDispatchedOnce() {
+        verify(mHandler, times(1)).handleMessage(any(Message.class));
+        assertEquals("what", TEST_CMD, mHandler.getLastMessage().what);
+        assertEquals("arg1", TEST_ARG1, mHandler.getLastMessage().arg1);
+        assertEquals("arg2", TEST_ARG2, mHandler.getLastMessage().arg2);
+    }
+
+    /**
+     * Schedule and deliver a single message
+     */
+    @Test
+    public void scheduleAndDeliverMessage() {
+        final long when = 1001;
+        scheduleAndVerifyAlarm(when);
+        verify(mHandler, never()).handleMessage(any(Message.class));
+        mListenerCaptor.getValue().onAlarm();
+        verifyMessageDispatchedOnce();
+    }
+
+    /**
+     * Check that the message is not delivered if cancel is called it after its alarm fires but
+     * before onAlarm is called.
+     *
+     * This ensures that if cancel is called on the handler thread, any previously-scheduled message
+     * is guaranteed not to be delivered.
+     */
+    @Test
+    public void scheduleAndCancelMessage() {
+        final long when = 1010;
+        scheduleAndVerifyAlarm(when);
+        mMessage.cancel();
+        mListenerCaptor.getValue().onAlarm();
+        verify(mHandler, never()).handleMessage(any(Message.class));
+    }
+
+    /**
+     * Verify nothing happens when cancel is called without a schedule
+     */
+    @Test
+    public void cancelWithoutSchedule() {
+        mMessage.cancel();
+    }
+
+    /**
+     * Verify that the message is silently rescheduled if schedule is called twice without the
+     * message being dispatched first.
+     */
+    @Test
+    public void scheduleTwiceWithoutMessageDispatched() {
+        final long when1 = 1011;
+        final long when2 = 1012;
+        scheduleAndVerifyAlarm(when1);
+        scheduleAndVerifyAlarm(when2);
+        mListenerCaptor.getValue().onAlarm();
+        verifyMessageDispatchedOnce();
+    }
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/util/XmlUtilsTest.java b/core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
similarity index 100%
rename from core/tests/coretests/src/com/android/internal/util/XmlUtilsTest.java
rename to core/tests/utiltests/src/com/android/internal/util/XmlUtilsTest.java
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 2e96f18..32df06c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -24,6 +24,8 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.database.Cursor;
+import android.net.NetworkPolicy;
+import android.net.NetworkPolicyManager;
 import android.net.Uri;
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiConfiguration.KeyMgmt;
@@ -34,6 +36,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.BackupUtils;
 import android.util.Log;
 
 import com.android.internal.widget.LockPatternUtils;
@@ -81,36 +84,49 @@
     private static final String KEY_GLOBAL = "global";
     private static final String KEY_LOCALE = "locale";
     private static final String KEY_LOCK_SETTINGS = "lock_settings";
+    private static final String KEY_SOFTAP_CONFIG = "softap_config";
+    private static final String KEY_NETWORK_POLICIES = "network_policies";
 
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
-    private static final int STATE_VERSION = 4;
+    private static final int STATE_VERSION = 6;
+
+    // Versioning of the Network Policies backup payload.
+    private static final int NETWORK_POLICIES_BACKUP_VERSION = 1;
+
 
     // Slots in the checksum array.  Never insert new items in the middle
     // of this array; new slots must be appended.
-    private static final int STATE_SYSTEM          = 0;
-    private static final int STATE_SECURE          = 1;
-    private static final int STATE_LOCALE          = 2;
-    private static final int STATE_WIFI_SUPPLICANT = 3;
-    private static final int STATE_WIFI_CONFIG     = 4;
-    private static final int STATE_GLOBAL          = 5;
-    private static final int STATE_LOCK_SETTINGS   = 6;
+    private static final int STATE_SYSTEM           = 0;
+    private static final int STATE_SECURE           = 1;
+    private static final int STATE_LOCALE           = 2;
+    private static final int STATE_WIFI_SUPPLICANT  = 3;
+    private static final int STATE_WIFI_CONFIG      = 4;
+    private static final int STATE_GLOBAL           = 5;
+    private static final int STATE_LOCK_SETTINGS    = 6;
+    private static final int STATE_SOFTAP_CONFIG    = 7;
+    private static final int STATE_NETWORK_POLICIES = 8;
 
-    private static final int STATE_SIZE            = 7; // The current number of state items
+    private static final int STATE_SIZE             = 9; // The current number of state items
 
     // Number of entries in the checksum array at various version numbers
     private static final int STATE_SIZES[] = {
-        0,
-        4,              // version 1
-        5,              // version 2 added STATE_WIFI_CONFIG
-        6,              // version 3 added STATE_GLOBAL
-        STATE_SIZE      // version 4 added STATE_LOCK_SETTINGS
+            0,
+            4,              // version 1
+            5,              // version 2 added STATE_WIFI_CONFIG
+            6,              // version 3 added STATE_GLOBAL
+            7,              // version 4 added STATE_LOCK_SETTINGS
+            8,              // version 5 added STATE_SOFTAP_CONFIG
+            STATE_SIZE      // version 6 added STATE_NETWORK_POLICIES
     };
 
     // Versioning of the 'full backup' format
-    private static final int FULL_BACKUP_VERSION = 3;
+    // Increment this version any time a new item is added
+    private static final int FULL_BACKUP_VERSION = 5;
     private static final int FULL_BACKUP_ADDED_GLOBAL = 2;  // added the "global" entry
     private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
+    private static final int FULL_BACKUP_ADDED_SOFTAP_CONF = 4; //added the "softap_config" entry
+    private static final int FULL_BACKUP_ADDED_NETWORK_POLICIES = 5; //added "network_policies"
 
     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
 
@@ -119,8 +135,8 @@
     private static final String TAG = "SettingsBackupAgent";
 
     private static final String[] PROJECTION = {
-        Settings.NameValueTable.NAME,
-        Settings.NameValueTable.VALUE
+            Settings.NameValueTable.NAME,
+            Settings.NameValueTable.VALUE
     };
 
     private static final String FILE_WIFI_SUPPLICANT = "/data/misc/wifi/wpa_supplicant.conf";
@@ -146,7 +162,7 @@
 
     private SettingsHelper mSettingsHelper;
     private WifiManager mWfm;
-    private static String mWifiConfigFile;
+    private String mWifiConfigFile;
 
     // Chain of asynchronous operations used when rewriting the wifi supplicant config file
     WifiDisableRunnable mWifiDisable = null;
@@ -338,7 +354,7 @@
                                 }
                                 continue;
                             }
-                            if (! mKnownNetworks.contains(net)) {
+                            if (!mKnownNetworks.contains(net)) {
                                 if (DEBUG_BACKUP) {
                                     Log.v(TAG, "Adding " + net.ssid + " / " + net.key_mgmt);
                                 }
@@ -405,26 +421,34 @@
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
+        byte[] softApConfigData = getSoftAPConfiguration();
+        byte[] netPoliciesData = getNetworkPolicies();
 
         long[] stateChecksums = readOldChecksums(oldState);
 
         stateChecksums[STATE_SYSTEM] =
-            writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_SYSTEM], KEY_SYSTEM, systemSettingsData, data);
         stateChecksums[STATE_SECURE] =
-            writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_SECURE], KEY_SECURE, secureSettingsData, data);
         stateChecksums[STATE_GLOBAL] =
-            writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_GLOBAL], KEY_GLOBAL, globalSettingsData, data);
         stateChecksums[STATE_LOCALE] =
-            writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
+                writeIfChanged(stateChecksums[STATE_LOCALE], KEY_LOCALE, locale, data);
         stateChecksums[STATE_WIFI_SUPPLICANT] =
-            writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
-                    wifiSupplicantData, data);
+                writeIfChanged(stateChecksums[STATE_WIFI_SUPPLICANT], KEY_WIFI_SUPPLICANT,
+                        wifiSupplicantData, data);
         stateChecksums[STATE_WIFI_CONFIG] =
-            writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
-                    data);
+                writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
+                        data);
         stateChecksums[STATE_LOCK_SETTINGS] =
-            writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
-                    lockSettingsData, data);
+                writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
+                        lockSettingsData, data);
+        stateChecksums[STATE_SOFTAP_CONFIG] =
+                writeIfChanged(stateChecksums[STATE_SOFTAP_CONFIG], KEY_SOFTAP_CONFIG,
+                        softApConfigData, data);
+        stateChecksums[STATE_NETWORK_POLICIES] =
+                writeIfChanged(stateChecksums[STATE_NETWORK_POLICIES], KEY_NETWORK_POLICIES,
+                        netPoliciesData, data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -503,8 +527,8 @@
                     restoreWifiSupplicant(FILE_WIFI_SUPPLICANT,
                             restoredSupplicantData, restoredSupplicantData.length);
                     FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
-                            FileUtils.S_IRUSR | FileUtils.S_IWUSR |
-                            FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+                            FileUtils.S_IRUSR | FileUtils.S_IWUSR
+                            | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                             Process.myUid(), Process.WIFI_UID);
                 }
                 if (restoredWifiConfigFile != null) {
@@ -516,8 +540,8 @@
                     Settings.Global.putInt(getContentResolver(),
                             Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE, scanAlways);
                 }
-                enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
-                        retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+                enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
+                        || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
             }
         }
     }
@@ -542,27 +566,55 @@
         while (data.readNextHeader()) {
             final String key = data.getKey();
             final int size = data.getDataSize();
-            if (KEY_SYSTEM.equals(key)) {
-                restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
-                mSettingsHelper.applyAudioSettings();
-            } else if (KEY_SECURE.equals(key)) {
-                restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
-            } else if (KEY_GLOBAL.equals(key)) {
-                restoreSettings(data, Settings.Global.CONTENT_URI, null);
-            } else if (KEY_WIFI_SUPPLICANT.equals(key)) {
-                initWifiRestoreIfNecessary();
-                mWifiRestore.incorporateWifiSupplicant(data);
-            } else if (KEY_LOCALE.equals(key)) {
-                byte[] localeData = new byte[size];
-                data.readEntityData(localeData, 0, size);
-                mSettingsHelper.setLocaleData(localeData, size);
-            } else if (KEY_WIFI_CONFIG.equals(key)) {
-                initWifiRestoreIfNecessary();
-                mWifiRestore.incorporateWifiConfigFile(data);
-            } else if (KEY_LOCK_SETTINGS.equals(key)) {
-                restoreLockSettings(data);
-             } else {
-                data.skipEntityData();
+            switch (key) {
+                case KEY_SYSTEM :
+                    restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal);
+                    mSettingsHelper.applyAudioSettings();
+                    break;
+
+                case KEY_SECURE :
+                    restoreSettings(data, Settings.Secure.CONTENT_URI, movedToGlobal);
+                    break;
+
+                case KEY_GLOBAL :
+                    restoreSettings(data, Settings.Global.CONTENT_URI, null);
+                    break;
+
+                case KEY_WIFI_SUPPLICANT :
+                    initWifiRestoreIfNecessary();
+                    mWifiRestore.incorporateWifiSupplicant(data);
+                    break;
+
+                case KEY_LOCALE :
+                    byte[] localeData = new byte[size];
+                    data.readEntityData(localeData, 0, size);
+                    mSettingsHelper.setLocaleData(localeData, size);
+                    break;
+
+                case KEY_WIFI_CONFIG :
+                    initWifiRestoreIfNecessary();
+                    mWifiRestore.incorporateWifiConfigFile(data);
+                    break;
+
+                case KEY_LOCK_SETTINGS :
+                    restoreLockSettings(data);
+                    break;
+
+                case KEY_SOFTAP_CONFIG :
+                    byte[] softapData = new byte[size];
+                    data.readEntityData(softapData, 0, size);
+                    restoreSoftApConfiguration(softapData);
+                    break;
+
+                case KEY_NETWORK_POLICIES:
+                    byte[] netPoliciesData = new byte[size];
+                    data.readEntityData(netPoliciesData, 0, size);
+                    restoreNetworkPolicies(netPoliciesData);
+                    break;
+
+                default :
+                    data.skipEntityData();
+
             }
         }
 
@@ -589,6 +641,8 @@
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
+        byte[] softApConfigData = getSoftAPConfiguration();
+        byte[] netPoliciesData = getNetworkPolicies();
 
         // Write the data to the staging file, then emit that as our tarfile
         // representation of the backed-up settings.
@@ -605,16 +659,22 @@
             if (DEBUG_BACKUP) Log.d(TAG, systemSettingsData.length + " bytes of settings data");
             out.writeInt(systemSettingsData.length);
             out.write(systemSettingsData);
-            if (DEBUG_BACKUP) Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
+            if (DEBUG_BACKUP) {
+                Log.d(TAG, secureSettingsData.length + " bytes of secure settings data");
+            }
             out.writeInt(secureSettingsData.length);
             out.write(secureSettingsData);
-            if (DEBUG_BACKUP) Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
+            if (DEBUG_BACKUP) {
+                Log.d(TAG, globalSettingsData.length + " bytes of global settings data");
+            }
             out.writeInt(globalSettingsData.length);
             out.write(globalSettingsData);
             if (DEBUG_BACKUP) Log.d(TAG, locale.length + " bytes of locale data");
             out.writeInt(locale.length);
             out.write(locale);
-            if (DEBUG_BACKUP) Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
+            if (DEBUG_BACKUP) {
+                Log.d(TAG, wifiSupplicantData.length + " bytes of wifi supplicant data");
+            }
             out.writeInt(wifiSupplicantData.length);
             out.write(wifiSupplicantData);
             if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
@@ -623,6 +683,12 @@
             if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
             out.writeInt(lockSettingsData.length);
             out.write(lockSettingsData);
+            if (DEBUG_BACKUP) Log.d(TAG, softApConfigData.length + " bytes of softap config data");
+            out.writeInt(softApConfigData.length);
+            out.write(softApConfigData);
+            if (DEBUG_BACKUP) Log.d(TAG, netPoliciesData.length + " bytes of net policies data");
+            out.writeInt(netPoliciesData.length);
+            out.write(netPoliciesData);
 
             out.flush();    // also flushes downstream
 
@@ -691,12 +757,12 @@
             int retainedWifiState = enableWifi(false);
             restoreWifiSupplicant(FILE_WIFI_SUPPLICANT, buffer, nBytes);
             FileUtils.setPermissions(FILE_WIFI_SUPPLICANT,
-                    FileUtils.S_IRUSR | FileUtils.S_IWUSR |
-                    FileUtils.S_IRGRP | FileUtils.S_IWGRP,
+                    FileUtils.S_IRUSR | FileUtils.S_IWUSR
+                    | FileUtils.S_IRGRP | FileUtils.S_IWGRP,
                     Process.myUid(), Process.WIFI_UID);
             // retain the previous WIFI state.
-            enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED ||
-                    retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
+            enableWifi(retainedWifiState == WifiManager.WIFI_STATE_ENABLED
+                    || retainedWifiState == WifiManager.WIFI_STATE_ENABLING);
 
             // wifi config
             nBytes = in.readInt();
@@ -714,7 +780,26 @@
                     restoreLockSettings(buffer, nBytes);
                 }
             }
-
+            // softap config
+            if (version >= FULL_BACKUP_ADDED_SOFTAP_CONF) {
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of softap config data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                if (nBytes > 0) {
+                    in.readFully(buffer, 0, nBytes);
+                    restoreSoftApConfiguration(buffer);
+                }
+            }
+            // network policies
+            if (version >= FULL_BACKUP_ADDED_NETWORK_POLICIES) {
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of network policies data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                if (nBytes > 0) {
+                    in.readFully(buffer, 0, nBytes);
+                    restoreNetworkPolicies(buffer);
+                }
+            }
             if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
         } else {
             data.close();
@@ -899,7 +984,7 @@
             settingsHelper.restoreValue(this, cr, contentValues, destination, key, value);
 
             if (DEBUG) {
-                Log.d(TAG, "Restored setting: " + destination + " : "+ key + "=" + value);
+                Log.d(TAG, "Restored setting: " + destination + " : " + key + "=" + value);
             }
         }
     }
@@ -1031,12 +1116,12 @@
 
             //Will truncate read on a very long file,
             //should not happen for a config file
-            byte[] bytes = new byte[(int)file.length()];
+            byte[] bytes = new byte[(int) file.length()];
 
             int offset = 0;
             int numRead = 0;
             while (offset < bytes.length
-                    && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
+                    && (numRead = is.read(bytes, offset, bytes.length - offset)) >= 0) {
                 offset += numRead;
             }
 
@@ -1057,7 +1142,6 @@
                 }
             }
         }
-
     }
 
     private void restoreFileData(String filename, byte[] bytes, int size) {
@@ -1160,6 +1244,87 @@
         }
     }
 
+    private byte[] getSoftAPConfiguration() {
+        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+        try {
+            return wifiManager.getWifiApConfiguration().getBytesForBackup();
+        } catch (IOException ioe) {
+            Log.e(TAG, "Failed to marshal SoftAPConfiguration" + ioe.getMessage());
+            return new byte[0];
+        }
+    }
+
+    private void restoreSoftApConfiguration(byte[] data) {
+        WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
+        try {
+            WifiConfiguration config = WifiConfiguration
+                    .getWifiConfigFromBackup(new DataInputStream(new ByteArrayInputStream(data)));
+            if (DEBUG) Log.d(TAG, "Successfully unMarshaled WifiConfiguration ");
+            wifiManager.setWifiApConfiguration(config);
+        } catch (IOException | BackupUtils.BadVersionException e) {
+            Log.e(TAG, "Failed to unMarshal SoftAPConfiguration " + e.getMessage());
+        }
+    }
+
+    private byte[] getNetworkPolicies() {
+        NetworkPolicyManager networkPolicyManager =
+                (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
+        NetworkPolicy[] policies = networkPolicyManager.getNetworkPolicies();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        if (policies != null && policies.length != 0) {
+            DataOutputStream out = new DataOutputStream(baos);
+            try {
+                out.writeInt(NETWORK_POLICIES_BACKUP_VERSION);
+                out.writeInt(policies.length);
+                for (NetworkPolicy policy : policies) {
+                    if (policy != null) {
+                        byte[] marshaledPolicy = policy.getBytesForBackup();
+                        out.writeByte(BackupUtils.NOT_NULL);
+                        out.writeInt(marshaledPolicy.length);
+                        out.write(marshaledPolicy);
+                    } else {
+                        out.writeByte(BackupUtils.NULL);
+                    }
+                }
+            } catch (IOException ioe) {
+                Log.e(TAG, "Failed to convert NetworkPolicies to byte array " + ioe.getMessage());
+                baos.reset();
+            }
+        }
+        return baos.toByteArray();
+    }
+
+    private void restoreNetworkPolicies(byte[] data) {
+        NetworkPolicyManager networkPolicyManager =
+                (NetworkPolicyManager) getSystemService(NETWORK_POLICY_SERVICE);
+        if (data != null && data.length != 0) {
+            DataInputStream in = new DataInputStream(new ByteArrayInputStream(data));
+            try {
+                int version = in.readInt();
+                if (version < 1 || version > NETWORK_POLICIES_BACKUP_VERSION) {
+                    throw new BackupUtils.BadVersionException(
+                            "Unknown Backup Serialization Version");
+                }
+                int length = in.readInt();
+                NetworkPolicy[] policies = new NetworkPolicy[length];
+                for (int i = 0; i < length; i++) {
+                    byte isNull = in.readByte();
+                    if (isNull == BackupUtils.NULL) continue;
+                    int byteLength = in.readInt();
+                    byte[] policyData = new byte[byteLength];
+                    in.read(policyData, 0, byteLength);
+                    policies[i] = NetworkPolicy.getNetworkPolicyFromBackup(
+                            new DataInputStream(new ByteArrayInputStream(policyData)));
+                }
+                // Only set the policies if there was no error in the restore operation
+                networkPolicyManager.setNetworkPolicies(policies);
+            } catch (NullPointerException | IOException | BackupUtils.BadVersionException e) {
+                // NPE can be thrown when trying to instantiate a NetworkPolicy
+                Log.e(TAG, "Failed to convert byte array to NetworkPolicies " + e.getMessage());
+            }
+        }
+    }
+
     /**
      * Write an int in BigEndian into the byte array.
      * @param out byte array
@@ -1181,11 +1346,10 @@
     }
 
     private int readInt(byte[] in, int pos) {
-        int result =
-                ((in[pos    ] & 0xFF) << 24) |
-                ((in[pos + 1] & 0xFF) << 16) |
-                ((in[pos + 2] & 0xFF) <<  8) |
-                ((in[pos + 3] & 0xFF) <<  0);
+        int result = ((in[pos] & 0xFF) << 24)
+                | ((in[pos + 1] & 0xFF) << 16)
+                | ((in[pos + 2] & 0xFF) <<  8)
+                | ((in[pos + 3] & 0xFF) <<  0);
         return result;
     }
 
@@ -1202,4 +1366,4 @@
         }
         return WifiManager.WIFI_STATE_UNKNOWN;
     }
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
index a7fdadc..942ba59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileDataControllerImpl.java
@@ -218,7 +218,7 @@
     private static String getActiveSubscriberId(Context context) {
         final TelephonyManager tele = TelephonyManager.from(context);
         final String actualSubscriberId = tele.getSubscriberId(
-                SubscriptionManager.getDefaultDataSubId());
+                SubscriptionManager.getDefaultDataSubscriptionId());
         return actualSubscriberId;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 2996808..288fe72 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -811,11 +811,11 @@
 
     public static class SubscriptionDefaults {
         public int getDefaultVoiceSubId() {
-            return SubscriptionManager.getDefaultVoiceSubId();
+            return SubscriptionManager.getDefaultVoiceSubscriptionId();
         }
 
         public int getDefaultDataSubId() {
-            return SubscriptionManager.getDefaultDataSubId();
+            return SubscriptionManager.getDefaultDataSubscriptionId();
         }
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 327fb8a..9c09f24 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3678,6 +3678,12 @@
             throw new IllegalArgumentException("Bad timeout specified");
         }
 
+        if (NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER
+                .equals(networkCapabilities.getNetworkSpecifier())) {
+            throw new IllegalArgumentException("Invalid network specifier - must not be '"
+                    + NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER + "'");
+        }
+
         NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
                 nextNetworkRequestId());
         NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder,
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 19a4851..8083bf0 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -262,7 +262,8 @@
                 mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, userHandle, 0));
             } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) {
                 Integer newDefaultSubIdObj = new Integer(intent.getIntExtra(
-                        PhoneConstants.SUBSCRIPTION_KEY, SubscriptionManager.getDefaultSubId()));
+                        PhoneConstants.SUBSCRIPTION_KEY,
+                        SubscriptionManager.getDefaultSubscriptionId()));
                 int newDefaultPhoneId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
                     SubscriptionManager.getPhoneId(mDefaultSubId));
                 if (DBG) {
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
new file mode 100644
index 0000000..f6dc9b9
--- /dev/null
+++ b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import com.android.server.SystemService;
+
+import android.content.Context;
+import android.net.ConnectivityMetricsEvent;
+import android.net.ConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLogger;
+import android.net.IConnectivityMetricsLoggerSubscriber;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.ArrayMap;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** {@hide} */
+public class MetricsLoggerService extends SystemService {
+    private static String TAG = "ConnectivityMetricsLoggerService";
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    public MetricsLoggerService(Context context) {
+        super(context);
+    }
+
+    @Override
+    public void onStart() {
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
+            Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
+            publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
+                    mBinder);
+        }
+    }
+
+    private final int MAX_NUMBER_OF_EVENTS = 100;
+    private final int MAX_TIME_OFFSET = 15*60*1000; // 15 minutes
+    private final List<ConnectivityMetricsEvent> mEvents = new ArrayList<>();
+    private long mLastSentEventTimeMillis = System.currentTimeMillis();
+
+    private final void enforceConnectivityInternalPermission() {
+        getContext().enforceCallingPermission(
+                android.Manifest.permission.CONNECTIVITY_INTERNAL,
+                "MetricsLoggerService");
+    }
+
+    /**
+     * Implementation of the IConnectivityMetricsLogger interface.
+     */
+    private final IConnectivityMetricsLogger.Stub mBinder = new IConnectivityMetricsLogger.Stub() {
+
+        private final ArrayMap<IConnectivityMetricsLoggerSubscriber,
+                IBinder.DeathRecipient> mSubscribers = new ArrayMap<>();
+
+
+        private ConnectivityMetricsEvent[] prepareEventsToSendIfReady() {
+            ConnectivityMetricsEvent[] eventsToSend = null;
+            final long currentTimeMillis = System.currentTimeMillis();
+            final long timeOffset = currentTimeMillis - mLastSentEventTimeMillis;
+            if (timeOffset >= MAX_TIME_OFFSET
+                    || timeOffset < 0 // system time has changed
+                    || mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
+                // batch events
+                mLastSentEventTimeMillis = currentTimeMillis;
+                eventsToSend = new ConnectivityMetricsEvent[mEvents.size()];
+                mEvents.toArray(eventsToSend);
+                mEvents.clear();
+            }
+            return eventsToSend;
+        }
+
+        private void maybeSendEventsToSubscribers(ConnectivityMetricsEvent[] eventsToSend) {
+            if (eventsToSend == null || eventsToSend.length == 0) return;
+            synchronized (mSubscribers) {
+                for (IConnectivityMetricsLoggerSubscriber s : mSubscribers.keySet()) {
+                    try {
+                        s.onEvents(eventsToSend);
+                    } catch (RemoteException ex) {
+                        Log.e(TAG, "RemoteException " + ex);
+                    }
+                }
+            }
+        }
+
+        public void logEvent(ConnectivityMetricsEvent event) {
+            ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
+            logEvents(events);
+        }
+
+        public void logEvents(ConnectivityMetricsEvent[] events) {
+            enforceConnectivityInternalPermission();
+            ConnectivityMetricsEvent[] eventsToSend;
+
+            if (VDBG) {
+                for (ConnectivityMetricsEvent e : events) {
+                    Log.v(TAG, "writeEvent(" + e.toString() + ")");
+                }
+            }
+
+            synchronized (mEvents) {
+                for (ConnectivityMetricsEvent e : events) {
+                    mEvents.add(e);
+                }
+
+                eventsToSend = prepareEventsToSendIfReady();
+            }
+
+            maybeSendEventsToSubscribers(eventsToSend);
+        }
+
+        public boolean subscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
+            enforceConnectivityInternalPermission();
+            if (VDBG) Log.v(TAG, "subscribe");
+
+            synchronized (mSubscribers) {
+                if (mSubscribers.containsKey(subscriber)) {
+                    Log.e(TAG, "subscriber is already subscribed");
+                    return false;
+                }
+                final IConnectivityMetricsLoggerSubscriber s = subscriber;
+                IBinder.DeathRecipient dr = new IBinder.DeathRecipient() {
+                    @Override
+                    public void binderDied() {
+                        if (VDBG) Log.v(TAG, "subscriber died");
+                        synchronized (mSubscribers) {
+                            mSubscribers.remove(s);
+                        }
+                    }
+                };
+
+                try {
+                    subscriber.asBinder().linkToDeath(dr, 0);
+                    mSubscribers.put(subscriber, dr);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "subscribe failed: " + e);
+                    return false;
+                }
+            }
+
+            return true;
+        }
+
+        public void unsubscribe(IConnectivityMetricsLoggerSubscriber subscriber) {
+            enforceConnectivityInternalPermission();
+            if (VDBG) Log.v(TAG, "unsubscribe");
+            synchronized (mSubscribers) {
+                IBinder.DeathRecipient dr = mSubscribers.remove(subscriber);
+                if (dr == null) {
+                    Log.e(TAG, "subscriber is not subscribed");
+                    return;
+                }
+                subscriber.asBinder().unlinkToDeath(dr, 0);
+            }
+        }
+    };
+}
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 5fd39c0..dc62609 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -49,7 +49,9 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Random;
 
@@ -107,27 +109,33 @@
     // so callers can wait for completion.
     private final CountDownLatch mCountDownLatch;
 
-    private class Measurement {
+    public class Measurement {
         private static final String SUCCEEDED = "SUCCEEDED";
         private static final String FAILED = "FAILED";
 
-        // TODO: Refactor to make these private for better encapsulation.
-        public String description = "";
-        public long startTime;
-        public long finishTime;
-        public String result = "";
-        public Thread thread;
+        private boolean succeeded;
 
-        public void recordSuccess(String msg) {
+        // Package private.  TODO: investigate better encapsulation.
+        String description = "";
+        long startTime;
+        long finishTime;
+        String result = "";
+        Thread thread;
+
+        public boolean checkSucceeded() { return succeeded; }
+
+        void recordSuccess(String msg) {
             maybeFixupTimes();
+            succeeded = true;
             result = SUCCEEDED + ": " + msg;
             if (mCountDownLatch != null) {
                 mCountDownLatch.countDown();
             }
         }
 
-        public void recordFailure(String msg) {
+        void recordFailure(String msg) {
             maybeFixupTimes();
+            succeeded = false;
             result = FAILED + ": " + msg;
             if (mCountDownLatch != null) {
                 mCountDownLatch.countDown();
@@ -265,6 +273,51 @@
         } catch (InterruptedException ignored) {}
     }
 
+    public List<Measurement> getMeasurements() {
+        // TODO: Consider moving waitForMeasurements() in here to minimize the
+        // chance of caller errors.
+
+        ArrayList<Measurement> measurements = new ArrayList(totalMeasurementCount());
+
+        // Sort measurements IPv4 first.
+        for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
+            if (entry.getKey() instanceof Inet4Address) {
+                measurements.add(entry.getValue());
+            }
+        }
+        for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
+                mExplicitSourceIcmpChecks.entrySet()) {
+            if (entry.getKey().first instanceof Inet4Address) {
+                measurements.add(entry.getValue());
+            }
+        }
+        for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
+            if (entry.getKey() instanceof Inet4Address) {
+                measurements.add(entry.getValue());
+            }
+        }
+
+        // IPv6 measurements second.
+        for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
+            if (entry.getKey() instanceof Inet6Address) {
+                measurements.add(entry.getValue());
+            }
+        }
+        for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
+                mExplicitSourceIcmpChecks.entrySet()) {
+            if (entry.getKey().first instanceof Inet6Address) {
+                measurements.add(entry.getValue());
+            }
+        }
+        for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
+            if (entry.getKey() instanceof Inet6Address) {
+                measurements.add(entry.getValue());
+            }
+        }
+
+        return measurements;
+    }
+
     public void dump(IndentingPrintWriter pw) {
         pw.println(TAG + ":" + mDescription);
         final long unfinished = mCountDownLatch.getCount();
@@ -276,30 +329,13 @@
         }
 
         pw.increaseIndent();
-        for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
-            if (entry.getKey() instanceof Inet4Address) {
-                pw.println(entry.getValue().toString());
-            }
+
+        String prefix;
+        for (Measurement m : getMeasurements()) {
+            prefix = m.checkSucceeded() ? "." : "F";
+            pw.println(prefix + "  " + m.toString());
         }
-        for (Map.Entry<InetAddress, Measurement> entry : mIcmpChecks.entrySet()) {
-            if (entry.getKey() instanceof Inet6Address) {
-                pw.println(entry.getValue().toString());
-            }
-        }
-        for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
-                mExplicitSourceIcmpChecks.entrySet()) {
-            pw.println(entry.getValue().toString());
-        }
-        for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
-            if (entry.getKey() instanceof Inet4Address) {
-                pw.println(entry.getValue().toString());
-            }
-        }
-        for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
-            if (entry.getKey() instanceof Inet6Address) {
-                pw.println(entry.getValue().toString());
-            }
-        }
+
         pw.decreaseIndent();
     }
 
diff --git a/services/core/java/com/android/server/net/IpConfigStore.java b/services/core/java/com/android/server/net/IpConfigStore.java
index 90e26d8..9f1435a 100644
--- a/services/core/java/com/android/server/net/IpConfigStore.java
+++ b/services/core/java/com/android/server/net/IpConfigStore.java
@@ -59,8 +59,12 @@
 
     protected static final int IPCONFIG_FILE_VERSION = 2;
 
+    public IpConfigStore(DelayedDiskWrite writer) {
+        mWriter = writer;
+    }
+
     public IpConfigStore() {
-        mWriter = new DelayedDiskWrite();
+        this(new DelayedDiskWrite());
     }
 
     private boolean writeConfig(DataOutputStream out, int configKey,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 81c5a1a..09a1100 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -56,6 +56,7 @@
 import com.android.server.audio.AudioService;
 import com.android.server.camera.CameraService;
 import com.android.server.clipboard.ClipboardService;
+import com.android.server.connectivity.MetricsLoggerService;
 import com.android.server.content.ContentService;
 import com.android.server.devicepolicy.DevicePolicyManagerService;
 import com.android.server.display.DisplayManagerService;
@@ -552,6 +553,10 @@
             } else {
                 mSystemServiceManager.startService(BluetoothService.class);
             }
+
+            traceBeginAndSlog("ConnectivityMetricsLoggerService");
+            mSystemServiceManager.startService(MetricsLoggerService.class);
+            Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
         } catch (RuntimeException e) {
             Slog.e("System", "******************************************");
             Slog.e("System", "************ Failure starting core service", e);
diff --git a/services/net/java/android/net/apf/ApfGenerator.java b/services/net/java/android/net/apf/ApfGenerator.java
new file mode 100644
index 0000000..96c2ba5
--- /dev/null
+++ b/services/net/java/android/net/apf/ApfGenerator.java
@@ -0,0 +1,883 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.apf;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+/**
+ * APF assembler/generator.  A tool for generating an APF program.
+ *
+ * Call add*() functions to add instructions to the program, then call
+ * {@link generate} to get the APF bytecode for the program.
+ *
+ * @hide
+ */
+public class ApfGenerator {
+    /**
+     * This exception is thrown when an attempt is made to generate an illegal instruction.
+     */
+    public static class IllegalInstructionException extends Exception {
+        IllegalInstructionException(String msg) {
+            super(msg);
+        }
+    }
+    private enum Opcodes {
+        LABEL(-1),
+        LDB(1),    // Load 1 byte from immediate offset, e.g. "ldb R0, [5]"
+        LDH(2),    // Load 2 bytes from immediate offset, e.g. "ldh R0, [5]"
+        LDW(3),    // Load 4 bytes from immediate offset, e.g. "ldw R0, [5]"
+        LDBX(4),   // Load 1 byte from immediate offset plus register, e.g. "ldbx R0, [5]R0"
+        LDHX(5),   // Load 2 byte from immediate offset plus register, e.g. "ldhx R0, [5]R0"
+        LDWX(6),   // Load 4 byte from immediate offset plus register, e.g. "ldwx R0, [5]R0"
+        ADD(7),    // Add, e.g. "add R0,5"
+        MUL(8),    // Multiply, e.g. "mul R0,5"
+        DIV(9),    // Divide, e.g. "div R0,5"
+        AND(10),   // And, e.g. "and R0,5"
+        OR(11),    // Or, e.g. "or R0,5"
+        SH(12),    // Left shift, e.g, "sh R0, 5" or "sh R0, -5" (shifts right)
+        LI(13),    // Load immediate, e.g. "li R0,5" (immediate encoded as signed value)
+        JMP(14),   // Jump, e.g. "jmp label"
+        JEQ(15),   // Compare equal and branch, e.g. "jeq R0,5,label"
+        JNE(16),   // Compare not equal and branch, e.g. "jne R0,5,label"
+        JGT(17),   // Compare greater than and branch, e.g. "jgt R0,5,label"
+        JLT(18),   // Compare less than and branch, e.g. "jlt R0,5,label"
+        JSET(19),  // Compare any bits set and branch, e.g. "jset R0,5,label"
+        JNEBS(20), // Compare not equal byte sequence, e.g. "jnebs R0,5,label,0x1122334455"
+        EXT(21);   // Followed by immediate indicating ExtendedOpcodes.
+
+        final int value;
+
+        private Opcodes(int value) {
+            this.value = value;
+        }
+    }
+    // Extended opcodes. Primary opcode is Opcodes.EXT. ExtendedOpcodes are encoded in the immediate
+    // field.
+    private enum ExtendedOpcodes {
+        LDM(0),   // Load from memory, e.g. "ldm R0,5"
+        STM(16),  // Store to memory, e.g. "stm R0,5"
+        NOT(32),  // Not, e.g. "not R0"
+        NEG(33),  // Negate, e.g. "neg R0"
+        SWAP(34), // Swap, e.g. "swap R0,R1"
+        MOVE(35);  // Move, e.g. "move R0,R1"
+
+        final int value;
+
+        private ExtendedOpcodes(int value) {
+            this.value = value;
+        }
+    }
+    public enum Register {
+        R0(0),
+        R1(1);
+
+        final int value;
+
+        private Register(int value) {
+            this.value = value;
+        }
+    }
+    private class Instruction {
+        private final byte mOpcode;   // A "Opcode" value.
+        private final byte mRegister; // A "Register" value.
+        private boolean mHasImm;
+        private byte mImmSize;
+        private boolean mImmSigned;
+        private int mImm;
+        // When mOpcode is a jump:
+        private byte mTargetLabelSize;
+        private String mTargetLabel;
+        // When mOpcode == Opcodes.LABEL:
+        private String mLabel;
+        // When mOpcode == Opcodes.JNEBS:
+        private byte[] mCompareBytes;
+        // Offset in bytes from the begining of this program. Set by {@link ApfGenerator#generate}.
+        int offset;
+
+        Instruction(Opcodes opcode, Register register) {
+            mOpcode = (byte)opcode.value;
+            mRegister = (byte)register.value;
+        }
+
+        Instruction(Opcodes opcode) {
+            this(opcode, Register.R0);
+        }
+
+        void setImm(int imm, boolean signed) {
+            mHasImm = true;
+            mImm = imm;
+            mImmSigned = signed;
+            mImmSize = calculateImmSize(imm, signed);
+        }
+
+        void setUnsignedImm(int imm) {
+            setImm(imm, false);
+        }
+
+        void setSignedImm(int imm) {
+            setImm(imm, true);
+        }
+
+        void setLabel(String label) throws IllegalInstructionException {
+            if (mLabels.containsKey(label)) {
+                throw new IllegalInstructionException("duplicate label " + label);
+            }
+            if (mOpcode != Opcodes.LABEL.value) {
+                throw new IllegalStateException("adding label to non-label instruction");
+            }
+            mLabel = label;
+            mLabels.put(label, this);
+        }
+
+        void setTargetLabel(String label) {
+            mTargetLabel = label;
+            mTargetLabelSize = 4; // May shrink later on in generate().
+        }
+
+        void setCompareBytes(byte[] bytes) {
+            if (mOpcode != Opcodes.JNEBS.value) {
+                throw new IllegalStateException("adding compare bytes to non-JNEBS instruction");
+            }
+            mCompareBytes = bytes;
+        }
+
+        /**
+         * @return size of instruction in bytes.
+         */
+        int size() {
+            if (mOpcode == Opcodes.LABEL.value) {
+                return 0;
+            }
+            int size = 1;
+            if (mHasImm) {
+                size += generatedImmSize();
+            }
+            if (mTargetLabel != null) {
+                size += generatedImmSize();
+            }
+            if (mCompareBytes != null) {
+                size += mCompareBytes.length;
+            }
+            return size;
+        }
+
+        /**
+         * Resize immediate value field so that it's only as big as required to
+         * contain the offset of the jump destination.
+         * @return {@code true} if shrunk.
+         */
+        boolean shrink() throws IllegalInstructionException {
+            if (mTargetLabel == null) {
+                return false;
+            }
+            int oldSize = size();
+            int oldTargetLabelSize = mTargetLabelSize;
+            mTargetLabelSize = calculateImmSize(calculateTargetLabelOffset(), false);
+            if (mTargetLabelSize > oldTargetLabelSize) {
+                throw new IllegalStateException("instruction grew");
+            }
+            return size() < oldSize;
+        }
+
+        /**
+         * Assemble value for instruction size field.
+         */
+        private byte generateImmSizeField() {
+            byte immSize = generatedImmSize();
+            // Encode size field to fit in 2 bits: 0->0, 1->1, 2->2, 3->4.
+            return immSize == 4 ? 3 : immSize;
+        }
+
+        /**
+         * Assemble first byte of generated instruction.
+         */
+        private byte generateInstructionByte() {
+            byte sizeField = generateImmSizeField();
+            return (byte)((mOpcode << 3) | (sizeField << 1) | mRegister);
+        }
+
+        /**
+         * Write {@code value} at offset {@code writingOffset} into {@code bytecode}.
+         * {@link generatedImmSize} bytes are written. {@code value} is truncated to
+         * {@code generatedImmSize} bytes. {@code value} is treated simply as a
+         * 32-bit value, so unsigned values should be zero extended and the truncation
+         * should simply throw away their zero-ed upper bits, and signed values should
+         * be sign extended and the truncation should simply throw away their signed
+         * upper bits.
+         */
+        private int writeValue(int value, byte[] bytecode, int writingOffset) {
+            for (int i = generatedImmSize() - 1; i >= 0; i--) {
+                bytecode[writingOffset++] = (byte)((value >> (i * 8)) & 255);
+            }
+            return writingOffset;
+        }
+
+        /**
+         * Generate bytecode for this instruction at offset {@link offset}.
+         */
+        void generate(byte[] bytecode) throws IllegalInstructionException {
+            if (mOpcode == Opcodes.LABEL.value) {
+                return;
+            }
+            int writingOffset = offset;
+            bytecode[writingOffset++] = generateInstructionByte();
+            if (mTargetLabel != null) {
+                writingOffset = writeValue(calculateTargetLabelOffset(), bytecode, writingOffset);
+            }
+            if (mHasImm) {
+                writingOffset = writeValue(mImm, bytecode, writingOffset);
+            }
+            if (mCompareBytes != null) {
+                System.arraycopy(mCompareBytes, 0, bytecode, writingOffset, mCompareBytes.length);
+                writingOffset += mCompareBytes.length;
+            }
+            if ((writingOffset - offset) != size()) {
+                throw new IllegalStateException("wrote " + (writingOffset - offset) +
+                        " but should have written " + size());
+            }
+        }
+
+        /**
+         * Calculate the size of either the immediate field or the target label field, if either is
+         * present. Most instructions have either an immediate or a target label field, but for the
+         * instructions that have both, the size of the target label field must be the same as the
+         * size of the immediate field, because there is only one length field in the instruction
+         * byte, hence why this function simply takes the maximum of the two sizes, so neither is
+         * truncated.
+         */
+        private byte generatedImmSize() {
+            return mImmSize > mTargetLabelSize ? mImmSize : mTargetLabelSize;
+        }
+
+        private int calculateTargetLabelOffset() throws IllegalInstructionException {
+            Instruction targetLabelInstruction;
+            if (mTargetLabel == DROP_LABEL) {
+                targetLabelInstruction = mDropLabel;
+            } else if (mTargetLabel == PASS_LABEL) {
+                targetLabelInstruction = mPassLabel;
+            } else {
+                targetLabelInstruction = mLabels.get(mTargetLabel);
+            }
+            if (targetLabelInstruction == null) {
+                throw new IllegalInstructionException("label not found: " + mTargetLabel);
+            }
+            // Calculate distance from end of this instruction to instruction.offset.
+            final int targetLabelOffset = targetLabelInstruction.offset - (offset + size());
+            if (targetLabelOffset < 0) {
+                throw new IllegalInstructionException("backward branches disallowed; label: " +
+                        mTargetLabel);
+            }
+            return targetLabelOffset;
+        }
+
+        private byte calculateImmSize(int imm, boolean signed) {
+            if (imm == 0) {
+                return 0;
+            }
+            if (signed && (imm >= -128 && imm <= 127) ||
+                    !signed && (imm >= 0 && imm <= 255)) {
+                return 1;
+            }
+            if (signed && (imm >= -32768 && imm <= 32767) ||
+                    !signed && (imm >= 0 && imm <= 65535)) {
+                return 2;
+            }
+            return 4;
+        }
+    }
+
+    /**
+     * Jump to this label to terminate the program and indicate the packet
+     * should be dropped.
+     */
+    public static final String DROP_LABEL = "__DROP__";
+
+    /**
+     * Jump to this label to terminate the program and indicate the packet
+     * should be passed to the AP.
+     */
+    public static final String PASS_LABEL = "__PASS__";
+
+    /**
+     * Number of memory slots available for access via APF stores to memory and loads from memory.
+     * The memory slots are numbered 0 to {@code MEMORY_SLOTS} - 1. This must be kept in sync with
+     * the APF interpreter.
+     */
+    public static final int MEMORY_SLOTS = 16;
+
+    /**
+     * Memory slot number that is prefilled with the IPv4 header length.
+     * Note that this memory slot may be overwritten by a program that
+     * executes stores to this memory slot. This must be kept in sync with
+     * the APF interpreter.
+     */
+    public static final int IPV4_HEADER_SIZE_MEMORY_SLOT = 13;
+
+    /**
+     * Memory slot number that is prefilled with the size of the packet being filtered in bytes.
+     * Note that this memory slot may be overwritten by a program that
+     * executes stores to this memory slot. This must be kept in sync with the APF interpreter.
+     */
+    public static final int PACKET_SIZE_MEMORY_SLOT = 14;
+
+    /**
+     * Memory slot number that is prefilled with the age of the filter in seconds. The age of the
+     * filter is the time since the filter was installed until now.
+     * Note that this memory slot may be overwritten by a program that
+     * executes stores to this memory slot. This must be kept in sync with the APF interpreter.
+     */
+    public static final int FILTER_AGE_MEMORY_SLOT = 15;
+
+    /**
+     * First memory slot containing prefilled values. Can be used in range comparisons to determine
+     * if memory slot index is within prefilled slots.
+     */
+    public static final int FIRST_PREFILLED_MEMORY_SLOT = IPV4_HEADER_SIZE_MEMORY_SLOT;
+
+    /**
+     * Last memory slot containing prefilled values. Can be used in range comparisons to determine
+     * if memory slot index is within prefilled slots.
+     */
+    public static final int LAST_PREFILLED_MEMORY_SLOT = FILTER_AGE_MEMORY_SLOT;
+
+    private final ArrayList<Instruction> mInstructions = new ArrayList<Instruction>();
+    private final HashMap<String, Instruction> mLabels = new HashMap<String, Instruction>();
+    private final Instruction mDropLabel = new Instruction(Opcodes.LABEL);
+    private final Instruction mPassLabel = new Instruction(Opcodes.LABEL);
+    private boolean mGenerated;
+
+    /**
+     * Set version of APF instruction set to generate instructions for. Returns {@code true}
+     * if generating for this version is supported, {@code false} otherwise.
+     */
+    public boolean setApfVersion(int version) {
+        // This version number syncs up with APF_VERSION in hardware/google/apf/apf_interpreter.h
+        return version == 2;
+    }
+
+    private void addInstruction(Instruction instruction) {
+        if (mGenerated) {
+            throw new IllegalStateException("Program already generated");
+        }
+        mInstructions.add(instruction);
+    }
+
+    /**
+     * Define a label at the current end of the program. Jumps can jump to this label. Labels are
+     * their own separate instructions, though with size 0. This facilitates having labels with
+     * no corresponding code to execute, for example a label at the end of a program. For example
+     * an {@link ApfGenerator} might be passed to a function that adds a filter like so:
+     * <pre>
+     *   load from packet
+     *   compare loaded data, jump if not equal to "next_filter"
+     *   load from packet
+     *   compare loaded data, jump if not equal to "next_filter"
+     *   jump to drop label
+     *   define "next_filter" here
+     * </pre>
+     * In this case "next_filter" may not have any generated code associated with it.
+     */
+    public ApfGenerator defineLabel(String name) throws IllegalInstructionException {
+        Instruction instruction = new Instruction(Opcodes.LABEL);
+        instruction.setLabel(name);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an unconditional jump instruction to the end of the program.
+     */
+    public ApfGenerator addJump(String target) {
+        Instruction instruction = new Instruction(Opcodes.JMP);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to load the byte at offset {@code offset}
+     * bytes from the begining of the packet into {@code register}.
+     */
+    public ApfGenerator addLoad8(Register register, int offset) {
+        Instruction instruction = new Instruction(Opcodes.LDB, register);
+        instruction.setUnsignedImm(offset);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to load 16-bits at offset {@code offset}
+     * bytes from the begining of the packet into {@code register}.
+     */
+    public ApfGenerator addLoad16(Register register, int offset) {
+        Instruction instruction = new Instruction(Opcodes.LDH, register);
+        instruction.setUnsignedImm(offset);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to load 32-bits at offset {@code offset}
+     * bytes from the begining of the packet into {@code register}.
+     */
+    public ApfGenerator addLoad32(Register register, int offset) {
+        Instruction instruction = new Instruction(Opcodes.LDW, register);
+        instruction.setUnsignedImm(offset);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to load a byte from the packet into
+     * {@code register}. The offset of the loaded byte from the begining of the packet is
+     * the sum of {@code offset} and the value in register R1.
+     */
+    public ApfGenerator addLoad8Indexed(Register register, int offset) {
+        Instruction instruction = new Instruction(Opcodes.LDBX, register);
+        instruction.setUnsignedImm(offset);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to load 16-bits from the packet into
+     * {@code register}. The offset of the loaded 16-bits from the begining of the packet is
+     * the sum of {@code offset} and the value in register R1.
+     */
+    public ApfGenerator addLoad16Indexed(Register register, int offset) {
+        Instruction instruction = new Instruction(Opcodes.LDHX, register);
+        instruction.setUnsignedImm(offset);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to load 32-bits from the packet into
+     * {@code register}. The offset of the loaded 32-bits from the begining of the packet is
+     * the sum of {@code offset} and the value in register R1.
+     */
+    public ApfGenerator addLoad32Indexed(Register register, int offset) {
+        Instruction instruction = new Instruction(Opcodes.LDWX, register);
+        instruction.setUnsignedImm(offset);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to add {@code value} to register R0.
+     */
+    public ApfGenerator addAdd(int value) {
+        Instruction instruction = new Instruction(Opcodes.ADD);
+        instruction.setSignedImm(value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to multiply register R0 by {@code value}.
+     */
+    public ApfGenerator addMul(int value) {
+        Instruction instruction = new Instruction(Opcodes.MUL);
+        instruction.setSignedImm(value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to divide register R0 by {@code value}.
+     */
+    public ApfGenerator addDiv(int value) {
+        Instruction instruction = new Instruction(Opcodes.DIV);
+        instruction.setSignedImm(value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to logically and register R0 with {@code value}.
+     */
+    public ApfGenerator addAnd(int value) {
+        Instruction instruction = new Instruction(Opcodes.AND);
+        instruction.setUnsignedImm(value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to logically or register R0 with {@code value}.
+     */
+    public ApfGenerator addOr(int value) {
+        Instruction instruction = new Instruction(Opcodes.OR);
+        instruction.setUnsignedImm(value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to shift left register R0 by {@code value} bits.
+     */
+    public ApfGenerator addLeftShift(int value) {
+        Instruction instruction = new Instruction(Opcodes.SH);
+        instruction.setSignedImm(value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to shift right register R0 by {@code value}
+     * bits.
+     */
+    public ApfGenerator addRightShift(int value) {
+        Instruction instruction = new Instruction(Opcodes.SH);
+        instruction.setSignedImm(-value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to add register R1 to register R0.
+     */
+    public ApfGenerator addAddR1() {
+        Instruction instruction = new Instruction(Opcodes.ADD, Register.R1);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to multiply register R0 by register R1.
+     */
+    public ApfGenerator addMulR1() {
+        Instruction instruction = new Instruction(Opcodes.MUL, Register.R1);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to divide register R0 by register R1.
+     */
+    public ApfGenerator addDivR1() {
+        Instruction instruction = new Instruction(Opcodes.DIV, Register.R1);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to logically and register R0 with register R1
+     * and store the result back into register R0.
+     */
+    public ApfGenerator addAndR1() {
+        Instruction instruction = new Instruction(Opcodes.AND, Register.R1);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to logically or register R0 with register R1
+     * and store the result back into register R0.
+     */
+    public ApfGenerator addOrR1() {
+        Instruction instruction = new Instruction(Opcodes.OR, Register.R1);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to shift register R0 left by the value in
+     * register R1.
+     */
+    public ApfGenerator addLeftShiftR1() {
+        Instruction instruction = new Instruction(Opcodes.SH, Register.R1);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to move {@code value} into {@code register}.
+     */
+    public ApfGenerator addLoadImmediate(Register register, int value) {
+        Instruction instruction = new Instruction(Opcodes.LI, register);
+        instruction.setSignedImm(value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value equals {@code value}.
+     */
+    public ApfGenerator addJumpIfR0Equals(int value, String target) {
+        Instruction instruction = new Instruction(Opcodes.JEQ);
+        instruction.setUnsignedImm(value);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value does not equal {@code value}.
+     */
+    public ApfGenerator addJumpIfR0NotEquals(int value, String target) {
+        Instruction instruction = new Instruction(Opcodes.JNE);
+        instruction.setUnsignedImm(value);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value is greater than {@code value}.
+     */
+    public ApfGenerator addJumpIfR0GreaterThan(int value, String target) {
+        Instruction instruction = new Instruction(Opcodes.JGT);
+        instruction.setUnsignedImm(value);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value is less than {@code value}.
+     */
+    public ApfGenerator addJumpIfR0LessThan(int value, String target) {
+        Instruction instruction = new Instruction(Opcodes.JLT);
+        instruction.setUnsignedImm(value);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value has any bits set that are also set in {@code value}.
+     */
+    public ApfGenerator addJumpIfR0AnyBitsSet(int value, String target) {
+        Instruction instruction = new Instruction(Opcodes.JSET);
+        instruction.setUnsignedImm(value);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value equals register R1's value.
+     */
+    public ApfGenerator addJumpIfR0EqualsR1(String target) {
+        Instruction instruction = new Instruction(Opcodes.JEQ, Register.R1);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value does not equal register R1's value.
+     */
+    public ApfGenerator addJumpIfR0NotEqualsR1(String target) {
+        Instruction instruction = new Instruction(Opcodes.JNE, Register.R1);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value is greater than register R1's value.
+     */
+    public ApfGenerator addJumpIfR0GreaterThanR1(String target) {
+        Instruction instruction = new Instruction(Opcodes.JGT, Register.R1);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value is less than register R1's value.
+     */
+    public ApfGenerator addJumpIfR0LessThanR1(String target) {
+        Instruction instruction = new Instruction(Opcodes.JLT, Register.R1);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if register R0's
+     * value has any bits set that are also set in R1's value.
+     */
+    public ApfGenerator addJumpIfR0AnyBitsSetR1(String target) {
+        Instruction instruction = new Instruction(Opcodes.JSET, Register.R1);
+        instruction.setTargetLabel(target);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to jump to {@code target} if the bytes of the
+     * packet at, an offset specified by {@code register}, match {@code bytes}.
+     */
+    public ApfGenerator addJumpIfBytesNotEqual(Register register, byte[] bytes, String target) {
+        Instruction instruction = new Instruction(Opcodes.JNEBS, register);
+        instruction.setUnsignedImm(bytes.length);
+        instruction.setTargetLabel(target);
+        instruction.setCompareBytes(bytes);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to load memory slot {@code slot} into
+     * {@code register}.
+     */
+    public ApfGenerator addLoadFromMemory(Register register, int slot)
+            throws IllegalInstructionException {
+        if (slot < 0 || slot > (MEMORY_SLOTS - 1)) {
+            throw new IllegalInstructionException("illegal memory slot number: " + slot);
+        }
+        Instruction instruction = new Instruction(Opcodes.EXT, register);
+        instruction.setUnsignedImm(ExtendedOpcodes.LDM.value + slot);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to store {@code register} into memory slot
+     * {@code slot}.
+     */
+    public ApfGenerator addStoreToMemory(Register register, int slot)
+            throws IllegalInstructionException {
+        if (slot < 0 || slot > (MEMORY_SLOTS - 1)) {
+            throw new IllegalInstructionException("illegal memory slot number: " + slot);
+        }
+        Instruction instruction = new Instruction(Opcodes.EXT, register);
+        instruction.setUnsignedImm(ExtendedOpcodes.STM.value + slot);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to logically not {@code register}.
+     */
+    public ApfGenerator addNot(Register register) {
+        Instruction instruction = new Instruction(Opcodes.EXT, register);
+        instruction.setUnsignedImm(ExtendedOpcodes.NOT.value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to negate {@code register}.
+     */
+    public ApfGenerator addNeg(Register register) {
+        Instruction instruction = new Instruction(Opcodes.EXT, register);
+        instruction.setUnsignedImm(ExtendedOpcodes.NEG.value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to swap the values in register R0 and register R1.
+     */
+    public ApfGenerator addSwap() {
+        Instruction instruction = new Instruction(Opcodes.EXT);
+        instruction.setUnsignedImm(ExtendedOpcodes.SWAP.value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Add an instruction to the end of the program to move the value into
+     * {@code register} from the other register.
+     */
+    public ApfGenerator addMove(Register register) {
+        Instruction instruction = new Instruction(Opcodes.EXT, register);
+        instruction.setUnsignedImm(ExtendedOpcodes.MOVE.value);
+        addInstruction(instruction);
+        return this;
+    }
+
+    /**
+     * Updates instruction offset fields using latest instruction sizes.
+     * @return current program length in bytes.
+     */
+    private int updateInstructionOffsets() {
+        int offset = 0;
+        for (Instruction instruction : mInstructions) {
+            instruction.offset = offset;
+            offset += instruction.size();
+        }
+        return offset;
+    }
+
+    /**
+     * Returns an overestimate of the size of the generated program. {@link #generate} may return
+     * a program that is smaller.
+     */
+    public int programLengthOverEstimate() {
+        return updateInstructionOffsets();
+    }
+
+    /**
+     * Generate the bytecode for the APF program.
+     * @return the bytecode.
+     * @throws IllegalStateException if a label is referenced but not defined.
+     */
+    public byte[] generate() throws IllegalInstructionException {
+        // Enforce that we can only generate once because we cannot unshrink instructions and
+        // PASS/DROP labels may move further away requiring unshrinking if we add further
+        // instructions.
+        if (mGenerated) {
+            throw new IllegalStateException("Can only generate() once!");
+        }
+        mGenerated = true;
+        int total_size;
+        boolean shrunk;
+        // Shrink the immediate value fields of instructions.
+        // As we shrink the instructions some branch offset
+        // fields may shrink also, thereby shrinking the
+        // instructions further. Loop until we've reached the
+        // minimum size. Rarely will this loop more than a few times.
+        // Limit iterations to avoid O(n^2) behavior.
+        int iterations_remaining = 10;
+        do {
+            total_size = updateInstructionOffsets();
+            // Update drop and pass label offsets.
+            mDropLabel.offset = total_size + 1;
+            mPassLabel.offset = total_size;
+            // Limit run-time in aberant circumstances.
+            if (iterations_remaining-- == 0) break;
+            // Attempt to shrink instructions.
+            shrunk = false;
+            for (Instruction instruction : mInstructions) {
+                if (instruction.shrink()) {
+                    shrunk = true;
+                }
+            }
+        } while (shrunk);
+        // Generate bytecode for instructions.
+        byte[] bytecode = new byte[total_size];
+        for (Instruction instruction : mInstructions) {
+            instruction.generate(bytecode);
+        }
+        return bytecode;
+    }
+}
+
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index c9efc69..7fc6c5b 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -19,6 +19,7 @@
 import com.android.internal.util.HexDump;
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
+import com.android.internal.util.MessageUtils;
 import com.android.internal.util.StateMachine;
 
 import android.app.AlarmManager;
@@ -28,15 +29,12 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.DhcpResults;
-import android.net.BaseDhcpStateMachine;
-import android.net.DhcpStateMachine;
 import android.net.InterfaceConfiguration;
 import android.net.LinkAddress;
 import android.net.NetworkUtils;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Message;
-import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -44,16 +42,15 @@
 import android.system.Os;
 import android.system.PacketSocketAddress;
 import android.util.Log;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.lang.Thread;
 import java.net.Inet4Address;
-import java.net.InetSocketAddress;
 import java.net.NetworkInterface;
 import java.net.SocketException;
-import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.util.Arrays;
 import java.util.Random;
@@ -86,7 +83,7 @@
  *
  * @hide
  */
-public class DhcpClient extends BaseDhcpStateMachine {
+public class DhcpClient extends StateMachine {
 
     private static final String TAG = "DhcpClient";
     private static final boolean DBG = true;
@@ -105,12 +102,40 @@
     // t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
     private static final int DHCP_TIMEOUT_MS    =  36 * SECONDS;
 
+    private static final int PUBLIC_BASE = Protocol.BASE_DHCP;
+
+    /* Commands from controller to start/stop DHCP */
+    public static final int CMD_START_DHCP                  = PUBLIC_BASE + 1;
+    public static final int CMD_STOP_DHCP                   = PUBLIC_BASE + 2;
+    public static final int CMD_RENEW_DHCP                  = PUBLIC_BASE + 3;
+
+    /* Notification from DHCP state machine prior to DHCP discovery/renewal */
+    public static final int CMD_PRE_DHCP_ACTION             = PUBLIC_BASE + 4;
+    /* Notification from DHCP state machine post DHCP discovery/renewal. Indicates
+     * success/failure */
+    public static final int CMD_POST_DHCP_ACTION            = PUBLIC_BASE + 5;
+    /* Notification from DHCP state machine before quitting */
+    public static final int CMD_ON_QUIT                     = PUBLIC_BASE + 6;
+
+    /* Command from controller to indicate DHCP discovery/renewal can continue
+     * after pre DHCP action is complete */
+    public static final int CMD_PRE_DHCP_ACTION_COMPLETE    = PUBLIC_BASE + 7;
+
+    /* Message.arg1 arguments to CMD_POST_DHCP notification */
+    public static final int DHCP_SUCCESS = 1;
+    public static final int DHCP_FAILURE = 2;
+
     // Messages.
-    private static final int BASE                 = Protocol.BASE_DHCP + 100;
-    private static final int CMD_KICK             = BASE + 1;
-    private static final int CMD_RECEIVED_PACKET  = BASE + 2;
-    private static final int CMD_TIMEOUT          = BASE + 3;
-    private static final int CMD_ONESHOT_TIMEOUT  = BASE + 4;
+    private static final int PRIVATE_BASE         = Protocol.BASE_DHCP + 100;
+    private static final int CMD_KICK             = PRIVATE_BASE + 1;
+    private static final int CMD_RECEIVED_PACKET  = PRIVATE_BASE + 2;
+    private static final int CMD_TIMEOUT          = PRIVATE_BASE + 3;
+    private static final int CMD_ONESHOT_TIMEOUT  = PRIVATE_BASE + 4;
+
+    // For message logging.
+    private static final Class[] sMessageClasses = { DhcpClient.class };
+    private static final SparseArray<String> sMessageNames =
+            MessageUtils.findMessageNames(sMessageClasses);
 
     // DHCP parameters that we request.
     private static final byte[] REQUESTED_PARAMS = new byte[] {
@@ -210,7 +235,7 @@
         // Used to time out PacketRetransmittingStates.
         mTimeoutIntent = createStateMachineCommandIntent("TIMEOUT", CMD_TIMEOUT);
         // Used to schedule DHCP renews.
-        mRenewIntent = createStateMachineCommandIntent("RENEW", DhcpStateMachine.CMD_RENEW_DHCP);
+        mRenewIntent = createStateMachineCommandIntent("RENEW", CMD_RENEW_DHCP);
         // Used to tell the caller when its request (CMD_START_DHCP or CMD_RENEW_DHCP) timed out.
         // TODO: when the legacy DHCP client is gone, make the client fully asynchronous and
         // remove this.
@@ -218,12 +243,11 @@
                 CMD_ONESHOT_TIMEOUT);
     }
 
-    @Override
     public void registerForPreDhcpNotification() {
         mRegisteredForPreDhcpNotification = true;
     }
 
-    public static BaseDhcpStateMachine makeDhcpStateMachine(
+    public static DhcpClient makeDhcpClient(
             Context context, StateMachine controller, String intf) {
         DhcpClient client = new DhcpClient(context, controller, intf);
         client.start();
@@ -437,13 +461,12 @@
     }
 
     private void notifySuccess() {
-        mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
-                DhcpStateMachine.DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
+        mController.sendMessage(
+                CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, new DhcpResults(mDhcpLease));
     }
 
     private void notifyFailure() {
-        mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
-                DhcpStateMachine.DHCP_FAILURE, 0, null);
+        mController.sendMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0, null);
     }
 
     private void clearDhcpState() {
@@ -457,15 +480,15 @@
      *
      * @hide
      */
-    @Override
     public void doQuit() {
         Log.d(TAG, "doQuit");
         quit();
     }
 
+    @Override
     protected void onQuitting() {
         Log.d(TAG, "onQuitting");
-        mController.sendMessage(DhcpStateMachine.CMD_ON_QUIT);
+        mController.sendMessage(CMD_ON_QUIT);
     }
 
     private void maybeLog(String msg) {
@@ -478,30 +501,7 @@
         }
 
         private String messageName(int what) {
-            switch (what) {
-                case DhcpStateMachine.CMD_START_DHCP:
-                    return "CMD_START_DHCP";
-                case DhcpStateMachine.CMD_STOP_DHCP:
-                    return "CMD_STOP_DHCP";
-                case DhcpStateMachine.CMD_RENEW_DHCP:
-                    return "CMD_RENEW_DHCP";
-                case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
-                    return "CMD_PRE_DHCP_ACTION";
-                case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
-                    return "CMD_PRE_DHCP_ACTION_COMPLETE";
-                case DhcpStateMachine.CMD_POST_DHCP_ACTION:
-                    return "CMD_POST_DHCP_ACTION";
-                case CMD_KICK:
-                    return "CMD_KICK";
-                case CMD_RECEIVED_PACKET:
-                    return "CMD_RECEIVED_PACKET";
-                case CMD_TIMEOUT:
-                    return "CMD_TIMEOUT";
-                case CMD_ONESHOT_TIMEOUT:
-                    return "CMD_ONESHOT_TIMEOUT";
-                default:
-                    return Integer.toString(what);
-            }
+            return sMessageNames.get(what, Integer.toString(what));
         }
 
         private String messageToString(Message message) {
@@ -532,14 +532,14 @@
         @Override
         public void enter() {
             super.enter();
-            mController.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION);
+            mController.sendMessage(CMD_PRE_DHCP_ACTION);
         }
 
         @Override
         public boolean processMessage(Message message) {
             super.processMessage(message);
             switch (message.what) {
-                case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
+                case CMD_PRE_DHCP_ACTION_COMPLETE:
                     transitionTo(mOtherState);
                     return HANDLED;
                 default:
@@ -574,7 +574,7 @@
         public boolean processMessage(Message message) {
             super.processMessage(message);
             switch (message.what) {
-                case DhcpStateMachine.CMD_START_DHCP:
+                case CMD_START_DHCP:
                     scheduleOneshotTimeout();
                     if (mRegisteredForPreDhcpNotification) {
                         transitionTo(mWaitBeforeStartState);
@@ -630,7 +630,7 @@
         public boolean processMessage(Message message) {
             super.processMessage(message);
             switch (message.what) {
-                case DhcpStateMachine.CMD_STOP_DHCP:
+                case CMD_STOP_DHCP:
                     transitionTo(mStoppedState);
                     return HANDLED;
                 case CMD_ONESHOT_TIMEOUT:
@@ -845,7 +845,7 @@
             super.enter();
             cancelOneshotTimeout();
             notifySuccess();
-            // TODO: DhcpStateMachine only supports renewing at 50% of the lease time, and does not
+            // TODO: DhcpStateMachine only supported renewing at 50% of the lease time, and did not
             // support rebinding. Once the legacy DHCP client is gone, fix this.
             scheduleRenew();
         }
@@ -854,7 +854,7 @@
         public boolean processMessage(Message message) {
             super.processMessage(message);
             switch (message.what) {
-                case DhcpStateMachine.CMD_RENEW_DHCP:
+                case CMD_RENEW_DHCP:
                     if (mRegisteredForPreDhcpNotification) {
                         transitionTo(mWaitBeforeRenewalState);
                     } else {
@@ -908,7 +908,7 @@
         }
     }
 
-    // Not implemented. DhcpStateMachine does not implement it either.
+    // Not implemented. DhcpStateMachine did not implement it either.
     class DhcpRebindingState extends LoggingState {
     }
 
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
new file mode 100644
index 0000000..2a90c60
--- /dev/null
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -0,0 +1,886 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.ip;
+
+import com.android.internal.util.MessageUtils;
+
+import android.content.Context;
+import android.net.DhcpResults;
+import android.net.InterfaceConfiguration;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.LinkProperties.ProvisioningChange;
+import android.net.ProxyInfo;
+import android.net.RouteInfo;
+import android.net.StaticIpConfiguration;
+import android.net.dhcp.DhcpClient;
+import android.os.INetworkManagementService;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+import com.android.server.net.NetlinkTracker;
+
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.util.Objects;
+
+
+/**
+ * IpManager
+ *
+ * This class provides the interface to IP-layer provisioning and maintenance
+ * functionality that can be used by transport layers like Wi-Fi, Ethernet,
+ * et cetera.
+ *
+ * [ Lifetime ]
+ * IpManager is designed to be instantiated as soon as the interface name is
+ * known and can be as long-lived as the class containing it (i.e. declaring
+ * it "private final" is okay).
+ *
+ * @hide
+ */
+public class IpManager extends StateMachine {
+    private static final boolean DBG = true;
+    private static final boolean VDBG = false;
+
+    private static final boolean NO_CALLBACKS = false;
+    private static final boolean SEND_CALLBACKS = true;
+
+    // For message logging.
+    private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
+    private static final SparseArray<String> sWhatToString =
+            MessageUtils.findMessageNames(sMessageClasses);
+
+    /**
+     * Callbacks for handling IpManager events.
+     */
+    public static class Callback {
+        // In order to receive onPreDhcpAction(), call #withPreDhcpAction()
+        // when constructing a ProvisioningConfiguration.
+        //
+        // Implementations of onPreDhcpAction() must call
+        // IpManager#completedPreDhcpAction() to indicate that DHCP is clear
+        // to proceed.
+        public void onPreDhcpAction() {}
+        public void onPostDhcpAction() {}
+
+        // This is purely advisory and not an indication of provisioning
+        // success or failure.  This is only here for callers that want to
+        // expose DHCPv4 results to other APIs (e.g., WifiInfo#setInetAddress).
+        // DHCPv4 or static IPv4 configuration failure or success can be
+        // determined by whether or not the passed-in DhcpResults object is
+        // null or not.
+        public void onNewDhcpResults(DhcpResults dhcpResults) {}
+
+        public void onProvisioningSuccess(LinkProperties newLp) {}
+        public void onProvisioningFailure(LinkProperties newLp) {}
+
+        // Invoked on LinkProperties changes.
+        public void onLinkPropertiesChange(LinkProperties newLp) {}
+
+        // Called when the internal IpReachabilityMonitor (if enabled) has
+        // detected the loss of a critical number of required neighbors.
+        public void onReachabilityLost(String logMsg) {}
+
+        // Called when the IpManager state machine terminates.
+        public void onQuit() {}
+    }
+
+    public static class WaitForProvisioningCallback extends Callback {
+        private LinkProperties mCallbackLinkProperties;
+
+        public LinkProperties waitForProvisioning() {
+            synchronized (this) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {}
+                return mCallbackLinkProperties;
+            }
+        }
+
+        @Override
+        public void onProvisioningSuccess(LinkProperties newLp) {
+            synchronized (this) {
+                mCallbackLinkProperties = newLp;
+                notify();
+            }
+        }
+
+        @Override
+        public void onProvisioningFailure(LinkProperties newLp) {
+            synchronized (this) {
+                mCallbackLinkProperties = null;
+                notify();
+            }
+        }
+    }
+
+    /**
+     * This class encapsulates parameters to be passed to
+     * IpManager#startProvisioning(). A defensive copy is made by IpManager
+     * and the values specified herein are in force until IpManager#stop()
+     * is called.
+     *
+     * Example use:
+     *
+     *     final ProvisioningConfiguration config =
+     *             mIpManager.buildProvisioningConfiguration()
+     *                     .withPreDhcpAction()
+     *                     .build();
+     *     mIpManager.startProvisioning(config);
+     *     ...
+     *     mIpManager.stop();
+     *
+     * The specified provisioning configuration will only be active until
+     * IpManager#stop() is called. Future calls to IpManager#startProvisioning()
+     * must specify the configuration again.
+     */
+    public static class ProvisioningConfiguration {
+
+        public static class Builder {
+            private ProvisioningConfiguration mConfig = new ProvisioningConfiguration();
+
+            public Builder withoutIpReachabilityMonitor() {
+                mConfig.mUsingIpReachabilityMonitor = false;
+                return this;
+            }
+
+            public Builder withPreDhcpAction() {
+                mConfig.mRequestedPreDhcpAction = true;
+                return this;
+            }
+
+            public Builder withStaticConfiguration(StaticIpConfiguration staticConfig) {
+                mConfig.mStaticIpConfig = staticConfig;
+                return this;
+            }
+
+            public ProvisioningConfiguration build() {
+                return new ProvisioningConfiguration(mConfig);
+            }
+        }
+
+        /* package */ boolean mUsingIpReachabilityMonitor = true;
+        /* package */ boolean mRequestedPreDhcpAction;
+        /* package */ StaticIpConfiguration mStaticIpConfig;
+
+        public ProvisioningConfiguration() {}
+
+        public ProvisioningConfiguration(ProvisioningConfiguration other) {
+            mUsingIpReachabilityMonitor = other.mUsingIpReachabilityMonitor;
+            mRequestedPreDhcpAction = other.mRequestedPreDhcpAction;
+            mStaticIpConfig = other.mStaticIpConfig;
+        }
+    }
+
+    private static final int CMD_STOP = 1;
+    private static final int CMD_START = 2;
+    private static final int CMD_CONFIRM = 3;
+    private static final int EVENT_PRE_DHCP_ACTION_COMPLETE = 4;
+    // Sent by NetlinkTracker to communicate netlink events.
+    private static final int EVENT_NETLINK_LINKPROPERTIES_CHANGED = 5;
+    private static final int CMD_UPDATE_TCP_BUFFER_SIZES = 6;
+    private static final int CMD_UPDATE_HTTP_PROXY = 7;
+
+    private static final int MAX_LOG_RECORDS = 1000;
+
+    private final Object mLock = new Object();
+    private final State mStoppedState = new StoppedState();
+    private final State mStoppingState = new StoppingState();
+    private final State mStartedState = new StartedState();
+
+    private final String mTag;
+    private final Context mContext;
+    private final String mInterfaceName;
+    @VisibleForTesting
+    protected final Callback mCallback;
+    private final INetworkManagementService mNwService;
+    private final NetlinkTracker mNetlinkTracker;
+
+    private int mInterfaceIndex;
+
+    /**
+     * Non-final member variables accessed only from within our StateMachine.
+     */
+    private ProvisioningConfiguration mConfiguration;
+    private IpReachabilityMonitor mIpReachabilityMonitor;
+    private DhcpClient mDhcpClient;
+    private DhcpResults mDhcpResults;
+    private String mTcpBufferSizes;
+    private ProxyInfo mHttpProxy;
+
+    /**
+     * Member variables accessed both from within the StateMachine thread
+     * and via accessors from other threads.
+     */
+    @GuardedBy("mLock")
+    private LinkProperties mLinkProperties;
+
+    public IpManager(Context context, String ifName, Callback callback)
+                throws IllegalArgumentException {
+        super(IpManager.class.getSimpleName() + "." + ifName);
+        mTag = getName();
+
+        mContext = context;
+        mInterfaceName = ifName;
+        mCallback = callback;
+
+        mNwService = INetworkManagementService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+
+        mNetlinkTracker = new NetlinkTracker(
+                mInterfaceName,
+                new NetlinkTracker.Callback() {
+                    @Override
+                    public void update() {
+                        sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
+                    }
+                });
+        try {
+            mNwService.registerObserver(mNetlinkTracker);
+        } catch (RemoteException e) {
+            Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
+        }
+
+        resetLinkProperties();
+
+        // Super simple StateMachine.
+        addState(mStoppedState);
+        addState(mStartedState);
+        addState(mStoppingState);
+
+        setInitialState(mStoppedState);
+        setLogRecSize(MAX_LOG_RECORDS);
+        super.start();
+    }
+
+    /**
+     * A special constructor for use in testing that bypasses some of the more
+     * complicated setup bits.
+     *
+     * TODO: Figure out how to delete this yet preserve testability.
+     */
+    @VisibleForTesting
+    protected IpManager(String ifName, Callback callback) {
+        super(IpManager.class.getSimpleName() + ".test-" + ifName);
+        mTag = getName();
+
+        mInterfaceName = ifName;
+        mCallback = callback;
+
+        mContext = null;
+        mNwService = null;
+        mNetlinkTracker = null;
+    }
+
+    @Override
+    protected void onQuitting() {
+        mCallback.onQuit();
+    }
+
+    // Shut down this IpManager instance altogether.
+    public void shutdown() {
+        stop();
+        quit();
+    }
+
+    public static ProvisioningConfiguration.Builder buildProvisioningConfiguration() {
+        return new ProvisioningConfiguration.Builder();
+    }
+
+    public void startProvisioning(ProvisioningConfiguration req) {
+        getInterfaceIndex();
+        sendMessage(CMD_START, new ProvisioningConfiguration(req));
+    }
+
+    // TODO: Delete this.
+    public void startProvisioning(StaticIpConfiguration staticIpConfig) {
+        startProvisioning(buildProvisioningConfiguration()
+                .withStaticConfiguration(staticIpConfig)
+                .build());
+    }
+
+    public void startProvisioning() {
+        startProvisioning(new ProvisioningConfiguration());
+    }
+
+    public void stop() {
+        sendMessage(CMD_STOP);
+    }
+
+    public void confirmConfiguration() {
+        sendMessage(CMD_CONFIRM);
+    }
+
+    public void completedPreDhcpAction() {
+        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+    }
+
+    /**
+     * Set the TCP buffer sizes to use.
+     *
+     * This may be called, repeatedly, at any time before or after a call to
+     * #startProvisioning(). The setting is cleared upon calling #stop().
+     */
+    public void setTcpBufferSizes(String tcpBufferSizes) {
+        sendMessage(CMD_UPDATE_TCP_BUFFER_SIZES, tcpBufferSizes);
+    }
+
+    /**
+     * Set the HTTP Proxy configuration to use.
+     *
+     * This may be called, repeatedly, at any time before or after a call to
+     * #startProvisioning(). The setting is cleared upon calling #stop().
+     */
+    public void setHttpProxy(ProxyInfo proxyInfo) {
+        sendMessage(CMD_UPDATE_HTTP_PROXY, proxyInfo);
+    }
+
+    public LinkProperties getLinkProperties() {
+        synchronized (mLock) {
+            return new LinkProperties(mLinkProperties);
+        }
+    }
+
+
+    /**
+     * Internals.
+     */
+
+    @Override
+    protected String getWhatToString(int what) {
+        return sWhatToString.get(what, "UNKNOWN: " + Integer.toString(what));
+    }
+
+    @Override
+    protected String getLogRecString(Message msg) {
+        final String logLine = String.format(
+                "iface{%s/%d} arg1{%d} arg2{%d} obj{%s}",
+                mInterfaceName, mInterfaceIndex,
+                msg.arg1, msg.arg2, Objects.toString(msg.obj));
+        if (VDBG) {
+            Log.d(mTag, getWhatToString(msg.what) + " " + logLine);
+        }
+        return logLine;
+    }
+
+    private void getInterfaceIndex() {
+        try {
+            mInterfaceIndex = NetworkInterface.getByName(mInterfaceName).getIndex();
+        } catch (SocketException | NullPointerException e) {
+            // TODO: throw new IllegalStateException.
+            Log.e(mTag, "ALERT: Failed to get interface index: ", e);
+        }
+    }
+
+    // This needs to be called with care to ensure that our LinkProperties
+    // are in sync with the actual LinkProperties of the interface. For example,
+    // we should only call this if we know for sure that there are no IP addresses
+    // assigned to the interface, etc.
+    private void resetLinkProperties() {
+        mNetlinkTracker.clearLinkProperties();
+        mConfiguration = null;
+        mDhcpResults = null;
+        mTcpBufferSizes = "";
+        mHttpProxy = null;
+
+        synchronized (mLock) {
+            mLinkProperties = new LinkProperties();
+            mLinkProperties.setInterfaceName(mInterfaceName);
+        }
+    }
+
+    // For now: use WifiStateMachine's historical notion of provisioned.
+    private static boolean isProvisioned(LinkProperties lp) {
+        // For historical reasons, we should connect even if all we have is
+        // an IPv4 address and nothing else.
+        return lp.isProvisioned() || lp.hasIPv4Address();
+    }
+
+    // TODO: Investigate folding all this into the existing static function
+    // LinkProperties.compareProvisioning() or some other single function that
+    // takes two LinkProperties objects and returns a ProvisioningChange
+    // object that is a correct and complete assessment of what changed, taking
+    // account of the asymmetries described in the comments in this function.
+    // Then switch to using it everywhere (IpReachabilityMonitor, etc.).
+    private static ProvisioningChange compareProvisioning(
+            LinkProperties oldLp, LinkProperties newLp) {
+        ProvisioningChange delta;
+
+        final boolean wasProvisioned = isProvisioned(oldLp);
+        final boolean isProvisioned = isProvisioned(newLp);
+
+        if (!wasProvisioned && isProvisioned) {
+            delta = ProvisioningChange.GAINED_PROVISIONING;
+        } else if (wasProvisioned && isProvisioned) {
+            delta = ProvisioningChange.STILL_PROVISIONED;
+        } else if (!wasProvisioned && !isProvisioned) {
+            delta = ProvisioningChange.STILL_NOT_PROVISIONED;
+        } else {
+            // (wasProvisioned && !isProvisioned)
+            //
+            // Note that this is true even if we lose a configuration element
+            // (e.g., a default gateway) that would not be required to advance
+            // into provisioned state. This is intended: if we have a default
+            // router and we lose it, that's a sure sign of a problem, but if
+            // we connect to a network with no IPv4 DNS servers, we consider
+            // that to be a network without DNS servers and connect anyway.
+            //
+            // See the comment below.
+            delta = ProvisioningChange.LOST_PROVISIONING;
+        }
+
+        // Additionally:
+        //
+        // Partial configurations (e.g., only an IPv4 address with no DNS
+        // servers and no default route) are accepted as long as DHCPv4
+        // succeeds. On such a network, isProvisioned() will always return
+        // false, because the configuration is not complete, but we want to
+        // connect anyway. It might be a disconnected network such as a
+        // Chromecast or a wireless printer, for example.
+        //
+        // Because on such a network isProvisioned() will always return false,
+        // delta will never be LOST_PROVISIONING. So check for loss of
+        // provisioning here too.
+        if ((oldLp.hasIPv4Address() && !newLp.hasIPv4Address()) ||
+                (oldLp.isIPv6Provisioned() && !newLp.isIPv6Provisioned())) {
+            delta = ProvisioningChange.LOST_PROVISIONING;
+        }
+
+        return delta;
+    }
+
+    private void dispatchCallback(ProvisioningChange delta, LinkProperties newLp) {
+        switch (delta) {
+            case GAINED_PROVISIONING:
+                if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+                mCallback.onProvisioningSuccess(newLp);
+                break;
+
+            case LOST_PROVISIONING:
+                if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+                mCallback.onProvisioningFailure(newLp);
+                break;
+
+            default:
+                if (VDBG) { Log.d(mTag, "onLinkPropertiesChange()"); }
+                mCallback.onLinkPropertiesChange(newLp);
+                break;
+        }
+    }
+
+    private ProvisioningChange setLinkProperties(LinkProperties newLp) {
+        if (mIpReachabilityMonitor != null) {
+            mIpReachabilityMonitor.updateLinkProperties(newLp);
+        }
+
+        ProvisioningChange delta;
+        synchronized (mLock) {
+            delta = compareProvisioning(mLinkProperties, newLp);
+            mLinkProperties = new LinkProperties(newLp);
+        }
+
+        if (DBG) {
+            switch (delta) {
+                case GAINED_PROVISIONING:
+                case LOST_PROVISIONING:
+                    Log.d(mTag, "provisioning: " + delta);
+                    break;
+            }
+        }
+
+        return delta;
+    }
+
+    private boolean linkPropertiesUnchanged(LinkProperties newLp) {
+        synchronized (mLock) {
+            return Objects.equals(newLp, mLinkProperties);
+        }
+    }
+
+    private LinkProperties assembleLinkProperties() {
+        // [1] Create a new LinkProperties object to populate.
+        LinkProperties newLp = new LinkProperties();
+        newLp.setInterfaceName(mInterfaceName);
+
+        // [2] Pull in data from netlink:
+        //         - IPv4 addresses
+        //         - IPv6 addresses
+        //         - IPv6 routes
+        //         - IPv6 DNS servers
+        LinkProperties netlinkLinkProperties = mNetlinkTracker.getLinkProperties();
+        newLp.setLinkAddresses(netlinkLinkProperties.getLinkAddresses());
+        for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
+            newLp.addRoute(route);
+        }
+        for (InetAddress dns : netlinkLinkProperties.getDnsServers()) {
+            // Only add likely reachable DNS servers.
+            // TODO: investigate deleting this.
+            if (newLp.isReachable(dns)) {
+                newLp.addDnsServer(dns);
+            }
+        }
+
+        // [3] Add in data from DHCPv4, if available.
+        //
+        // mDhcpResults is never shared with any other owner so we don't have
+        // to worry about concurrent modification.
+        if (mDhcpResults != null) {
+            for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
+                newLp.addRoute(route);
+            }
+            for (InetAddress dns : mDhcpResults.dnsServers) {
+                // Only add likely reachable DNS servers.
+                // TODO: investigate deleting this.
+                if (newLp.isReachable(dns)) {
+                    newLp.addDnsServer(dns);
+                }
+            }
+            newLp.setDomains(mDhcpResults.domains);
+        }
+
+        // [4] Add in TCP buffer sizes and HTTP Proxy config, if available.
+        if (!TextUtils.isEmpty(mTcpBufferSizes)) {
+            newLp.setTcpBufferSizes(mTcpBufferSizes);
+        }
+        if (mHttpProxy != null) {
+            newLp.setHttpProxy(mHttpProxy);
+        }
+
+        if (VDBG) {
+            Log.d(mTag, "newLp{" + newLp + "}");
+        }
+        return newLp;
+    }
+
+    // Returns false if we have lost provisioning, true otherwise.
+    private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
+        final LinkProperties newLp = assembleLinkProperties();
+        if (linkPropertiesUnchanged(newLp)) {
+            return true;
+        }
+        final ProvisioningChange delta = setLinkProperties(newLp);
+        if (sendCallbacks) {
+            dispatchCallback(delta, newLp);
+        }
+        return (delta != ProvisioningChange.LOST_PROVISIONING);
+    }
+
+    private void clearIPv4Address() {
+        try {
+            final InterfaceConfiguration ifcg = new InterfaceConfiguration();
+            ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
+            mNwService.setInterfaceConfig(mInterfaceName, ifcg);
+        } catch (RemoteException e) {
+            Log.e(mTag, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
+        }
+    }
+
+    private void handleIPv4Success(DhcpResults dhcpResults) {
+        mDhcpResults = new DhcpResults(dhcpResults);
+        final LinkProperties newLp = assembleLinkProperties();
+        final ProvisioningChange delta = setLinkProperties(newLp);
+
+        if (VDBG) {
+            Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
+        }
+        mCallback.onNewDhcpResults(dhcpResults);
+
+        dispatchCallback(delta, newLp);
+    }
+
+    private void handleIPv4Failure() {
+        // TODO: Figure out to de-dup this and the same code in DhcpClient.
+        clearIPv4Address();
+        mDhcpResults = null;
+        final LinkProperties newLp = assembleLinkProperties();
+        ProvisioningChange delta = setLinkProperties(newLp);
+        // If we've gotten here and we're still not provisioned treat that as
+        // a total loss of provisioning.
+        //
+        // Either (a) static IP configuration failed or (b) DHCPv4 failed AND
+        // there was no usable IPv6 obtained before the DHCPv4 timeout.
+        //
+        // Regardless: GAME OVER.
+        //
+        // TODO: Make the DHCP client not time out and just continue in
+        // exponential backoff. Callers such as Wi-Fi which need a timeout
+        // should implement it themselves.
+        if (delta == ProvisioningChange.STILL_NOT_PROVISIONED) {
+            delta = ProvisioningChange.LOST_PROVISIONING;
+        }
+
+        if (VDBG) { Log.d(mTag, "onNewDhcpResults(null)"); }
+        mCallback.onNewDhcpResults(null);
+
+        dispatchCallback(delta, newLp);
+        if (delta == ProvisioningChange.LOST_PROVISIONING) {
+            transitionTo(mStoppingState);
+        }
+    }
+
+    class StoppedState extends State {
+        @Override
+        public void enter() {
+            try {
+                mNwService.disableIpv6(mInterfaceName);
+                mNwService.clearInterfaceAddresses(mInterfaceName);
+            } catch (Exception e) {
+                Log.e(mTag, "Failed to clear addresses or disable IPv6" + e);
+            }
+
+            resetLinkProperties();
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    break;
+
+                case CMD_START:
+                    mConfiguration = (ProvisioningConfiguration) msg.obj;
+                    transitionTo(mStartedState);
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_TCP_BUFFER_SIZES:
+                    mTcpBufferSizes = (String) msg.obj;
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_HTTP_PROXY:
+                    mHttpProxy = (ProxyInfo) msg.obj;
+                    handleLinkPropertiesUpdate(NO_CALLBACKS);
+                    break;
+
+                case DhcpClient.CMD_ON_QUIT:
+                    // Everything is already stopped.
+                    Log.e(mTag, "Unexpected CMD_ON_QUIT (already stopped).");
+                    break;
+
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+    }
+
+    class StoppingState extends State {
+        @Override
+        public void enter() {
+            if (mDhcpClient == null) {
+                // There's no DHCPv4 for which to wait; proceed to stopped.
+                transitionTo(mStoppedState);
+            }
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case DhcpClient.CMD_ON_QUIT:
+                    mDhcpClient = null;
+                    transitionTo(mStoppedState);
+                    break;
+
+                default:
+                    deferMessage(msg);
+            }
+            return HANDLED;
+        }
+    }
+
+    class StartedState extends State {
+        @Override
+        public void enter() {
+            // Set privacy extensions.
+            try {
+                mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
+                mNwService.enableIpv6(mInterfaceName);
+                // TODO: Perhaps clearIPv4Address() as well.
+            } catch (RemoteException re) {
+                Log.e(mTag, "Unable to change interface settings: " + re);
+            } catch (IllegalStateException ie) {
+                Log.e(mTag, "Unable to change interface settings: " + ie);
+            }
+
+            if (mConfiguration.mUsingIpReachabilityMonitor) {
+                mIpReachabilityMonitor = new IpReachabilityMonitor(
+                        mContext,
+                        mInterfaceName,
+                        new IpReachabilityMonitor.Callback() {
+                            @Override
+                            public void notifyLost(InetAddress ip, String logMsg) {
+                                mCallback.onReachabilityLost(logMsg);
+                            }
+                        });
+            }
+
+            // If we have a StaticIpConfiguration attempt to apply it and
+            // handle the result accordingly.
+            if (mConfiguration.mStaticIpConfig != null) {
+                if (applyStaticIpConfig()) {
+                    handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
+                } else {
+                    if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+                    mCallback.onProvisioningFailure(getLinkProperties());
+                    transitionTo(mStoppingState);
+                }
+            } else {
+                // Start DHCPv4.
+                mDhcpClient = DhcpClient.makeDhcpClient(
+                        mContext,
+                        IpManager.this,
+                        mInterfaceName);
+                mDhcpClient.registerForPreDhcpNotification();
+                mDhcpClient.sendMessage(DhcpClient.CMD_START_DHCP);
+            }
+        }
+
+        @Override
+        public void exit() {
+            if (mIpReachabilityMonitor != null) {
+                mIpReachabilityMonitor.stop();
+                mIpReachabilityMonitor = null;
+            }
+
+            if (mDhcpClient != null) {
+                mDhcpClient.sendMessage(DhcpClient.CMD_STOP_DHCP);
+                mDhcpClient.doQuit();
+            }
+
+            resetLinkProperties();
+        }
+
+        @Override
+        public boolean processMessage(Message msg) {
+            switch (msg.what) {
+                case CMD_STOP:
+                    transitionTo(mStoppedState);
+                    break;
+
+                case CMD_START:
+                    Log.e(mTag, "ALERT: START received in StartedState. Please fix caller.");
+                    break;
+
+                case CMD_CONFIRM:
+                    // TODO: Possibly introduce a second type of confirmation
+                    // that both probes (a) on-link neighbors and (b) does
+                    // a DHCPv4 RENEW.  We used to do this on Wi-Fi framework
+                    // roams.
+                    if (mIpReachabilityMonitor != null) {
+                        mIpReachabilityMonitor.probeAll();
+                    }
+                    break;
+
+                case EVENT_PRE_DHCP_ACTION_COMPLETE:
+                    // It's possible to reach here if, for example, someone
+                    // calls completedPreDhcpAction() after provisioning with
+                    // a static IP configuration.
+                    if (mDhcpClient != null) {
+                        mDhcpClient.sendMessage(DhcpClient.CMD_PRE_DHCP_ACTION_COMPLETE);
+                    }
+                    break;
+
+                case EVENT_NETLINK_LINKPROPERTIES_CHANGED:
+                    if (!handleLinkPropertiesUpdate(SEND_CALLBACKS)) {
+                        transitionTo(mStoppedState);
+                    }
+                    break;
+
+                case CMD_UPDATE_TCP_BUFFER_SIZES:
+                    mTcpBufferSizes = (String) msg.obj;
+                    // This cannot possibly change provisioning state.
+                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
+                    break;
+
+                case CMD_UPDATE_HTTP_PROXY:
+                    mHttpProxy = (ProxyInfo) msg.obj;
+                    // This cannot possibly change provisioning state.
+                    handleLinkPropertiesUpdate(SEND_CALLBACKS);
+                    break;
+
+                case DhcpClient.CMD_PRE_DHCP_ACTION:
+                    if (VDBG) { Log.d(mTag, "onPreDhcpAction()"); }
+                    if (mConfiguration.mRequestedPreDhcpAction) {
+                        mCallback.onPreDhcpAction();
+                    } else {
+                        sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
+                    }
+                    break;
+
+                case DhcpClient.CMD_POST_DHCP_ACTION: {
+                    // Note that onPostDhcpAction() is likely to be
+                    // asynchronous, and thus there is no guarantee that we
+                    // will be able to observe any of its effects here.
+                    if (VDBG) { Log.d(mTag, "onPostDhcpAction()"); }
+                    mCallback.onPostDhcpAction();
+
+                    final DhcpResults dhcpResults = (DhcpResults) msg.obj;
+                    switch (msg.arg1) {
+                        case DhcpClient.DHCP_SUCCESS:
+                            handleIPv4Success(dhcpResults);
+                            break;
+                        case DhcpClient.DHCP_FAILURE:
+                            handleIPv4Failure();
+                            break;
+                        default:
+                            Log.e(mTag, "Unknown CMD_POST_DHCP_ACTION status:" + msg.arg1);
+                    }
+                    break;
+                }
+
+                case DhcpClient.CMD_ON_QUIT:
+                    // DHCPv4 quit early for some reason.
+                    Log.e(mTag, "Unexpected CMD_ON_QUIT.");
+                    mDhcpClient = null;
+                    break;
+
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+
+        private boolean applyStaticIpConfig() {
+            final InterfaceConfiguration ifcg = new InterfaceConfiguration();
+            ifcg.setLinkAddress(mConfiguration.mStaticIpConfig.ipAddress);
+            ifcg.setInterfaceUp();
+            try {
+                mNwService.setInterfaceConfig(mInterfaceName, ifcg);
+                if (DBG) Log.d(mTag, "Static IP configuration succeeded");
+            } catch (IllegalStateException | RemoteException e) {
+                Log.e(mTag, "Static IP configuration failed: ", e);
+                return false;
+            }
+
+            return true;
+        }
+    }
+}
diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk
index 33979b1..1ef7656 100644
--- a/services/tests/servicestests/Android.mk
+++ b/services/tests/servicestests/Android.mk
@@ -1,3 +1,7 @@
+#########################################################################
+# Build FrameworksServicesTests package
+#########################################################################
+
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 
@@ -21,5 +25,39 @@
 
 LOCAL_CERTIFICATE := platform
 
+LOCAL_JNI_SHARED_LIBRARIES := \
+    libapfjni \
+    libc++ \
+    libnativehelper
+
 include $(BUILD_PACKAGE)
 
+#########################################################################
+# Build JNI Shared Library
+#########################################################################
+
+LOCAL_PATH:= $(LOCAL_PATH)/jni
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -Wall -Werror
+
+LOCAL_C_INCLUDES := \
+  libpcap \
+  hardware/google/apf
+
+LOCAL_SRC_FILES := apf_jni.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+  libnativehelper \
+  liblog
+
+LOCAL_STATIC_LIBRARIES := \
+  libpcap \
+  libapf
+
+LOCAL_MODULE := libapfjni
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/tests/servicestests/jni/apf_jni.cpp b/services/tests/servicestests/jni/apf_jni.cpp
new file mode 100644
index 0000000..7d142eb
--- /dev/null
+++ b/services/tests/servicestests/jni/apf_jni.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright 2016, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <JNIHelp.h>
+#include <ScopedUtfChars.h>
+#include <jni.h>
+#include <pcap.h>
+#include <stdlib.h>
+#include <string>
+#include <utils/Log.h>
+
+#include "apf_interpreter.h"
+
+#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+
+// JNI function acting as simply call-through to native APF interpreter.
+static jint com_android_server_ApfTest_apfSimulate(
+        JNIEnv* env, jclass, jbyteArray program, jbyteArray packet, jint filter_age) {
+    return accept_packet(
+            (uint8_t*)env->GetByteArrayElements(program, NULL),
+            env->GetArrayLength(program),
+            (uint8_t*)env->GetByteArrayElements(packet, NULL),
+            env->GetArrayLength(packet),
+            filter_age);
+}
+
+class ScopedPcap {
+  public:
+    ScopedPcap(pcap_t* pcap) : pcap_ptr(pcap) {}
+    ~ScopedPcap() {
+        pcap_close(pcap_ptr);
+    }
+
+    pcap_t* get() const { return pcap_ptr; };
+  private:
+    pcap_t* const pcap_ptr;
+};
+
+class ScopedFILE {
+  public:
+    ScopedFILE(FILE* fp) : file(fp) {}
+    ~ScopedFILE() {
+        fclose(file);
+    }
+
+    FILE* get() const { return file; };
+  private:
+    FILE* const file;
+};
+
+static void throwException(JNIEnv* env, const std::string& error) {
+    jclass newExcCls = env->FindClass("java/lang/IllegalStateException");
+    if (newExcCls == 0) {
+      abort();
+      return;
+    }
+    env->ThrowNew(newExcCls, error.c_str());
+}
+
+static jstring com_android_server_ApfTest_compileToBpf(JNIEnv* env, jclass, jstring jfilter) {
+    ScopedUtfChars filter(env, jfilter);
+    std::string bpf_string;
+    ScopedPcap pcap(pcap_open_dead(DLT_EN10MB, 65535));
+    if (pcap.get() == NULL) {
+        throwException(env, "pcap_open_dead failed");
+        return NULL;
+    }
+
+    // Compile "filter" to a BPF program
+    bpf_program bpf;
+    if (pcap_compile(pcap.get(), &bpf, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN)) {
+        throwException(env, "pcap_compile failed");
+        return NULL;
+    }
+
+    // Translate BPF program to human-readable format
+    const struct bpf_insn* insn = bpf.bf_insns;
+    for (uint32_t i = 0; i < bpf.bf_len; i++) {
+        bpf_string += bpf_image(insn++, i);
+        bpf_string += "\n";
+    }
+
+    return env->NewStringUTF(bpf_string.c_str());
+}
+
+static jboolean com_android_server_ApfTest_compareBpfApf(JNIEnv* env, jclass, jstring jfilter,
+        jstring jpcap_filename, jbyteArray japf_program) {
+    ScopedUtfChars filter(env, jfilter);
+    ScopedUtfChars pcap_filename(env, jpcap_filename);
+    const uint8_t* apf_program = (uint8_t*)env->GetByteArrayElements(japf_program, NULL);
+    const uint32_t apf_program_len = env->GetArrayLength(japf_program);
+
+    // Open pcap file for BPF filtering
+    ScopedFILE bpf_fp(fopen(pcap_filename.c_str(), "rb"));
+    char pcap_error[PCAP_ERRBUF_SIZE];
+    ScopedPcap bpf_pcap(pcap_fopen_offline(bpf_fp.get(), pcap_error));
+    if (bpf_pcap.get() == NULL) {
+        throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
+        return false;
+    }
+
+    // Open pcap file for APF filtering
+    ScopedFILE apf_fp(fopen(pcap_filename.c_str(), "rb"));
+    ScopedPcap apf_pcap(pcap_fopen_offline(apf_fp.get(), pcap_error));
+    if (apf_pcap.get() == NULL) {
+        throwException(env, "pcap_fopen_offline failed: " + std::string(pcap_error));
+        return false;
+    }
+
+    // Compile "filter" to a BPF program
+    bpf_program bpf;
+    if (pcap_compile(bpf_pcap.get(), &bpf, filter.c_str(), 0, PCAP_NETMASK_UNKNOWN)) {
+        throwException(env, "pcap_compile failed");
+        return false;
+    }
+
+    // Install BPF filter on bpf_pcap
+    if (pcap_setfilter(bpf_pcap.get(), &bpf)) {
+        throwException(env, "pcap_setfilter failed");
+        return false;
+    }
+
+    while (1) {
+        pcap_pkthdr bpf_header, apf_header;
+        // Run BPF filter to the next matching packet.
+        const uint8_t* bpf_packet = pcap_next(bpf_pcap.get(), &bpf_header);
+
+        // Run APF filter to the next matching packet.
+        const uint8_t* apf_packet;
+        do {
+            apf_packet = pcap_next(apf_pcap.get(), &apf_header);
+        } while (apf_packet != NULL && !accept_packet(
+                apf_program, apf_program_len, apf_packet, apf_header.len, 0));
+
+        // Make sure both filters matched the same packet.
+        if (apf_packet == NULL && bpf_packet == NULL)
+             break;
+        if (apf_packet == NULL || bpf_packet == NULL)
+             return false;
+        if (apf_header.len != bpf_header.len ||
+                apf_header.ts.tv_sec != bpf_header.ts.tv_sec ||
+                apf_header.ts.tv_usec != bpf_header.ts.tv_usec ||
+                memcmp(apf_packet, bpf_packet, apf_header.len))
+            return false;
+    }
+    return true;
+}
+
+extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
+    JNIEnv *env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        ALOGE("ERROR: GetEnv failed");
+        return -1;
+    }
+
+    static JNINativeMethod gMethods[] = {
+            { "apfSimulate", "([B[BI)I",
+                    (void*)com_android_server_ApfTest_apfSimulate },
+            { "compileToBpf", "(Ljava/lang/String;)Ljava/lang/String;",
+                    (void*)com_android_server_ApfTest_compileToBpf },
+            { "compareBpfApf", "(Ljava/lang/String;Ljava/lang/String;[B)Z",
+                    (void*)com_android_server_ApfTest_compareBpfApf },
+    };
+
+    jniRegisterNativeMethods(env, "com/android/server/ApfTest",
+            gMethods, ARRAY_SIZE(gMethods));
+
+    return JNI_VERSION_1_6;
+}
diff --git a/services/tests/servicestests/res/raw/apf.pcap b/services/tests/servicestests/res/raw/apf.pcap
new file mode 100644
index 0000000..963165f
--- /dev/null
+++ b/services/tests/servicestests/res/raw/apf.pcap
Binary files differ
diff --git a/services/tests/servicestests/src/com/android/server/ApfTest.java b/services/tests/servicestests/src/com/android/server/ApfTest.java
new file mode 100644
index 0000000..640a6c9
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/ApfTest.java
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.frameworks.servicestests.R;
+import android.net.apf.ApfGenerator;
+import android.net.apf.ApfGenerator.IllegalInstructionException;
+import android.net.apf.ApfGenerator.Register;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import libcore.io.IoUtils;
+import libcore.io.Streams;
+
+/**
+ * Tests for APF program generator and interpreter.
+ *
+ * Build, install and run with:
+ *  runtest frameworks-services -c com.android.server.ApfTest
+ */
+public class ApfTest extends AndroidTestCase {
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        // Load up native shared library containing APF interpreter exposed via JNI.
+        System.loadLibrary("apfjni");
+    }
+
+    // Expected return codes from APF interpreter.
+    private final static int PASS = 1;
+    private final static int DROP = 0;
+    // Interpreter will just accept packets without link layer headers, so pad fake packet to at
+    // least the minimum packet size.
+    private final static int MIN_PKT_SIZE = 15;
+
+    private void assertVerdict(int expected, byte[] program, byte[] packet, int filterAge) {
+        assertEquals(expected, apfSimulate(program, packet, filterAge));
+    }
+
+    private void assertPass(byte[] program, byte[] packet, int filterAge) {
+        assertVerdict(PASS, program, packet, filterAge);
+    }
+
+    private void assertDrop(byte[] program, byte[] packet, int filterAge) {
+        assertVerdict(DROP, program, packet, filterAge);
+    }
+
+    private void assertVerdict(int expected, ApfGenerator gen, byte[] packet, int filterAge)
+            throws IllegalInstructionException {
+        assertEquals(expected, apfSimulate(gen.generate(), packet, filterAge));
+    }
+
+    private void assertPass(ApfGenerator gen, byte[] packet, int filterAge)
+            throws IllegalInstructionException {
+        assertVerdict(PASS, gen, packet, filterAge);
+    }
+
+    private void assertDrop(ApfGenerator gen, byte[] packet, int filterAge)
+            throws IllegalInstructionException {
+        assertVerdict(DROP, gen, packet, filterAge);
+    }
+
+    private void assertPass(ApfGenerator gen)
+            throws IllegalInstructionException {
+        assertVerdict(PASS, gen, new byte[MIN_PKT_SIZE], 0);
+    }
+
+    private void assertDrop(ApfGenerator gen)
+            throws IllegalInstructionException {
+        assertVerdict(DROP, gen, new byte[MIN_PKT_SIZE], 0);
+    }
+
+    /**
+     * Test each instruction by generating a program containing the instruction,
+     * generating bytecode for that program and running it through the
+     * interpreter to verify it functions correctly.
+     */
+    @LargeTest
+    public void testApfInstructions() throws IllegalInstructionException {
+        // Empty program should pass because having the program counter reach the
+        // location immediately after the program indicates the packet should be
+        // passed to the AP.
+        ApfGenerator gen = new ApfGenerator();
+        assertPass(gen);
+
+        // Test jumping to pass label.
+        gen = new ApfGenerator();
+        gen.addJump(gen.PASS_LABEL);
+        byte[] program = gen.generate();
+        assertEquals(1, program.length);
+        assertEquals((14 << 3) | (0 << 1) | 0, program[0]);
+        assertPass(program, new byte[MIN_PKT_SIZE], 0);
+
+        // Test jumping to drop label.
+        gen = new ApfGenerator();
+        gen.addJump(gen.DROP_LABEL);
+        program = gen.generate();
+        assertEquals(2, program.length);
+        assertEquals((14 << 3) | (1 << 1) | 0, program[0]);
+        assertEquals(1, program[1]);
+        assertDrop(program, new byte[15], 15);
+
+        // Test jumping if equal to 0.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if not equal to 0.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0NotEquals(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if registers equal.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0EqualsR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if registers not equal.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0NotEqualsR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test load immediate.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test add.
+        gen = new ApfGenerator();
+        gen.addAdd(1234567890);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test subtract.
+        gen = new ApfGenerator();
+        gen.addAdd(-1234567890);
+        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test or.
+        gen = new ApfGenerator();
+        gen.addOr(1234567890);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test and.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addAnd(123456789);
+        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test left shift.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLeftShift(1);
+        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test right shift.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addRightShift(1);
+        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test multiply.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addMul(2);
+        gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test divide.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addDiv(2);
+        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test divide by zero.
+        gen = new ApfGenerator();
+        gen.addDiv(0);
+        gen.addJump(gen.DROP_LABEL);
+        assertPass(gen);
+
+        // Test add.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addAddR1();
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test subtract.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, -1234567890);
+        gen.addAddR1();
+        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test or.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addOrR1();
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test and.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, 123456789);
+        gen.addAndR1();
+        gen.addJumpIfR0Equals(1234567890 & 123456789, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test left shift.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addLeftShiftR1();
+        gen.addJumpIfR0Equals(1234567890 << 1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test right shift.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, -1);
+        gen.addLeftShiftR1();
+        gen.addJumpIfR0Equals(1234567890 >> 1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test multiply.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, 2);
+        gen.addMulR1();
+        gen.addJumpIfR0Equals(1234567890 * 2, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test divide.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addLoadImmediate(Register.R1, 2);
+        gen.addDivR1();
+        gen.addJumpIfR0Equals(1234567890 / 2, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test divide by zero.
+        gen = new ApfGenerator();
+        gen.addDivR1();
+        gen.addJump(gen.DROP_LABEL);
+        assertPass(gen);
+
+        // Test byte load.
+        gen = new ApfGenerator();
+        gen.addLoad8(Register.R0, 1);
+        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test out of bounds load.
+        gen = new ApfGenerator();
+        gen.addLoad8(Register.R0, 16);
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test half-word load.
+        gen = new ApfGenerator();
+        gen.addLoad16(Register.R0, 1);
+        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test word load.
+        gen = new ApfGenerator();
+        gen.addLoad32(Register.R0, 1);
+        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test byte indexed load.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addLoad8Indexed(Register.R0, 0);
+        gen.addJumpIfR0Equals(45, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test out of bounds indexed load.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 8);
+        gen.addLoad8Indexed(Register.R0, 8);
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertPass(gen, new byte[]{123,45,0,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test half-word indexed load.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addLoad16Indexed(Register.R0, 0);
+        gen.addJumpIfR0Equals((45 << 8) | 67, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,67,0,0,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test word indexed load.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addLoad32Indexed(Register.R0, 0);
+        gen.addJumpIfR0Equals((45 << 24) | (67 << 16) | (89 << 8) | 12, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{123,45,67,89,12,0,0,0,0,0,0,0,0,0,0}, 0);
+
+        // Test jumping if greater than.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0GreaterThan(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if less than.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0LessThan(0, gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator();
+        gen.addJumpIfR0LessThan(1, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if any bits set.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
+        assertDrop(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 3);
+        gen.addJumpIfR0AnyBitsSet(3, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if register greater than.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 2);
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addJumpIfR0GreaterThanR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if register less than.
+        gen = new ApfGenerator();
+        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1);
+        gen.addJumpIfR0LessThanR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jumping if any bits set in register.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 3);
+        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
+        assertPass(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 3);
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
+        assertDrop(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 3);
+        gen.addLoadImmediate(Register.R0, 3);
+        gen.addJumpIfR0AnyBitsSetR1(gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test load from memory.
+        gen = new ApfGenerator();
+        gen.addLoadFromMemory(Register.R0, 0);
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test store to memory.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addStoreToMemory(Register.R1, 12);
+        gen.addLoadFromMemory(Register.R0, 12);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test filter age pre-filled memory.
+        gen = new ApfGenerator();
+        gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen, new byte[MIN_PKT_SIZE], 1234567890);
+
+        // Test packet size pre-filled memory.
+        gen = new ApfGenerator();
+        gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
+        gen.addJumpIfR0Equals(MIN_PKT_SIZE, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test IPv4 header size pre-filled memory.
+        gen = new ApfGenerator();
+        gen.addLoadFromMemory(Register.R0, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+        gen.addJumpIfR0Equals(20, gen.DROP_LABEL);
+        assertDrop(gen, new byte[]{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0x45}, 0);
+
+        // Test not.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addNot(Register.R0);
+        gen.addJumpIfR0Equals(~1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test negate.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addNeg(Register.R0);
+        gen.addJumpIfR0Equals(-1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test move.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addMove(Register.R0);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addMove(Register.R1);
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test swap.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R1, 1234567890);
+        gen.addSwap();
+        gen.addJumpIfR0Equals(1234567890, gen.DROP_LABEL);
+        assertDrop(gen);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1234567890);
+        gen.addSwap();
+        gen.addJumpIfR0Equals(0, gen.DROP_LABEL);
+        assertDrop(gen);
+
+        // Test jump if bytes not equal.
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
+        program = gen.generate();
+        assertEquals(6, program.length);
+        assertEquals((13 << 3) | (1 << 1) | 0, program[0]);
+        assertEquals(1, program[1]);
+        assertEquals(((20 << 3) | (1 << 1) | 0) - 256, program[2]);
+        assertEquals(1, program[3]);
+        assertEquals(1, program[4]);
+        assertEquals(123, program[5]);
+        assertDrop(program, new byte[MIN_PKT_SIZE], 0);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
+        byte[] packet123 = new byte[]{0,123,0,0,0,0,0,0,0,0,0,0,0,0,0};
+        assertPass(gen, packet123, 0);
+        gen = new ApfGenerator();
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{123}, gen.DROP_LABEL);
+        assertDrop(gen, packet123, 0);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,30,4,5}, gen.DROP_LABEL);
+        byte[] packet12345 = new byte[]{0,1,2,3,4,5,0,0,0,0,0,0,0,0,0};
+        assertDrop(gen, packet12345, 0);
+        gen = new ApfGenerator();
+        gen.addLoadImmediate(Register.R0, 1);
+        gen.addJumpIfBytesNotEqual(Register.R0, new byte[]{1,2,3,4,5}, gen.DROP_LABEL);
+        assertPass(gen, packet12345, 0);
+    }
+
+    /**
+     * Generate some BPF programs, translate them to APF, then run APF and BPF programs
+     * over packet traces and verify both programs filter out the same packets.
+     */
+    @LargeTest
+    public void testApfAgainstBpf() throws Exception {
+        String[] tcpdump_filters = new String[]{ "udp", "tcp", "icmp", "icmp6", "udp port 53",
+                "arp", "dst 239.255.255.250", "arp or tcp or udp port 53", "net 192.168.1.0/24",
+                "arp or icmp6 or portrange 53-54", "portrange 53-54 or portrange 100-50000",
+                "tcp[tcpflags] & (tcp-ack|tcp-fin) != 0 and (ip[2:2] > 57 or icmp)" };
+        String pcap_filename = stageFile(R.raw.apf);
+        for (String tcpdump_filter : tcpdump_filters) {
+            byte[] apf_program = Bpf2Apf.convert(compileToBpf(tcpdump_filter));
+            assertTrue("Failed to match for filter: " + tcpdump_filter,
+                    compareBpfApf(tcpdump_filter, pcap_filename, apf_program));
+        }
+    }
+
+    /**
+     * Stage a file for testing, i.e. make it native accessible. Given a resource ID,
+     * copy that resource into the app's data directory and return the path to it.
+     */
+    private String stageFile(int rawId) throws Exception {
+        File file = new File(getContext().getFilesDir(), "staged_file");
+        new File(file.getParent()).mkdirs();
+        InputStream in = null;
+        OutputStream out = null;
+        try {
+            in = getContext().getResources().openRawResource(rawId);
+            out = new FileOutputStream(file);
+            Streams.copy(in, out);
+        } finally {
+            if (in != null) in.close();
+            if (out != null) out.close();
+        }
+        return file.getAbsolutePath();
+    }
+
+    /**
+     * Call the APF interpreter the run {@code program} on {@code packet} pretending the
+     * filter was installed {@code filter_age} seconds ago.
+     */
+    private native static int apfSimulate(byte[] program, byte[] packet, int filter_age);
+
+    /**
+     * Compile a tcpdump human-readable filter (e.g. "icmp" or "tcp port 54") into a BPF
+     * prorgam and return a human-readable dump of the BPF program identical to "tcpdump -d".
+     */
+    private native static String compileToBpf(String filter);
+
+    /**
+     * Open packet capture file {@code pcap_filename} and filter the packets using tcpdump
+     * human-readable filter (e.g. "icmp" or "tcp port 54") compiled to a BPF program and
+     * at the same time using APF program {@code apf_program}.  Return {@code true} if
+     * both APF and BPF programs filter out exactly the same packets.
+     */
+    private native static boolean compareBpfApf(String filter, String pcap_filename,
+            byte[] apf_program);
+}
diff --git a/services/tests/servicestests/src/com/android/server/Bpf2Apf.java b/services/tests/servicestests/src/com/android/server/Bpf2Apf.java
new file mode 100644
index 0000000..29594a8
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/Bpf2Apf.java
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.net.apf.ApfGenerator;
+import android.net.apf.ApfGenerator.IllegalInstructionException;
+import android.net.apf.ApfGenerator.Register;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+/**
+ * BPF to APF translator.
+ *
+ * Note: This is for testing purposes only and is not guaranteed to support
+ *       translation of all BPF programs.
+ *
+ * Example usage:
+ *   javac net/java/android/net/apf/ApfGenerator.java \
+ *         tests/servicestests/src/com/android/server/Bpf2Apf.java
+ *   sudo tcpdump -i em1 -d icmp | java -classpath tests/servicestests/src:net/java \
+ *                                      com.android.server.Bpf2Apf
+ */
+public class Bpf2Apf {
+    private static int parseImm(String line, String arg) {
+        if (!arg.startsWith("#0x")) {
+            throw new IllegalArgumentException("Unhandled instruction: " + line);
+        }
+        final long val_long = Long.parseLong(arg.substring(3), 16);
+        if (val_long < 0 || val_long > Long.parseLong("ffffffff", 16)) {
+            throw new IllegalArgumentException("Unhandled instruction: " + line);
+        }
+        return new Long((val_long << 32) >> 32).intValue();
+    }
+
+    /**
+     * Convert a single line of "tcpdump -d" (human readable BPF program dump) {@code line} into
+     * APF instruction(s) and append them to {@code gen}. Here's an example line:
+     * (001) jeq      #0x86dd          jt 2    jf 7
+     */
+    private static void convertLine(String line, ApfGenerator gen)
+            throws IllegalInstructionException {
+        if (line.indexOf("(") != 0 || line.indexOf(")") != 4 || line.indexOf(" ") != 5) {
+            throw new IllegalArgumentException("Unhandled instruction: " + line);
+        }
+        int label = Integer.parseInt(line.substring(1, 4));
+        gen.defineLabel(Integer.toString(label));
+        String opcode = line.substring(6, 10).trim();
+        String arg = line.substring(15, Math.min(32, line.length())).trim();
+        switch (opcode) {
+            case "ld":
+            case "ldh":
+            case "ldb":
+            case "ldx":
+            case "ldxb":
+            case "ldxh":
+                Register dest = opcode.contains("x") ? Register.R1 : Register.R0;
+                if (arg.equals("4*([14]&0xf)")) {
+                    if (!opcode.equals("ldxb")) {
+                        throw new IllegalArgumentException("Unhandled instruction: " + line);
+                    }
+                    gen.addLoadFromMemory(dest, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+                    break;
+                }
+                if (arg.equals("#pktlen")) {
+                    if (!opcode.equals("ld")) {
+                        throw new IllegalArgumentException("Unhandled instruction: " + line);
+                    }
+                    gen.addLoadFromMemory(dest, gen.PACKET_SIZE_MEMORY_SLOT);
+                    break;
+                }
+                if (arg.startsWith("#0x")) {
+                    if (!opcode.equals("ld")) {
+                        throw new IllegalArgumentException("Unhandled instruction: " + line);
+                    }
+                    gen.addLoadImmediate(dest, parseImm(line, arg));
+                    break;
+                }
+                if (arg.startsWith("M[")) {
+                    if (!opcode.startsWith("ld")) {
+                        throw new IllegalArgumentException("Unhandled instruction: " + line);
+                    }
+                    int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1));
+                    if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS ||
+                            // Disallow use of pre-filled slots as BPF programs might
+                            // wrongfully assume they're initialized to 0.
+                            (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT &&
+                                    memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) {
+                        throw new IllegalArgumentException("Unhandled instruction: " + line);
+                    }
+                    gen.addLoadFromMemory(dest, memory_slot);
+                    break;
+                }
+                if (arg.startsWith("[x + ")) {
+                    int offset = Integer.parseInt(arg.substring(5, arg.length() - 1));
+                    switch (opcode) {
+                        case "ld":
+                        case "ldx":
+                            gen.addLoad32Indexed(dest, offset);
+                            break;
+                        case "ldh":
+                        case "ldxh":
+                            gen.addLoad16Indexed(dest, offset);
+                            break;
+                        case "ldb":
+                        case "ldxb":
+                            gen.addLoad8Indexed(dest, offset);
+                            break;
+                    }
+                } else {
+                    int offset = Integer.parseInt(arg.substring(1, arg.length() - 1));
+                    switch (opcode) {
+                        case "ld":
+                        case "ldx":
+                            gen.addLoad32(dest, offset);
+                            break;
+                        case "ldh":
+                        case "ldxh":
+                            gen.addLoad16(dest, offset);
+                            break;
+                        case "ldb":
+                        case "ldxb":
+                            gen.addLoad8(dest, offset);
+                            break;
+                    }
+                }
+                break;
+            case "st":
+            case "stx":
+                Register src = opcode.contains("x") ? Register.R1 : Register.R0;
+                if (!arg.startsWith("M[")) {
+                    throw new IllegalArgumentException("Unhandled instruction: " + line);
+                }
+                int memory_slot = Integer.parseInt(arg.substring(2, arg.length() - 1));
+                if (memory_slot < 0 || memory_slot >= gen.MEMORY_SLOTS ||
+                        // Disallow overwriting pre-filled slots
+                        (memory_slot >= gen.FIRST_PREFILLED_MEMORY_SLOT &&
+                                memory_slot <= gen.LAST_PREFILLED_MEMORY_SLOT)) {
+                    throw new IllegalArgumentException("Unhandled instruction: " + line);
+                }
+                gen.addStoreToMemory(src, memory_slot);
+                break;
+            case "add":
+            case "and":
+            case "or":
+            case "sub":
+                if (arg.equals("x")) {
+                    switch(opcode) {
+                        case "add":
+                            gen.addAddR1();
+                            break;
+                        case "and":
+                            gen.addAndR1();
+                            break;
+                        case "or":
+                            gen.addOrR1();
+                            break;
+                        case "sub":
+                            gen.addNeg(Register.R1);
+                            gen.addAddR1();
+                            gen.addNeg(Register.R1);
+                            break;
+                    }
+                } else {
+                    int imm = parseImm(line, arg);
+                    switch(opcode) {
+                        case "add":
+                            gen.addAdd(imm);
+                            break;
+                        case "and":
+                            gen.addAnd(imm);
+                            break;
+                        case "or":
+                            gen.addOr(imm);
+                            break;
+                        case "sub":
+                            gen.addAdd(-imm);
+                            break;
+                    }
+                }
+                break;
+            case "jeq":
+            case "jset":
+            case "jgt":
+            case "jge":
+                int val = 0;
+                boolean reg_compare;
+                if (arg.startsWith("x")) {
+                    reg_compare = true;
+                } else {
+                    reg_compare = false;
+                    val = parseImm(line, arg);
+                }
+                int jt_offset = line.indexOf("jt");
+                int jf_offset = line.indexOf("jf");
+                String true_label = line.substring(jt_offset + 2, jf_offset).trim();
+                String false_label = line.substring(jf_offset + 2).trim();
+                boolean true_label_is_fallthrough = Integer.parseInt(true_label) == label + 1;
+                boolean false_label_is_fallthrough = Integer.parseInt(false_label) == label + 1;
+                if (true_label_is_fallthrough && false_label_is_fallthrough)
+                    break;
+                switch (opcode) {
+                    case "jeq":
+                        if (!true_label_is_fallthrough) {
+                            if (reg_compare) {
+                                gen.addJumpIfR0EqualsR1(true_label);
+                            } else {
+                                gen.addJumpIfR0Equals(val, true_label);
+                            }
+                        }
+                        if (!false_label_is_fallthrough) {
+                            if (!true_label_is_fallthrough) {
+                                gen.addJump(false_label);
+                            } else if (reg_compare) {
+                                gen.addJumpIfR0NotEqualsR1(false_label);
+                            } else {
+                                gen.addJumpIfR0NotEquals(val, false_label);
+                            }
+                        }
+                        break;
+                    case "jset":
+                        if (reg_compare) {
+                            gen.addJumpIfR0AnyBitsSetR1(true_label);
+                        } else {
+                            gen.addJumpIfR0AnyBitsSet(val, true_label);
+                        }
+                        if (!false_label_is_fallthrough) {
+                            gen.addJump(false_label);
+                        }
+                        break;
+                    case "jgt":
+                        if (!true_label_is_fallthrough ||
+                                // We have no less-than-or-equal-to register to register
+                                // comparison instruction, so in this case we'll jump
+                                // around an unconditional jump.
+                                (!false_label_is_fallthrough && reg_compare)) {
+                            if (reg_compare) {
+                                gen.addJumpIfR0GreaterThanR1(true_label);
+                            } else {
+                                gen.addJumpIfR0GreaterThan(val, true_label);
+                            }
+                        }
+                        if (!false_label_is_fallthrough) {
+                            if (!true_label_is_fallthrough || reg_compare) {
+                                gen.addJump(false_label);
+                            } else {
+                                gen.addJumpIfR0LessThan(val + 1, false_label);
+                            }
+                        }
+                        break;
+                    case "jge":
+                        if (!false_label_is_fallthrough ||
+                                // We have no greater-than-or-equal-to register to register
+                                // comparison instruction, so in this case we'll jump
+                                // around an unconditional jump.
+                                (!true_label_is_fallthrough && reg_compare)) {
+                            if (reg_compare) {
+                                gen.addJumpIfR0LessThanR1(false_label);
+                            } else {
+                                gen.addJumpIfR0LessThan(val, false_label);
+                            }
+                        }
+                        if (!true_label_is_fallthrough) {
+                            if (!false_label_is_fallthrough || reg_compare) {
+                                gen.addJump(true_label);
+                            } else {
+                                gen.addJumpIfR0GreaterThan(val - 1, true_label);
+                            }
+                        }
+                        break;
+                }
+                break;
+            case "ret":
+                if (arg.equals("#0")) {
+                    gen.addJump(gen.DROP_LABEL);
+                } else {
+                    gen.addJump(gen.PASS_LABEL);
+                }
+                break;
+            case "tax":
+                gen.addMove(Register.R1);
+                break;
+            case "txa":
+                gen.addMove(Register.R0);
+                break;
+            default:
+                throw new IllegalArgumentException("Unhandled instruction: " + line);
+        }
+    }
+
+    /**
+     * Convert the output of "tcpdump -d" (human readable BPF program dump) {@code bpf} into an APF
+     * program and return it.
+     */
+    public static byte[] convert(String bpf) throws IllegalInstructionException {
+        ApfGenerator gen = new ApfGenerator();
+        for (String line : bpf.split("\\n")) convertLine(line, gen);
+        return gen.generate();
+    }
+
+    /**
+     * Convert the output of "tcpdump -d" (human readable BPF program dump) piped in stdin into an
+     * APF program and output it via stdout.
+     */
+    public static void main(String[] args) throws Exception {
+        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
+        String line = null;
+        StringBuilder responseData = new StringBuilder();
+        ApfGenerator gen = new ApfGenerator();
+        while ((line = in.readLine()) != null) convertLine(line, gen);
+        System.out.write(gen.generate());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 97e16da..d096c28 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -52,13 +52,16 @@
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
 import android.os.MessageQueue;
+import android.os.Messenger;
 import android.os.MessageQueue.IdleHandler;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.LogPrinter;
 
@@ -1291,6 +1294,36 @@
         validatedCallback.expectCallback(CallbackState.LOST);
     }
 
+    @SmallTest
+    public void testInvalidNetworkSpecifier() {
+        boolean execptionCalled = true;
+
+        try {
+            NetworkRequest.Builder builder = new NetworkRequest.Builder();
+            builder.setNetworkSpecifier(MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+            execptionCalled = false;
+        } catch (IllegalArgumentException e) {
+            // do nothing - should get here
+        }
+
+        assertTrue("NetworkReqeuest builder with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER",
+                execptionCalled);
+
+        try {
+            NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+            networkCapabilities.addTransportType(TRANSPORT_WIFI)
+                    .setNetworkSpecifier(NetworkCapabilities.MATCH_ALL_REQUESTS_NETWORK_SPECIFIER);
+            mService.requestNetwork(networkCapabilities, null, 0, null,
+                    ConnectivityManager.TYPE_WIFI);
+            execptionCalled = false;
+        } catch (IllegalArgumentException e) {
+            // do nothing - should get here
+        }
+
+        assertTrue("ConnectivityService requestNetwork with MATCH_ALL_REQUESTS_NETWORK_SPECIFIER",
+                execptionCalled);
+    }
+
     private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
 
         public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 6511705..270c8ce 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -24,7 +24,6 @@
 import java.lang.String;
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -210,7 +209,22 @@
          * Call sends responses through connection.
          * @hide
          */
-        public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
+        public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00200000;
+
+        /**
+         * When set, prevents a video {@code Call} from being downgraded to an audio-only call.
+         * <p>
+         * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
+         * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
+         * downgraded from a video call back to a VideoState of
+         * {@link VideoProfile#STATE_AUDIO_ONLY}.
+         * <p>
+         * Intuitively, a call which can be downgraded to audio should also have local and remote
+         * video
+         * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
+         * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
+         */
+        public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00400000;
 
         //******************************************************************************************
         // Next CAPABILITY value: 0x00800000
@@ -327,6 +341,9 @@
             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
             }
+            if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
+                builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
+            }
             if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
                 builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
             }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 4115756..c9fc51e 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -255,8 +255,23 @@
      */
     public static final int CAPABILITY_CAN_SEND_RESPONSE_VIA_CONNECTION = 0x00400000;
 
+    /**
+     * When set, prevents a video call from being downgraded to an audio-only call.
+     * <p>
+     * Should be set when the VideoState has the {@link VideoProfile#STATE_TX_ENABLED} or
+     * {@link VideoProfile#STATE_RX_ENABLED} bits set to indicate that the connection cannot be
+     * downgraded from a video call back to a VideoState of
+     * {@link VideoProfile#STATE_AUDIO_ONLY}.
+     * <p>
+     * Intuitively, a call which can be downgraded to audio should also have local and remote
+     * video
+     * capabilities (see {@link #CAPABILITY_SUPPORTS_VT_LOCAL_BIDIRECTIONAL} and
+     * {@link #CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL}).
+     */
+    public static final int CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO = 0x00800000;
+
     //**********************************************************************************************
-    // Next CAPABILITY value: 0x00800000
+    // Next CAPABILITY value: 0x01000000
     //**********************************************************************************************
 
     /**
@@ -371,6 +386,9 @@
         if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL)) {
             builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_BIDIRECTIONAL");
         }
+        if (can(capabilities, CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO)) {
+            builder.append(" CAPABILITY_CANNOT_DOWNGRADE_VIDEO_TO_AUDIO");
+        }
         if (can(capabilities, CAPABILITY_HIGH_DEF_AUDIO)) {
             builder.append(" CAPABILITY_HIGH_DEF_AUDIO");
         }
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 1e49dad..70e3820 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -685,9 +685,28 @@
      * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
      * @return A {@link PersistableBundle} containing the config for the given subId, or default
      *         values for an invalid subId.
+     *
+     * @deprecated use getConfig.
      */
     @Nullable
     public PersistableBundle getConfigForSubId(int subId) {
+        return getConfig(subId);
+    }
+
+    /**
+     * Gets the configuration values for a particular subscription, which is associated with a
+     * specific SIM card. If an invalid subId is used, the returned config will contain default
+     * values.
+     *
+     * <p>Requires Permission:
+     * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     *
+     * @param subId the subscription ID, normally obtained from {@link SubscriptionManager}.
+     * @return A {@link PersistableBundle} containing the config for the given subId, or default
+     *         values for an invalid subId.
+     */
+    @Nullable
+    public PersistableBundle getConfig(int subId) {
         try {
             return getICarrierConfigLoader().getConfigForSubId(subId);
         } catch (RemoteException ex) {
@@ -706,11 +725,32 @@
      * <p>Requires Permission:
      * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *
-     * @see #getConfigForSubId
+     * @return A {@link PersistableBundle} containing the config for the default subscription.
      */
     @Nullable
     public PersistableBundle getConfig() {
-        return getConfigForSubId(SubscriptionManager.getDefaultSubId());
+        return getConfig(SubscriptionManager.getDefaultSubscriptionId());
+    }
+
+    /**
+     * Calling this method triggers telephony services to fetch the current carrier configuration.
+     * <p>
+     * Normally this does not need to be called because the platform reloads config on its own.
+     * This should be called by a carrier service app if it wants to update config at an arbitrary
+     * moment.
+     * </p>
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
+     * <p>
+     * This method returns before the reload has completed, and
+     * {@link android.service.carrier.CarrierService#onLoadConfig} will be called from an
+     * arbitrary thread.
+     * </p>
+     *
+     * @deprecated use notifyConfigChanged.
+     */
+    public void notifyConfigChangedForSubId(int subId) {
+        notifyConfigChanged(subId);
     }
 
     /**
@@ -728,7 +768,7 @@
      * arbitrary thread.
      * </p>
      */
-    public void notifyConfigChangedForSubId(int subId) {
+    public void notifyConfigChanged(int subId) {
         try {
             getICarrierConfigLoader().notifyConfigChangedForSubId(subId);
         } catch (RemoteException ex) {
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 90d2aa0..74f1171 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -38,6 +38,10 @@
     private final int mLac;
     // 16-bit GSM Cell Identity described in TS 27.007, 0..65535
     private final int mCid;
+    // 16-bit GSM Absolute RF Channel Number
+    private final int mArfcn;
+    // 6-bit Base Station Identity Code
+    private final int mBsic;
 
     /**
      * @hide
@@ -47,6 +51,8 @@
         mMnc = Integer.MAX_VALUE;
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
+        mArfcn = Integer.MAX_VALUE;
+        mBsic = Integer.MAX_VALUE;
     }
     /**
      * public constructor
@@ -58,10 +64,27 @@
      * @hide
      */
     public CellIdentityGsm (int mcc, int mnc, int lac, int cid) {
+        this(mcc, mnc, lac, cid, Integer.MAX_VALUE, Integer.MAX_VALUE);
+    }
+
+    /**
+     * public constructor
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param lac 16-bit Location Area Code, 0..65535
+     * @param cid 16-bit GSM Cell Identity or 28-bit UMTS Cell Identity
+     * @param arfcn 16-bit GSM Absolute RF Channel Number
+     * @param bsic 6-bit Base Station Identity Code
+     *
+     * @hide
+     */
+    public CellIdentityGsm (int mcc, int mnc, int lac, int cid, int arfcn, int bsic) {
         mMcc = mcc;
         mMnc = mnc;
         mLac = lac;
         mCid = cid;
+        mArfcn = arfcn;
+        mBsic = bsic;
     }
 
     private CellIdentityGsm(CellIdentityGsm cid) {
@@ -69,6 +92,8 @@
         mMnc = cid.mMnc;
         mLac = cid.mLac;
         mCid = cid.mCid;
+        mArfcn = cid.mArfcn;
+        mBsic = cid.mBsic;
     }
 
     CellIdentityGsm copy() {
@@ -106,6 +131,21 @@
     }
 
     /**
+     * @return 16-bit GSM Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+     */
+    public int getArfcn() {
+        return mArfcn;
+    }
+
+    /**
+     * @return 6-bit Base Station Identity Code, Integer.MAX_VALUE if unknown
+     */
+    public int getBsic() {
+        return mBsic;
+    }
+
+
+    /**
      * @return Integer.MAX_VALUE, undefined for GSM
      */
     @Deprecated
@@ -132,7 +172,9 @@
         return mMcc == o.mMcc &&
                 mMnc == o.mMnc &&
                 mLac == o.mLac &&
-                mCid == o.mCid;
+                mCid == o.mCid &&
+                mArfcn == o.mArfcn &&
+                mBsic == o.mBsic;
     }
 
     @Override
@@ -142,6 +184,8 @@
         sb.append(" mMnc=").append(mMnc);
         sb.append(" mLac=").append(mLac);
         sb.append(" mCid=").append(mCid);
+        sb.append(" mArfcn=").append(mArfcn);
+        sb.append(" mBsic=").append("0x").append(Integer.toHexString(mBsic));
         sb.append("}");
 
         return sb.toString();
@@ -161,6 +205,8 @@
         dest.writeInt(mMnc);
         dest.writeInt(mLac);
         dest.writeInt(mCid);
+        dest.writeInt(mArfcn);
+        dest.writeInt(mBsic);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -169,6 +215,8 @@
         mMnc = in.readInt();
         mLac = in.readInt();
         mCid = in.readInt();
+        mArfcn = in.readInt();
+        mBsic = in.readInt();
         if (DBG) log("CellIdentityGsm(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 1e7ac08..ce74383 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -40,6 +40,8 @@
     private final int mPci;
     // 16-bit tracking area code
     private final int mTac;
+    // 18-bit Absolute RF Channel Number
+    private final int mEarfcn;
 
     /**
      * @hide
@@ -50,6 +52,7 @@
         mCi = Integer.MAX_VALUE;
         mPci = Integer.MAX_VALUE;
         mTac = Integer.MAX_VALUE;
+        mEarfcn = Integer.MAX_VALUE;
     }
 
     /**
@@ -63,11 +66,27 @@
      * @hide
      */
     public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac) {
+        this(mcc, mnc, ci, pci, tac, Integer.MAX_VALUE);
+    }
+
+    /**
+     *
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param ci 28-bit Cell Identity
+     * @param pci Physical Cell Id 0..503
+     * @param tac 16-bit Tracking Area Code
+     * @param earfcn 18-bit LTE Absolute RF Channel Number
+     *
+     * @hide
+     */
+    public CellIdentityLte (int mcc, int mnc, int ci, int pci, int tac, int earfcn) {
         mMcc = mcc;
         mMnc = mnc;
         mCi = ci;
         mPci = pci;
         mTac = tac;
+        mEarfcn = earfcn;
     }
 
     private CellIdentityLte(CellIdentityLte cid) {
@@ -76,6 +95,7 @@
         mCi = cid.mCi;
         mPci = cid.mPci;
         mTac = cid.mTac;
+        mEarfcn = cid.mEarfcn;
     }
 
     CellIdentityLte copy() {
@@ -117,6 +137,13 @@
         return mTac;
     }
 
+    /**
+     * @return 18-bit Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+     */
+    public int getEarfcn() {
+        return mEarfcn;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(mMcc, mMnc, mCi, mPci, mTac);
@@ -137,7 +164,8 @@
                 mMnc == o.mMnc &&
                 mCi == o.mCi &&
                 mPci == o.mPci &&
-                mTac == o.mTac;
+                mTac == o.mTac &&
+                mEarfcn == o.mEarfcn;
     }
 
     @Override
@@ -148,6 +176,7 @@
         sb.append(" mCi="); sb.append(mCi);
         sb.append(" mPci="); sb.append(mPci);
         sb.append(" mTac="); sb.append(mTac);
+        sb.append(" mEarfcn="); sb.append(mEarfcn);
         sb.append("}");
 
         return sb.toString();
@@ -168,6 +197,7 @@
         dest.writeInt(mCi);
         dest.writeInt(mPci);
         dest.writeInt(mTac);
+        dest.writeInt(mEarfcn);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -177,6 +207,7 @@
         mCi = in.readInt();
         mPci = in.readInt();
         mTac = in.readInt();
+        mEarfcn = in.readInt();
         if (DBG) log("CellIdentityLte(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 56ee8c9..0d13efd 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -40,6 +40,8 @@
     private final int mCid;
     // 9-bit UMTS Primary Scrambling Code described in TS 25.331, 0..511
     private final int mPsc;
+    // 16-bit UMTS Absolute RF Channel Number
+    private final int mUarfcn;
 
     /**
      * @hide
@@ -50,6 +52,7 @@
         mLac = Integer.MAX_VALUE;
         mCid = Integer.MAX_VALUE;
         mPsc = Integer.MAX_VALUE;
+        mUarfcn = Integer.MAX_VALUE;
     }
     /**
      * public constructor
@@ -62,11 +65,27 @@
      * @hide
      */
     public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc) {
+        this(mcc, mnc, lac, cid, psc, Integer.MAX_VALUE);
+    }
+
+    /**
+     * public constructor
+     * @param mcc 3-digit Mobile Country Code, 0..999
+     * @param mnc 2 or 3-digit Mobile Network Code, 0..999
+     * @param lac 16-bit Location Area Code, 0..65535
+     * @param cid 28-bit UMTS Cell Identity
+     * @param psc 9-bit UMTS Primary Scrambling Code
+     * @param uarfcn 16-bit UMTS Absolute RF Channel Number
+     *
+     * @hide
+     */
+    public CellIdentityWcdma (int mcc, int mnc, int lac, int cid, int psc, int uarfcn) {
         mMcc = mcc;
         mMnc = mnc;
         mLac = lac;
         mCid = cid;
         mPsc = psc;
+        mUarfcn = uarfcn;
     }
 
     private CellIdentityWcdma(CellIdentityWcdma cid) {
@@ -75,6 +94,7 @@
         mLac = cid.mLac;
         mCid = cid.mCid;
         mPsc = cid.mPsc;
+        mUarfcn = cid.mUarfcn;
     }
 
     CellIdentityWcdma copy() {
@@ -123,6 +143,13 @@
         return Objects.hash(mMcc, mMnc, mLac, mCid, mPsc);
     }
 
+    /**
+     * @return 16-bit UMTS Absolute RF Channel Number, Integer.MAX_VALUE if unknown
+     */
+    public int getUarfcn() {
+        return mUarfcn;
+    }
+
     @Override
     public boolean equals(Object other) {
         if (this == other) {
@@ -138,7 +165,8 @@
                 mMnc == o.mMnc &&
                 mLac == o.mLac &&
                 mCid == o.mCid &&
-                mPsc == o.mPsc;
+                mPsc == o.mPsc &&
+                mUarfcn == o.mUarfcn;
     }
 
     @Override
@@ -149,6 +177,7 @@
         sb.append(" mLac=").append(mLac);
         sb.append(" mCid=").append(mCid);
         sb.append(" mPsc=").append(mPsc);
+        sb.append(" mUarfcn=").append(mUarfcn);
         sb.append("}");
 
         return sb.toString();
@@ -169,6 +198,7 @@
         dest.writeInt(mLac);
         dest.writeInt(mCid);
         dest.writeInt(mPsc);
+        dest.writeInt(mUarfcn);
     }
 
     /** Construct from Parcel, type has already been processed */
@@ -178,6 +208,7 @@
         mLac = in.readInt();
         mCid = in.readInt();
         mPsc = in.readInt();
+        mUarfcn = in.readInt();
         if (DBG) log("CellIdentityWcdma(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index d27fcec..addf7ef 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -34,6 +34,7 @@
 
     private int mSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5
     private int mBitErrorRate;   // bit error rate (0-7, 99) as defined in TS 27.007 8.5
+    private int mTimingAdvance;
 
     /**
      * Empty constructor
@@ -75,6 +76,22 @@
     public void initialize(int ss, int ber) {
         mSignalStrength = ss;
         mBitErrorRate = ber;
+        mTimingAdvance = Integer.MAX_VALUE;
+    }
+
+    /**
+     * Initialize all the values
+     *
+     * @param ss SignalStrength as ASU value
+     * @param ber is Bit Error Rate
+     * @param ta timing advance
+     *
+     * @hide
+     */
+    public void initialize(int ss, int ber, int ta) {
+        mSignalStrength = ss;
+        mBitErrorRate = ber;
+        mTimingAdvance = ta;
     }
 
     /**
@@ -83,6 +100,7 @@
     protected void copyFrom(CellSignalStrengthGsm s) {
         mSignalStrength = s.mSignalStrength;
         mBitErrorRate = s.mBitErrorRate;
+        mTimingAdvance = s.mTimingAdvance;
     }
 
     /**
@@ -98,6 +116,7 @@
     public void setDefaultValues() {
         mSignalStrength = Integer.MAX_VALUE;
         mBitErrorRate = Integer.MAX_VALUE;
+        mTimingAdvance = Integer.MAX_VALUE;
     }
 
     /**
@@ -174,7 +193,8 @@
             return false;
         }
 
-        return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate;
+        return mSignalStrength == s.mSignalStrength && mBitErrorRate == s.mBitErrorRate &&
+                        s.mTimingAdvance == mTimingAdvance;
     }
 
     /**
@@ -184,7 +204,8 @@
     public String toString() {
         return "CellSignalStrengthGsm:"
                 + " ss=" + mSignalStrength
-                + " ber=" + mBitErrorRate;
+                + " ber=" + mBitErrorRate
+                + " mTa=" + mTimingAdvance;
     }
 
     /** Implement the Parcelable interface */
@@ -193,6 +214,7 @@
         if (DBG) log("writeToParcel(Parcel, int): " + toString());
         dest.writeInt(mSignalStrength);
         dest.writeInt(mBitErrorRate);
+        dest.writeInt(mTimingAdvance);
     }
 
     /**
@@ -202,6 +224,7 @@
     private CellSignalStrengthGsm(Parcel in) {
         mSignalStrength = in.readInt();
         mBitErrorRate = in.readInt();
+        mTimingAdvance = in.readInt();
         if (DBG) log("CellSignalStrengthGsm(Parcel): " + toString());
     }
 
diff --git a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
index 96069213..f71f58d 100644
--- a/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
+++ b/telephony/java/android/telephony/DataConnectionRealTimeInfo.java
@@ -28,10 +28,10 @@
 public class DataConnectionRealTimeInfo implements Parcelable {
     private long mTime;             // Time the info was collected since boot in nanos;
 
-    public static int DC_POWER_STATE_LOW       = 1;
-    public static int DC_POWER_STATE_MEDIUM    = 2;
-    public static int DC_POWER_STATE_HIGH      = 3;
-    public static int DC_POWER_STATE_UNKNOWN   = Integer.MAX_VALUE;
+    public static final int DC_POWER_STATE_LOW       = 1;
+    public static final int DC_POWER_STATE_MEDIUM    = 2;
+    public static final int DC_POWER_STATE_HIGH      = 3;
+    public static final int DC_POWER_STATE_UNKNOWN   = Integer.MAX_VALUE;
 
     private int mDcPowerState;      // DC_POWER_STATE_[LOW | MEDIUM | HIGH | UNKNOWN]
 
diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java
index 8443490..9eb1304 100644
--- a/telephony/java/android/telephony/DisconnectCause.java
+++ b/telephony/java/android/telephony/DisconnectCause.java
@@ -187,6 +187,13 @@
      */
     public static final int CDMA_ALREADY_ACTIVATED         = 49;
 
+    /**
+     * The call was terminated because it is not possible to place a video call while TTY is
+     * enabled.
+     * {@hide}
+     */
+    public static final int VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED = 50;
+
     //*********************************************************************************************
     // When adding a disconnect type:
     // 1) Please assign the new type the next id value below.
@@ -202,7 +209,7 @@
     public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED;
 
     /** Largest valid value for call disconnect codes. */
-    public static final int MAXIMUM_VALID_VALUE = CDMA_ALREADY_ACTIVATED;
+    public static final int MAXIMUM_VALID_VALUE = VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED;
 
     /** Private constructor to avoid class instantiation. */
     private DisconnectCause() {
@@ -310,6 +317,8 @@
             return "IMS_MERGED_SUCCESSFULLY";
         case CDMA_ALREADY_ACTIVATED:
             return "CDMA_ALREADY_ACTIVATED";
+        case VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED:
+                return "VIDEO_CALL_NOT_ALLOWED_WHILE_TTY_ENABLED";
         default:
             return "INVALID: " + cause;
         }
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index ea96e7c..6425744 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -48,7 +48,9 @@
         mTimestamp = timestamp;
         mSleepTimeMs = sleepTimeMs;
         mIdleTimeMs = idleTimeMs;
-        System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+        if (txTimeMs != null) {
+            System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+        }
         mRxTimeMs = rxTimeMs;
         mEnergyUsed = energyUsed;
     }
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 553221d..962a600 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1857,9 +1857,6 @@
         // to the list.
         number = extractNetworkPortionAlt(number);
 
-        Rlog.d(LOG_TAG, "subId:" + subId + ", defaultCountryIso:" +
-                ((defaultCountryIso == null) ? "NULL" : defaultCountryIso));
-
         String emergencyNumbers = "";
         int slotId = SubscriptionManager.getSlotId(subId);
 
@@ -1869,7 +1866,8 @@
 
         emergencyNumbers = SystemProperties.get(ecclist, "");
 
-        Rlog.d(LOG_TAG, "slotId:" + slotId + ", emergencyNumbers: " +  emergencyNumbers);
+        Rlog.d(LOG_TAG, "slotId:" + slotId + " subId:" + subId + " country:"
+                + defaultCountryIso + " emergencyNumbers: " +  emergencyNumbers);
 
         if (TextUtils.isEmpty(emergencyNumbers)) {
             // then read-only ecclist property since old RIL only uses this
@@ -2082,7 +2080,7 @@
      * to read the VM number.
      */
     public static boolean isVoiceMailNumber(String number) {
-        return isVoiceMailNumber(SubscriptionManager.getDefaultSubId(), number);
+        return isVoiceMailNumber(SubscriptionManager.getDefaultSubscriptionId(), number);
     }
 
     /**
@@ -2977,7 +2975,7 @@
      * Returns Default voice subscription Id.
      */
     private static int getDefaultVoiceSubId() {
-        return SubscriptionManager.getDefaultVoiceSubId();
+        return SubscriptionManager.getDefaultVoiceSubscriptionId();
     }
     //==== End of utility methods used only in compareStrictly() =====
 }
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index c680999..ad007c6 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -37,6 +37,7 @@
 
     static final String LOG_TAG = "PHONE";
     static final boolean DBG = true;
+    static final boolean VDBG = false;  // STOPSHIP if true
 
     /**
      * Normal operation condition, the phone is registered
@@ -829,7 +830,7 @@
     /** @hide */
     public void setDataRegState(int state) {
         mDataRegState = state;
-        if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
+        if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRegState=" + mDataRegState);
     }
 
     public void setRoaming(boolean roaming) {
@@ -1017,7 +1018,8 @@
     /** @hide */
     public void setRilDataRadioTechnology(int rt) {
         this.mRilDataRadioTechnology = rt;
-        if (DBG) Rlog.d(LOG_TAG, "[ServiceState] setDataRadioTechnology=" + mRilDataRadioTechnology);
+        if (VDBG) Rlog.d(LOG_TAG, "[ServiceState] setRilDataRadioTechnology=" +
+                mRilDataRadioTechnology);
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 9998937..ff8c71c 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -53,7 +53,6 @@
     private static final boolean VDBG = false;
 
     /** An invalid subscription identifier */
-    /** @hide */
     public static final int INVALID_SUBSCRIPTION_ID = -1;
 
     /** Base value for Dummy SUBSCRIPTION_ID's. */
@@ -455,8 +454,9 @@
     }
 
     /**
-     * Get the active SubscriptionInfo with the subId key
-     * @param subId The unique SubscriptionInfo key in database
+     * Get the active SubscriptionInfo with the input subId.
+     *
+     * @param subId The unique SubscriptionInfo key in database.
      * @return SubscriptionInfo, maybe null if its not active.
      */
     public SubscriptionInfo getActiveSubscriptionInfo(int subId) {
@@ -898,12 +898,15 @@
     }
 
     /**
-     * @return the "system" defaultSubId on a voice capable device this
-     * will be getDefaultVoiceSubId() and on a data only device it will be
-     * getDefaultDataSubId().
-     * @hide
+     * Returns the system's default subscription id.
+     *
+     * For a voice capable device, it will return getDefaultVoiceSubscriptionId.
+     * For a data only device, it will return the getDefaultDataSubscriptionId.
+     * May return an INVALID_SUBSCRIPTION_ID on error.
+     *
+     * @return the "system" default subscription id.
      */
-    public static int getDefaultSubId() {
+    public static int getDefaultSubscriptionId() {
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
@@ -919,8 +922,14 @@
         return subId;
     }
 
-    /** @hide */
-    public static int getDefaultVoiceSubId() {
+    /**
+     * Returns the system's default voice subscription id.
+     *
+     * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
+     *
+     * @return the default voice subscription Id.
+     */
+    public static int getDefaultVoiceSubscriptionId() {
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
@@ -932,7 +941,7 @@
             // ignore it
         }
 
-        if (VDBG) logd("getDefaultVoiceSubId, sub id = " + subId);
+        if (VDBG) logd("getDefaultVoiceSubscriptionId, sub id = " + subId);
         return subId;
     }
 
@@ -949,23 +958,31 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Return the SubscriptionInfo for default voice subscription.
+     *
+     * Will return null on data only devices, or on error.
+     *
+     * @return the SubscriptionInfo for the default voice subscription.
+     * @hide
+     */
     public SubscriptionInfo getDefaultVoiceSubscriptionInfo() {
-        return getActiveSubscriptionInfo(getDefaultVoiceSubId());
+        return getActiveSubscriptionInfo(getDefaultVoiceSubscriptionId());
     }
 
     /** @hide */
     public static int getDefaultVoicePhoneId() {
-        return getPhoneId(getDefaultVoiceSubId());
+        return getPhoneId(getDefaultVoiceSubscriptionId());
     }
 
     /**
-     * @return subId of the DefaultSms subscription or
-     * a value < 0 if an error.
+     * Returns the system's default SMS subscription id.
      *
-     * @hide
+     * On a data only device or on error, will return INVALID_SUBSCRIPTION_ID.
+     *
+     * @return the default SMS subscription Id.
      */
-    public static int getDefaultSmsSubId() {
+    public static int getDefaultSmsSubscriptionId() {
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
@@ -977,7 +994,7 @@
             // ignore it
         }
 
-        if (VDBG) logd("getDefaultSmsSubId, sub id = " + subId);
+        if (VDBG) logd("getDefaultSmsSubscriptionId, sub id = " + subId);
         return subId;
     }
 
@@ -994,18 +1011,31 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Return the SubscriptionInfo for default voice subscription.
+     *
+     * Will return null on data only devices, or on error.
+     *
+     * @return the SubscriptionInfo for the default SMS subscription.
+     * @hide
+     */
     public SubscriptionInfo getDefaultSmsSubscriptionInfo() {
-        return getActiveSubscriptionInfo(getDefaultSmsSubId());
+        return getActiveSubscriptionInfo(getDefaultSmsSubscriptionId());
     }
 
     /** @hide */
     public int getDefaultSmsPhoneId() {
-        return getPhoneId(getDefaultSmsSubId());
+        return getPhoneId(getDefaultSmsSubscriptionId());
     }
 
-    /** @hide */
-    public static int getDefaultDataSubId() {
+    /**
+     * Returns the system's default data subscription id.
+     *
+     * On a voice only device or on error, will return INVALID_SUBSCRIPTION_ID.
+     *
+     * @return the default data subscription Id.
+     */
+    public static int getDefaultDataSubscriptionId() {
         int subId = INVALID_SUBSCRIPTION_ID;
 
         try {
@@ -1017,7 +1047,7 @@
             // ignore it
         }
 
-        if (VDBG) logd("getDefaultDataSubId, sub id = " + subId);
+        if (VDBG) logd("getDefaultDataSubscriptionId, sub id = " + subId);
         return subId;
     }
 
@@ -1034,14 +1064,21 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Return the SubscriptionInfo for default data subscription.
+     *
+     * Will return null on voice only devices, or on error.
+     *
+     * @return the SubscriptionInfo for the default data subscription.
+     * @hide
+     */
     public SubscriptionInfo getDefaultDataSubscriptionInfo() {
-        return getActiveSubscriptionInfo(getDefaultDataSubId());
+        return getActiveSubscriptionInfo(getDefaultDataSubscriptionId());
     }
 
     /** @hide */
     public int getDefaultDataPhoneId() {
-        return getPhoneId(getDefaultDataSubId());
+        return getPhoneId(getDefaultDataSubscriptionId());
     }
 
     /** @hide */
@@ -1061,13 +1098,13 @@
     //FIXME this is vulnerable to race conditions
     /** @hide */
     public boolean allDefaultsSelected() {
-        if (!isValidSubscriptionId(getDefaultDataSubId())) {
+        if (!isValidSubscriptionId(getDefaultDataSubscriptionId())) {
             return false;
         }
-        if (!isValidSubscriptionId(getDefaultSmsSubId())) {
+        if (!isValidSubscriptionId(getDefaultSmsSubscriptionId())) {
             return false;
         }
-        if (!isValidSubscriptionId(getDefaultVoiceSubId())) {
+        if (!isValidSubscriptionId(getDefaultVoiceSubscriptionId())) {
             return false;
         }
         return true;
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0b5aaa3..76ff47a 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1230,7 +1230,6 @@
      * on a CDMA network).
      * @param subId
      */
-    /** {@hide} */
     public String getNetworkOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, "");
@@ -1257,8 +1256,7 @@
      *
      * @param subId
      */
-    /** {@hide} */
-   public String getNetworkOperatorForSubscription(int subId) {
+    public String getNetworkOperator(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getNetworkOperatorForPhone(phoneId);
      }
@@ -1274,7 +1272,7 @@
      * @param phoneId
      * @hide
      **/
-   public String getNetworkOperatorForPhone(int phoneId) {
+    public String getNetworkOperatorForPhone(int phoneId) {
         return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, "");
      }
 
@@ -1296,7 +1294,6 @@
      *
      * @param subId
      */
-    /** {@hide} */
     public boolean isNetworkRoaming(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return Boolean.parseBoolean(getTelephonyProperty(phoneId,
@@ -1325,8 +1322,7 @@
      *
      * @param subId for which Network CountryIso is returned
      */
-    /** {@hide} */
-    public String getNetworkCountryIsoForSubscription(int subId) {
+    public String getNetworkCountryIso(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getNetworkCountryIsoForPhone(phoneId);
     }
@@ -1434,7 +1430,6 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    /** {@hide} */
    public int getNetworkType(int subId) {
        try {
            ITelephony telephony = getITelephony();
@@ -1495,7 +1490,6 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    /** {@hide} */
     public int getDataNetworkType(int subId) {
         try{
             ITelephony telephony = getITelephony();
@@ -1533,7 +1527,6 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    /** {@hide} */
     public int getVoiceNetworkType(int subId) {
         try{
             ITelephony telephony = getITelephony();
@@ -1802,10 +1795,9 @@
      * @see #getSimState
      *
      * @param subId for which SimOperator is returned
-     * @hide
      */
     public String getSimOperator(int subId) {
-        return getSimOperatorNumericForSubscription(subId);
+        return getSimOperatorNumeric(subId);
     }
 
     /**
@@ -1818,17 +1810,17 @@
      * @hide
      */
     public String getSimOperatorNumeric() {
-        int subId = SubscriptionManager.getDefaultDataSubId();
+        int subId = SubscriptionManager.getDefaultDataSubscriptionId();
         if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-            subId = SubscriptionManager.getDefaultSmsSubId();
+            subId = SubscriptionManager.getDefaultSmsSubscriptionId();
             if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-                subId = SubscriptionManager.getDefaultVoiceSubId();
+                subId = SubscriptionManager.getDefaultVoiceSubscriptionId();
                 if (!SubscriptionManager.isUsableSubIdValue(subId)) {
-                    subId = SubscriptionManager.getDefaultSubId();
+                    subId = SubscriptionManager.getDefaultSubscriptionId();
                 }
             }
         }
-        return getSimOperatorNumericForSubscription(subId);
+        return getSimOperatorNumeric(subId);
     }
 
     /**
@@ -1842,7 +1834,7 @@
      * @param subId for which SimOperator is returned
      * @hide
      */
-    public String getSimOperatorNumericForSubscription(int subId) {
+    public String getSimOperatorNumeric(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimOperatorNumericForPhone(phoneId);
     }
@@ -1879,9 +1871,8 @@
      * @see #getSimState
      *
      * @param subId for which SimOperatorName is returned
-     * @hide
      */
-    public String getSimOperatorNameForSubscription(int subId) {
+    public String getSimOperatorName(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimOperatorNameForPhone(phoneId);
     }
@@ -1907,21 +1898,8 @@
      * Returns the ISO country code equivalent for the SIM provider's country code.
      *
      * @param subId for which SimCountryIso is returned
-     *
-     * @hide
      */
     public String getSimCountryIso(int subId) {
-        return getSimCountryIsoForSubscription(subId);
-    }
-
-    /**
-     * Returns the ISO country code equivalent for the SIM provider's country code.
-     *
-     * @param subId for which SimCountryIso is returned
-     *
-     * @hide
-     */
-    public String getSimCountryIsoForSubscription(int subId) {
         int phoneId = SubscriptionManager.getPhoneId(subId);
         return getSimCountryIsoForPhone(phoneId);
     }
@@ -1955,7 +1933,6 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      */
-    /** {@hide} */
     public String getSimSerialNumber(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2044,7 +2021,6 @@
      *
      * @param subId whose subscriber id is returned
      */
-    /** {@hide} */
     public String getSubscriberId(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2087,9 +2063,8 @@
      * Requires Permission:
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      *
-     * @param subscription whose subscriber id is returned
+     * @param subId whose subscriber id is returned
      */
-    /** {@hide} */
     public String getGroupIdLevel1(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2116,7 +2091,7 @@
      * The default SMS app can also use this.
      */
     public String getLine1Number() {
-        return getLine1NumberForSubscriber(getDefaultSubscription());
+        return getLine1Number(getDefaultSubscription());
     }
 
     /**
@@ -2132,8 +2107,7 @@
      *
      * @param subId whose phone number for line 1 is returned
      */
-    /** {@hide} */
-    public String getLine1NumberForSubscriber(int subId) {
+    public String getLine1Number(int subId) {
         String number = null;
         try {
             ITelephony telephony = getITelephony();
@@ -2172,7 +2146,7 @@
      * @return true if the operation was executed correctly.
      */
     public boolean setLine1NumberForDisplay(String alphaTag, String number) {
-        return setLine1NumberForDisplayForSubscriber(getDefaultSubscription(), alphaTag, number);
+        return setLine1NumberForDisplay(getDefaultSubscription(), alphaTag, number);
     }
 
     /**
@@ -2188,9 +2162,8 @@
      * @param alphaTag alpha-tagging of the dailing nubmer
      * @param number The dialing number
      * @return true if the operation was executed correctly.
-     * @hide
      */
-    public boolean setLine1NumberForDisplayForSubscriber(int subId, String alphaTag, String number) {
+    public boolean setLine1NumberForDisplay(int subId, String alphaTag, String number) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
@@ -2211,7 +2184,7 @@
      * nobody seems to call this.
      */
     public String getLine1AlphaTag() {
-        return getLine1AlphaTagForSubscriber(getDefaultSubscription());
+        return getLine1AlphaTag(getDefaultSubscription());
     }
 
     /**
@@ -2224,8 +2197,7 @@
      * @param subId whose alphabetic identifier associated with line 1 is returned
      * nobody seems to call this.
      */
-    /** {@hide} */
-    public String getLine1AlphaTagForSubscriber(int subId) {
+    public String getLine1AlphaTag(int subId) {
         String alphaTag = null;
         try {
             ITelephony telephony = getITelephony();
@@ -2325,7 +2297,6 @@
      *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
      * @param subId whose voice mail number is returned
      */
-    /** {@hide} */
     public String getVoiceMailNumber(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2398,7 +2369,6 @@
      * @param alphaTag The alpha tag to display.
      * @param number The voicemail number.
      */
-    /** {@hide} */
     public boolean setVoiceMailNumber(int subId, String alphaTag, String number) {
         try {
             ITelephony telephony = getITelephony();
@@ -2464,7 +2434,6 @@
      * @param subId whose alphabetic identifier associated with the
      * voice mail number is returned
      */
-    /** {@hide} */
     public String getVoiceMailAlphaTag(int subId) {
         try {
             IPhoneSubInfo info = getSubscriberInfo();
@@ -2582,7 +2551,6 @@
      *
      * @param subId whose call state is returned
      */
-    /** {@hide} */
     public int getCallState(int subId) {
         try {
             ITelephony telephony = getITelephony();
@@ -2961,10 +2929,27 @@
      * @return an IccOpenLogicalChannelResponse object.
      */
     public IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID) {
+        return iccOpenLogicalChannel(getDefaultSubscription(), AID);
+    }
+
+    /**
+     * Opens a logical channel to the ICC card.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHO command.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param AID Application id. See ETSI 102.221 and 101.220.
+     * @return an IccOpenLogicalChannelResponse object.
+     */
+    public IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccOpenLogicalChannel(AID);
+                return telephony.iccOpenLogicalChannel(subId, AID);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -2985,10 +2970,28 @@
      * @return true if the channel was closed successfully.
      */
     public boolean iccCloseLogicalChannel(int channel) {
+        return iccCloseLogicalChannel(getDefaultSubscription(), channel);
+    }
+
+    /**
+     * Closes a previously opened logical channel to the ICC card.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CCHC command.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param channel is the channel id to be closed as retruned by a successful
+     *            iccOpenLogicalChannel.
+     * @return true if the channel was closed successfully.
+     */
+    public boolean iccCloseLogicalChannel(int subId, int channel) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccCloseLogicalChannel(channel);
+                return telephony.iccCloseLogicalChannel(subId, channel);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -3018,10 +3021,38 @@
      */
     public String iccTransmitApduLogicalChannel(int channel, int cla,
             int instruction, int p1, int p2, int p3, String data) {
+        return iccTransmitApduLogicalChannel(getDefaultSubscription(), channel, cla,
+                    instruction, p1, p2, p3, data);
+    }
+
+    /**
+     * Transmit an APDU to the ICC card over a logical channel.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CGLA command.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param channel is the channel id to be closed as returned by a successful
+     *            iccOpenLogicalChannel.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     */
+    public String iccTransmitApduLogicalChannel(int subId, int channel, int cla,
+            int instruction, int p1, int p2, int p3, String data) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccTransmitApduLogicalChannel(channel, cla,
+                return telephony.iccTransmitApduLogicalChannel(subId, channel, cla,
                     instruction, p1, p2, p3, data);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
@@ -3050,10 +3081,36 @@
      */
     public String iccTransmitApduBasicChannel(int cla,
             int instruction, int p1, int p2, int p3, String data) {
+        return iccTransmitApduBasicChannel(getDefaultSubscription(), cla,
+                    instruction, p1, p2, p3, data);
+    }
+
+    /**
+     * Transmit an APDU to the ICC card over the basic channel.
+     *
+     * Input parameters equivalent to TS 27.007 AT+CSIM command.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param cla Class of the APDU command.
+     * @param instruction Instruction of the APDU command.
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command. If p3 is negative a 4 byte APDU
+     *            is sent to the SIM.
+     * @param data Data to be sent with the APDU.
+     * @return The APDU response from the ICC card with the status appended at
+     *            the end.
+     */
+    public String iccTransmitApduBasicChannel(int subId, int cla,
+            int instruction, int p1, int p2, int p3, String data) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccTransmitApduBasicChannel(cla,
+                return telephony.iccTransmitApduBasicChannel(subId, cla,
                     instruction, p1, p2, p3, data);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
@@ -3078,10 +3135,31 @@
      */
     public byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
             String filePath) {
+        return iccExchangeSimIO(getDefaultSubscription(), fileID, command, p1, p2, p3, filePath);
+    }
+
+    /**
+     * Returns the response APDU for a command APDU sent through SIM_IO.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param fileID
+     * @param command
+     * @param p1 P1 value of the APDU command.
+     * @param p2 P2 value of the APDU command.
+     * @param p3 P3 value of the APDU command.
+     * @param filePath
+     * @return The APDU response.
+     */
+    public byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2,
+            int p3, String filePath) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.iccExchangeSimIO(fileID, command, p1, p2, p3, filePath);
+                return telephony.iccExchangeSimIO(subId, fileID, command, p1, p2, p3, filePath);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -3103,10 +3181,29 @@
      *         returns an empty string.
      */
     public String sendEnvelopeWithStatus(String content) {
+        return sendEnvelopeWithStatus(getDefaultSubscription(), content);
+    }
+
+    /**
+     * Send ENVELOPE to the SIM and return the response.
+     *
+     * <p>Requires Permission:
+     *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+     * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param content String containing SAT/USAT response in hexadecimal
+     *                format starting with command tag. See TS 102 223 for
+     *                details.
+     * @return The APDU response from the ICC card in hexadecimal format
+     *         with the last 4 bytes being the status word. If the command fails,
+     *         returns an empty string.
+     */
+    public String sendEnvelopeWithStatus(int subId, String content) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.sendEnvelopeWithStatus(content);
+                return telephony.sendEnvelopeWithStatus(subId, content);
         } catch (RemoteException ex) {
         } catch (NullPointerException ex) {
         }
@@ -3223,19 +3320,19 @@
      * Returns Default subscription.
      */
     private static int getDefaultSubscription() {
-        return SubscriptionManager.getDefaultSubId();
+        return SubscriptionManager.getDefaultSubscriptionId();
     }
 
     /**
      * Returns Default phone.
      */
     private static int getDefaultPhone() {
-        return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubId());
+        return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubscriptionId());
     }
 
     /** {@hide} */
     public int getDefaultSim() {
-        return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubId());
+        return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubscriptionId());
     }
 
     /**
@@ -3664,8 +3761,20 @@
      * @return true on success; false on any failure.
      */
     public boolean setPreferredNetworkTypeToGlobal() {
-        return setPreferredNetworkType(getDefaultSubscription(),
-                RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
+        return setPreferredNetworkTypeToGlobal(getDefaultSubscription());
+    }
+
+    /**
+     * Set the preferred network type to global mode which includes LTE, CDMA, EvDo and GSM/WCDMA.
+     *
+     * <p>
+     * Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
+     *
+     * @return true on success; false on any failure.
+     */
+    public boolean setPreferredNetworkTypeToGlobal(int subId) {
+        return setPreferredNetworkType(subId, RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA);
     }
 
     /**
@@ -3712,10 +3821,26 @@
      * @return true if the app has carrier privileges.
      */
     public boolean hasCarrierPrivileges() {
+        return hasCarrierPrivileges(getDefaultSubscription());
+    }
+
+    /**
+     * Has the calling application been granted carrier privileges by the carrier.
+     *
+     * If any of the packages in the calling UID has carrier privileges, the
+     * call will return true. This access is granted by the owner of the UICC
+     * card and does not depend on the registered carrier.
+     *
+     * @param subId The subscription to use.
+     * @return true if the app has carrier privileges.
+     */
+    public boolean hasCarrierPrivileges(int subId) {
         try {
             ITelephony telephony = getITelephony();
-            if (telephony != null)
-                return telephony.getCarrierPrivilegeStatus() == CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+            if (telephony != null) {
+                return telephony.getCarrierPrivilegeStatus(subId) ==
+                    CARRIER_PRIVILEGE_STATUS_HAS_ACCESS;
+            }
         } catch (RemoteException ex) {
             Rlog.e(TAG, "hasCarrierPrivileges RemoteException", ex);
         } catch (NullPointerException ex) {
@@ -3739,10 +3864,29 @@
      * @return true if the operation was executed correctly.
      */
     public boolean setOperatorBrandOverride(String brand) {
+        return setOperatorBrandOverride(getDefaultSubscription(), brand);
+    }
+
+    /**
+     * Override the branding for the current ICCID.
+     *
+     * Once set, whenever the SIM is present in the device, the service
+     * provider name (SPN) and the operator name will both be replaced by the
+     * brand value input. To unset the value, the same function should be
+     * called with a null brand value.
+     *
+     * <p>Requires that the calling app has carrier privileges.
+     * @see #hasCarrierPrivileges
+     *
+     * @param subId The subscription to use.
+     * @param brand The brand name to display/set.
+     * @return true if the operation was executed correctly.
+     */
+    public boolean setOperatorBrandOverride(int subId, String brand) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.setOperatorBrandOverride(brand);
+                return telephony.setOperatorBrandOverride(subId, brand);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setOperatorBrandOverride RemoteException", ex);
         } catch (NullPointerException ex) {
@@ -3773,10 +3917,37 @@
     public boolean setRoamingOverride(List<String> gsmRoamingList,
             List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
             List<String> cdmaNonRoamingList) {
+        return setRoamingOverride(getDefaultSubscription(), gsmRoamingList, gsmNonRoamingList,
+                cdmaRoamingList, cdmaNonRoamingList);
+    }
+
+    /**
+     * Override the roaming preference for the current ICCID.
+     *
+     * Using this call, the carrier app (see #hasCarrierPrivileges) can override
+     * the platform's notion of a network operator being considered roaming or not.
+     * The change only affects the ICCID that was active when this call was made.
+     *
+     * If null is passed as any of the input, the corresponding value is deleted.
+     *
+     * <p>Requires that the caller have carrier privilege. See #hasCarrierPrivileges.
+     *
+     * @param subId for which the roaming overrides apply.
+     * @param gsmRoamingList - List of MCCMNCs to be considered roaming for 3GPP RATs.
+     * @param gsmNonRoamingList - List of MCCMNCs to be considered not roaming for 3GPP RATs.
+     * @param cdmaRoamingList - List of SIDs to be considered roaming for 3GPP2 RATs.
+     * @param cdmaNonRoamingList - List of SIDs to be considered not roaming for 3GPP2 RATs.
+     * @return true if the operation was executed correctly.
+     *
+     * @hide
+     */
+    public boolean setRoamingOverride(int subId, List<String> gsmRoamingList,
+            List<String> gsmNonRoamingList, List<String> cdmaRoamingList,
+            List<String> cdmaNonRoamingList) {
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.setRoamingOverride(gsmRoamingList, gsmNonRoamingList,
+                return telephony.setRoamingOverride(subId, gsmRoamingList, gsmNonRoamingList,
                         cdmaRoamingList, cdmaNonRoamingList);
         } catch (RemoteException ex) {
             Rlog.e(TAG, "setRoamingOverride RemoteException", ex);
@@ -4190,7 +4361,7 @@
     /** @hide */
     @SystemApi
     public void setDataEnabled(boolean enable) {
-        setDataEnabled(SubscriptionManager.getDefaultDataSubId(), enable);
+        setDataEnabled(SubscriptionManager.getDefaultDataSubscriptionId(), enable);
     }
 
     /** @hide */
@@ -4209,7 +4380,7 @@
     /** @hide */
     @SystemApi
     public boolean getDataEnabled() {
-        return getDataEnabled(SubscriptionManager.getDefaultDataSubId());
+        return getDataEnabled(SubscriptionManager.getDefaultDataSubscriptionId());
     }
 
     /** @hide */
diff --git a/telephony/java/com/android/ims/ImsCallForwardInfo.java b/telephony/java/com/android/ims/ImsCallForwardInfo.java
index 3f8fd19..eeee0fc 100644
--- a/telephony/java/com/android/ims/ImsCallForwardInfo.java
+++ b/telephony/java/com/android/ims/ImsCallForwardInfo.java
@@ -31,6 +31,8 @@
     public int mStatus;
     // 0x91: International, 0x81: Unknown
     public int mToA;
+    // Service class
+    public int mServiceClass;
     // Number (it will not include the "sip" or "tel" URI scheme)
     public String mNumber;
     // No reply timer for CF
@@ -55,13 +57,16 @@
         out.writeInt(mToA);
         out.writeString(mNumber);
         out.writeInt(mTimeSeconds);
+        out.writeInt(mServiceClass);
     }
 
     @Override
     public String toString() {
         return super.toString() + ", Condition: " + mCondition
             + ", Status: " + ((mStatus == 0) ? "disabled" : "enabled")
-            + ", ToA: " + mToA + ", Number=" + mNumber
+            + ", ToA: " + mToA
+            + ", Service Class: " + mServiceClass
+            + ", Number=" + mNumber
             + ", Time (seconds): " + mTimeSeconds;
     }
 
@@ -71,6 +76,7 @@
         mToA = in.readInt();
         mNumber = in.readString();
         mTimeSeconds = in.readInt();
+        mServiceClass = in.readInt();
     }
 
     public static final Creator<ImsCallForwardInfo> CREATOR =
diff --git a/telephony/java/com/android/ims/ImsCallProfile.java b/telephony/java/com/android/ims/ImsCallProfile.java
index 5f84e0c..96c6243 100644
--- a/telephony/java/com/android/ims/ImsCallProfile.java
+++ b/telephony/java/com/android/ims/ImsCallProfile.java
@@ -178,7 +178,7 @@
      *  Codec: Codec info.
      *  DisplayText: Display text for the call.
      *  AdditionalCallInfo: Additional call info.
-     *  CallRadioTech: The radio tech on which the call is placed.
+     *  CallPull: Boolean value specifying if the call is a pulled call.
      */
     public static final String EXTRA_OI = "oi";
     public static final String EXTRA_CNA = "cna";
@@ -188,6 +188,7 @@
     public static final String EXTRA_CODEC = "Codec";
     public static final String EXTRA_DISPLAY_TEXT = "DisplayText";
     public static final String EXTRA_ADDITIONAL_CALL_INFO = "AdditionalCallInfo";
+    public static final String EXTRA_IS_CALL_PULL = "CallPull";
 
     /**
      * Extra key which the RIL can use to indicate the radio technology used for a call.
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index 2769a2b..558c1dc 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -84,6 +84,8 @@
     public static final int CODE_LOCAL_CALL_VOLTE_RETRY_REQUIRED = 147;
     // IMS call is already terminated (in TERMINATED state)
     public static final int CODE_LOCAL_CALL_TERMINATED = 148;
+    // Handover not feasible
+    public static final int CODE_LOCAL_HO_NOT_FEASIBLE = 149;
 
     /**
      * TIMEOUT (IMS -> Telephony)
@@ -153,6 +155,9 @@
     public static final int CODE_SIP_USER_REJECTED = 361;
     // Others
     public static final int CODE_SIP_GLOBAL_ERROR = 362;
+    // Emergency failure
+    public static final int CODE_EMERGENCY_TEMP_FAILURE = 363;
+    public static final int CODE_EMERGENCY_PERM_FAILURE = 364;
 
     /**
      * MEDIA (IMS -> Telephony)
@@ -236,12 +241,51 @@
     public static final int CODE_ANSWERED_ELSEWHERE = 1014;
 
     /**
+     * Call pull request failure from the network.
+     */
+    public static final int CODE_CALL_PULL_OUT_OF_SYNC = 1015;
+
+    /**
+     * Call ended due to being pulled onto another device.
+     */
+    public static final int CODE_CALL_END_CAUSE_CALL_PULL = 1016;
+
+    /**
+     * Supplementary services (HOLD/RESUME) failure error codes.
+     * Values for Supplemetary services failure - Failed, Cancelled and Re-Invite collision.
+     */
+    public static final int CODE_SUPP_SVC_FAILED = 1201;
+    public static final int CODE_SUPP_SVC_CANCELLED = 1202;
+    public static final int CODE_SUPP_SVC_REINVITE_COLLISION = 1203;
+
+    /**
+     * DPD Procedure received no response or send failed
+     */
+    public static final int CODE_IWLAN_DPD_FAILURE = 1300;
+
+    /**
+     * Establishment of the ePDG Tunnel Failed
+     */
+    public static final int CODE_EPDG_TUNNEL_ESTABLISH_FAILURE = 1400;
+
+    /**
+     * Re-keying of the ePDG Tunnel Failed; may not always result in teardown
+     */
+    public static final int CODE_EPDG_TUNNEL_REKEY_FAILURE = 1401;
+
+    /**
+     * Connection to the packet gateway is lost
+     */
+    public static final int CODE_EPDG_TUNNEL_LOST_CONNECTION = 1402;
+
+    /**
      * Network string error messages.
      * mExtraMessage may have these values.
      */
     public static final String EXTRA_MSG_SERVICE_NOT_AUTHORIZED
             = "Forbidden. Not Authorized for Service";
 
+
     // For main reason code
     public int mCode;
     // For the extra code value; it depends on the code value.
diff --git a/telephony/java/com/android/ims/ImsStreamMediaProfile.java b/telephony/java/com/android/ims/ImsStreamMediaProfile.java
index 5a99212..216cef5 100644
--- a/telephony/java/com/android/ims/ImsStreamMediaProfile.java
+++ b/telephony/java/com/android/ims/ImsStreamMediaProfile.java
@@ -51,6 +51,16 @@
     public static final int AUDIO_QUALITY_GSM_EFR = 8;
     public static final int AUDIO_QUALITY_GSM_FR = 9;
     public static final int AUDIO_QUALITY_GSM_HR = 10;
+    public static final int AUDIO_QUALITY_G711U = 11;
+    public static final int AUDIO_QUALITY_G723 = 12;
+    public static final int AUDIO_QUALITY_G711A = 13;
+    public static final int AUDIO_QUALITY_G722 = 14;
+    public static final int AUDIO_QUALITY_G711AB = 15;
+    public static final int AUDIO_QUALITY_G729 = 16;
+    public static final int AUDIO_QUALITY_EVS_NB = 17;
+    public static final int AUDIO_QUALITY_EVS_WB = 18;
+    public static final int AUDIO_QUALITY_EVS_SWB = 19;
+    public static final int AUDIO_QUALITY_EVS_FB = 20;
 
    /**
      * Video information
diff --git a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
index 23a69d1..04cb1f2 100644
--- a/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsRegistrationListener.aidl
@@ -17,6 +17,9 @@
 package com.android.ims.internal;
 
 import com.android.ims.ImsReasonInfo;
+
+import android.net.Uri;
+
 /**
  * A listener type for receiving notifications about the changes to
  * the IMS connection(registration).
@@ -26,15 +29,36 @@
 interface IImsRegistrationListener {
     /**
      * Notifies the application when the device is connected to the IMS network.
+     *
+     * @deprecated see {@link registrationConnectedWithRadioTech}
      */
     void registrationConnected();
 
     /**
      * Notifies the application when the device is trying to connect the IMS network.
+     *
+     * @deprecated see {@link registrationProgressingWithRadioTech}
      */
     void registrationProgressing();
 
     /**
+     * Notifies the application when the device is connected to the IMS network.
+     *
+     * @param imsRadioTech the radio access technology. Valid values are {@code
+     * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
+     */
+    void registrationConnectedWithRadioTech(int imsRadioTech);
+
+    /**
+     * Notifies the application when the device is trying to connect the IMS network.
+     *
+     * @param imsRadioTech the radio access technology. Valid values are {@code
+     * RIL_RADIO_TECHNOLOGY_*} defined in {@link ServiceState}.
+     */
+    void registrationProgressingWithRadioTech(int imsRadioTech);
+
+
+    /**
      * Notifies the application when the device is disconnected from the IMS network.
      */
     void registrationDisconnected(in ImsReasonInfo imsReasonInfo);
@@ -78,4 +102,9 @@
      * @param count The number of waiting voice messages.
      */
     void voiceMessageCountUpdate(int count);
+
+    /**
+     * Notifies the application when the list of URIs associated with IMS client is updated.
+     */
+    void registrationAssociatedUriChanged(in Uri[] uris);
 }
diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java
index be7e702..ee5a152 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfo.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfo.java
@@ -309,7 +309,7 @@
     public static CallerInfo getCallerInfo(Context context, String number) {
         if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number...");
 
-        int subId = SubscriptionManager.getDefaultSubId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         return getCallerInfo(context, number, subId);
     }
 
@@ -426,7 +426,7 @@
     // string in the phone number field.
     /* package */ CallerInfo markAsVoiceMail() {
 
-        int subId = SubscriptionManager.getDefaultSubId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         return markAsVoiceMail(subId);
 
     }
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index c754068..05cb31e 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -387,7 +387,7 @@
     public static CallerInfoAsyncQuery startQuery(int token, Context context, String number,
             OnQueryCompleteListener listener, Object cookie) {
 
-        int subId = SubscriptionManager.getDefaultSubId();
+        int subId = SubscriptionManager.getDefaultSubscriptionId();
         return startQuery(token, context, number, listener, cookie, subId);
     }
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 8172e94..bb64165 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -543,27 +543,30 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CCHO command.
      *
+     * @param subId The subscription to use.
      * @param AID Application id. See ETSI 102.221 and 101.220.
      * @return an IccOpenLogicalChannelResponse object.
      */
-    IccOpenLogicalChannelResponse iccOpenLogicalChannel(String AID);
+    IccOpenLogicalChannelResponse iccOpenLogicalChannel(int subId, String AID);
 
     /**
      * Closes a previously opened logical channel to the ICC card.
      *
      * Input parameters equivalent to TS 27.007 AT+CCHC command.
      *
+     * @param subId The subscription to use.
      * @param channel is the channel id to be closed as retruned by a
      *            successful iccOpenLogicalChannel.
      * @return true if the channel was closed successfully.
      */
-    boolean iccCloseLogicalChannel(int channel);
+    boolean iccCloseLogicalChannel(int subId, int channel);
 
     /**
      * Transmit an APDU to the ICC card over a logical channel.
      *
      * Input parameters equivalent to TS 27.007 AT+CGLA command.
      *
+     * @param subId The subscription to use.
      * @param channel is the channel id to be closed as retruned by a
      *            successful iccOpenLogicalChannel.
      * @param cla Class of the APDU command.
@@ -576,7 +579,7 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      */
-    String iccTransmitApduLogicalChannel(int channel, int cla, int instruction,
+    String iccTransmitApduLogicalChannel(int subId, int channel, int cla, int instruction,
             int p1, int p2, int p3, String data);
 
     /**
@@ -584,6 +587,7 @@
      *
      * Input parameters equivalent to TS 27.007 AT+CSIM command.
      *
+     * @param subId The subscription to use.
      * @param cla Class of the APDU command.
      * @param instruction Instruction of the APDU command.
      * @param p1 P1 value of the APDU command.
@@ -594,12 +598,13 @@
      * @return The APDU response from the ICC card with the status appended at
      *            the end.
      */
-    String iccTransmitApduBasicChannel(int cla, int instruction,
+    String iccTransmitApduBasicChannel(int subId, int cla, int instruction,
             int p1, int p2, int p3, String data);
 
     /**
      * Returns the response APDU for a command APDU sent through SIM_IO.
      *
+     * @param subId The subscription to use.
      * @param fileID
      * @param command
      * @param p1 P1 value of the APDU command.
@@ -608,12 +613,13 @@
      * @param filePath
      * @return The APDU response.
      */
-    byte[] iccExchangeSimIO(int fileID, int command, int p1, int p2, int p3,
+    byte[] iccExchangeSimIO(int subId, int fileID, int command, int p1, int p2, int p3,
             String filePath);
 
     /**
      * Send ENVELOPE to the SIM and returns the response.
      *
+     * @param subId The subscription to use.
      * @param contents  String containing SAT/USAT response in hexadecimal
      *                  format starting with command tag. See TS 102 223 for
      *                  details.
@@ -621,7 +627,7 @@
      *         being the status word. If the command fails, returns an empty
      *         string.
      */
-    String sendEnvelopeWithStatus(String content);
+    String sendEnvelopeWithStatus(int subId, String content);
 
     /**
      * Read one of the NV items defined in {@link RadioNVItems} / {@code ril_nv_items.h}.
@@ -773,9 +779,10 @@
      *
      * TODO: Add a link to documentation.
      *
+     * @param subId The subscription to use.
      * @return carrier privilege status defined in TelephonyManager.
      */
-    int getCarrierPrivilegeStatus();
+    int getCarrierPrivilegeStatus(int subId);
 
     /**
      * Similar to above, but check for the package whose name is pkgName.
@@ -847,10 +854,11 @@
      *   {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
      *  or has to be carrier app - see #hasCarrierPrivileges.
      *
+     * @param subId The subscription to use.
      * @param brand The brand name to display/set.
      * @return true if the operation was executed correctly.
      */
-    boolean setOperatorBrandOverride(String brand);
+    boolean setOperatorBrandOverride(int subId, String brand);
 
     /**
      * Override the roaming indicator for the current ICCID.
@@ -863,13 +871,14 @@
      *
      * <p>Requires that the caller have carrier privilege. See #hasCarrierPrivileges.
      *
+     * @param subId for which the roaming overrides apply.
      * @param gsmRoamingList - List of MCCMNCs to be considered roaming for 3GPP RATs.
      * @param gsmNonRoamingList - List of MCCMNCs to be considered not roaming for 3GPP RATs.
      * @param cdmaRoamingList - List of SIDs to be considered roaming for 3GPP2 RATs.
      * @param cdmaNonRoamingList - List of SIDs to be considered not roaming for 3GPP2 RATs.
      * @return true if the operation was executed correctly.
      */
-    boolean setRoamingOverride(in List<String> gsmRoamingList,
+    boolean setRoamingOverride(int subId, in List<String> gsmRoamingList,
             in List<String> gsmNonRoamingList, in List<String> cdmaRoamingList,
             in List<String> cdmaNonRoamingList);
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
index 5dffa28..069fcbf 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
@@ -16,8 +16,9 @@
 
 package com.android.internal.telephony;
 
-import android.os.Bundle;
+import com.android.internal.telephony.ITelephonyDebugSubscriber;
 
+import android.os.Bundle;
 
 /**
  * Interface used to interact with the Telephony debug service.
@@ -36,4 +37,7 @@
      * @param data optional
      */
     void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
+
+    void subscribe(in ITelephonyDebugSubscriber subscriber);
+    void unsubscribe(in ITelephonyDebugSubscriber subscriber);
 }
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
similarity index 61%
copy from wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
copy to telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
index 44849bc..64eb0f1 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
@@ -14,6 +14,21 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package com.android.internal.telephony;
 
-parcelable SubscribeSettings;
+import com.android.internal.telephony.TelephonyEvent;
+
+import android.os.Bundle;
+
+/**
+ * Interface used to subscribe for events from Telephony debug service.
+ *
+ * {@hide}
+ */
+oneway interface ITelephonyDebugSubscriber {
+
+    /**
+     * Called when Telephony debug service has events.
+     */
+    void onEvents(in TelephonyEvent[] events);
+}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 3c4c04b..bba357e 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -77,7 +77,48 @@
     int SIM_SAP_MSG_SIZE_TOO_SMALL = 34;
     int SIM_SAP_CONNECT_OK_CALL_ONGOING = 35;
     int LCE_NOT_SUPPORTED = 36;               /* Link Capacity Estimation (LCE) not supported */
-
+    int NO_MEMORY = 37;                       /* Not sufficient memory to process the request */
+    int INTERNAL_ERR = 38;                    /* Hit unexpected vendor internal error scenario */
+    int SYSTEM_ERR = 39;                      /* Hit platform or system error */
+    int MODEM_ERR = 40;                       /* Hit unexpected modem error */
+    int INVALID_STATE = 41;                   /* Can not process the request as vendor RIL is in
+                                                   invalid state. */
+    int NO_RESOURCES = 42;                    /* Not sufficient resource to process the request */
+    int SIM_ERR = 43;                         /* Received error from SIM card */
+    int INVALID_ARGUMENTS = 44;               /* Received invalid arguments in request */
+    int INVALID_SIM_STATE = 45;               /* Can not process the request in current SIM state */
+    int INVALID_MODEM_STATE = 46;             /* Can not process the request in current Modem state */
+    int INVALID_CALL_ID = 47;                 /* Received invalid call id in request */
+    int NO_SMS_TO_ACK = 48;                   /* ACK received when there is no SMS to ack */
+    int NETWORK_ERR = 49;                     /* Received error from network */
+    int REQUEST_RATE_LIMITED = 50;            /* Operation denied due to overly-frequent requests */
+    // Below is list of OEM specific error codes which can by used by OEMs in case they don't want to
+    // reveal particular replacement for Generic failure
+    int OEM_ERROR_1 = 501;
+    int OEM_ERROR_2 = 502;
+    int OEM_ERROR_3 = 503;
+    int OEM_ERROR_4 = 504;
+    int OEM_ERROR_5 = 505;
+    int OEM_ERROR_6 = 506;
+    int OEM_ERROR_7 = 507;
+    int OEM_ERROR_8 = 508;
+    int OEM_ERROR_9 = 509;
+    int OEM_ERROR_10 = 510;
+    int OEM_ERROR_11 = 511;
+    int OEM_ERROR_12 = 512;
+    int OEM_ERROR_13 = 513;
+    int OEM_ERROR_14 = 514;
+    int OEM_ERROR_15 = 515;
+    int OEM_ERROR_16 = 516;
+    int OEM_ERROR_17 = 517;
+    int OEM_ERROR_18 = 518;
+    int OEM_ERROR_19 = 519;
+    int OEM_ERROR_20 = 520;
+    int OEM_ERROR_21 = 521;
+    int OEM_ERROR_22 = 522;
+    int OEM_ERROR_23 = 523;
+    int OEM_ERROR_24 = 524;
+    int OEM_ERROR_25 = 525;
 
     /* NETWORK_MODE_* See ril.h RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE */
     int NETWORK_MODE_WCDMA_PREF     = 0; /* GSM/WCDMA (WCDMA preferred) */
@@ -109,6 +150,26 @@
     int PREFERRED_NETWORK_MODE      = SystemProperties.getInt("ro.telephony.default_network",
             NETWORK_MODE_WCDMA_PREF);
 
+    int BAND_MODE_UNSPECIFIED = 0;      //"unspecified" (selected by baseband automatically)
+    int BAND_MODE_EURO = 1;             //"EURO band" (GSM-900 / DCS-1800 / WCDMA-IMT-2000)
+    int BAND_MODE_USA = 2;              //"US band" (GSM-850 / PCS-1900 / WCDMA-850 / WCDMA-PCS-1900)
+    int BAND_MODE_JPN = 3;              //"JPN band" (WCDMA-800 / WCDMA-IMT-2000)
+    int BAND_MODE_AUS = 4;              //"AUS band" (GSM-900 / DCS-1800 / WCDMA-850 / WCDMA-IMT-2000)
+    int BAND_MODE_AUS_2 = 5;            //"AUS band 2" (GSM-900 / DCS-1800 / WCDMA-850)
+    int BAND_MODE_CELL_800 = 6;         //"Cellular" (800-MHz Band)
+    int BAND_MODE_PCS = 7;              //"PCS" (1900-MHz Band)
+    int BAND_MODE_JTACS = 8;            //"Band Class 3" (JTACS Band)
+    int BAND_MODE_KOREA_PCS = 9;        //"Band Class 4" (Korean PCS Band)
+    int BAND_MODE_5_450M = 10;          //"Band Class 5" (450-MHz Band)
+    int BAND_MODE_IMT2000 = 11;         //"Band Class 6" (2-GMHz IMT2000 Band)
+    int BAND_MODE_7_700M_2 = 12;        //"Band Class 7" (Upper 700-MHz Band)
+    int BAND_MODE_8_1800M = 13;         //"Band Class 8" (1800-MHz Band)
+    int BAND_MODE_9_900M = 14;          //"Band Class 9" (900-MHz Band)
+    int BAND_MODE_10_800M_2 = 15;       //"Band Class 10" (Secondary 800-MHz Band)
+    int BAND_MODE_EURO_PAMR_400M = 16;  //"Band Class 11" (400-MHz European PAMR Band)
+    int BAND_MODE_AWS = 17;             //"Band Class 15" (AWS Band)
+    int BAND_MODE_USA_2500M = 18;       //"Band Class 16" (US 2.5-GHz Band)
+
     int CDMA_CELL_BROADCAST_SMS_DISABLED = 1;
     int CDMA_CELL_BROADCAST_SMS_ENABLED  = 0;
 
@@ -336,6 +397,8 @@
     int RIL_REQUEST_PULL_LCEDATA = 134;
     int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
 
+    int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
+
     int RIL_UNSOL_RESPONSE_BASE = 1000;
     int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000;
     int RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED = 1001;
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
similarity index 89%
copy from wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
copy to telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
index 44849bc..1e74b31 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-package android.net.wifi.nan;
+package com.android.internal.telephony;
 
-parcelable SubscribeSettings;
+parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
new file mode 100644
index 0000000..26d466d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ *  A parcelable used in ITelephonyDebugSubscriber.aidl
+ */
+public class TelephonyEvent implements Parcelable {
+
+    final public long timestamp;
+    final public int phoneId;
+    final public int tag;
+    final public int param1;
+    final public int param2;
+    final public Bundle data;
+
+    public TelephonyEvent(long timestamp, int phoneId, int tag,
+            int param1, int param2, Bundle data) {
+        this.timestamp = timestamp;
+        this.phoneId = phoneId;
+        this.tag = tag;
+        this.param1 = param1;
+        this.param2 = param2;
+        this.data = data;
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Parcelable.Creator<TelephonyEvent> CREATOR
+            = new Parcelable.Creator<TelephonyEvent> (){
+        public TelephonyEvent createFromParcel(Parcel source) {
+            final long timestamp = source.readLong();
+            final int phoneId = source.readInt();
+            final int tag = source.readInt();
+            final int param1 = source.readInt();
+            final int param2 = source.readInt();
+            final Bundle data = source.readBundle();
+            return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
+        }
+
+        public TelephonyEvent[] newArray(int size) {
+            return new TelephonyEvent[size];
+        }
+    };
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(timestamp);
+        dest.writeInt(phoneId);
+        dest.writeInt(tag);
+        dest.writeInt(param1);
+        dest.writeInt(param2);
+        dest.writeBundle(data);
+    }
+
+    public String toString() {
+        return String.format("%d,%d,%d,%d,%d,%s",
+                timestamp, phoneId, tag, param1, param2, data);
+    }
+}
diff --git a/wifi/java/android/net/wifi/AnqpInformationElement.java b/wifi/java/android/net/wifi/AnqpInformationElement.java
new file mode 100644
index 0000000..47b7129
--- /dev/null
+++ b/wifi/java/android/net/wifi/AnqpInformationElement.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+/**
+ * This object contains the payload of an ANQP element.
+ * Vendor id is the vendor ID for the element, or 0 if it is an 802.11(u) element.
+ * Hotspot 2.0 uses the WFA Vendor ID which is 0x506f9a
+ * The payload contains the bytes of the payload, starting after the length octet(s).
+ * @hide
+ */
+public class AnqpInformationElement {
+    public static final int HOTSPOT20_VENDOR_ID = 0x506f9a;
+
+    public static final int ANQP_QUERY_LIST = 256;
+    public static final int ANQP_CAPABILITY_LIST = 257;
+    public static final int ANQP_VENUE_NAME = 258;
+    public static final int ANQP_EMERGENCY_NUMBER = 259;
+    public static final int ANQP_NWK_AUTH_TYPE = 260;
+    public static final int ANQP_ROAMING_CONSORTIUM = 261;
+    public static final int ANQP_IP_ADDR_AVAILABILITY = 262;
+    public static final int ANQP_NAI_REALM = 263;
+    public static final int ANQP_3GPP_NETWORK = 264;
+    public static final int ANQP_GEO_LOC = 265;
+    public static final int ANQP_CIVIC_LOC = 266;
+    public static final int ANQP_LOC_URI = 267;
+    public static final int ANQP_DOM_NAME = 268;
+    public static final int ANQP_EMERGENCY_ALERT = 269;
+    public static final int ANQP_TDLS_CAP = 270;
+    public static final int ANQP_EMERGENCY_NAI = 271;
+    public static final int ANQP_NEIGHBOR_REPORT = 272;
+    public static final int ANQP_VENDOR_SPEC = 56797;
+
+    public static final int HS_QUERY_LIST = 1;
+    public static final int HS_CAPABILITY_LIST = 2;
+    public static final int HS_FRIENDLY_NAME = 3;
+    public static final int HS_WAN_METRICS = 4;
+    public static final int HS_CONN_CAPABILITY = 5;
+    public static final int HS_NAI_HOME_REALM_QUERY = 6;
+    public static final int HS_OPERATING_CLASS = 7;
+    public static final int HS_OSU_PROVIDERS = 8;
+    public static final int HS_ICON_REQUEST = 10;
+    public static final int HS_ICON_FILE = 11;
+
+    private final int mVendorId;
+    private final int mElementId;
+    private final byte[] mPayload;
+
+    public AnqpInformationElement(int vendorId, int elementId, byte[] payload) {
+        mVendorId = vendorId;
+        mElementId = elementId;
+        mPayload = payload;
+    }
+
+    public int getVendorId() {
+        return mVendorId;
+    }
+
+    public int getElementId() {
+        return mElementId;
+    }
+
+    public byte[] getPayload() {
+        return mPayload;
+    }
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index bad4e9c..1c7a308 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -20,7 +20,7 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.ScanSettings;
 import android.net.wifi.ScanResult;
-import android.net.wifi.ScanInfo;
+import android.net.wifi.PasspointManagementObjectDefinition;
 import android.net.wifi.WifiConnectionStatistics;
 import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.Network;
@@ -50,6 +50,17 @@
 
     int addOrUpdateNetwork(in WifiConfiguration config);
 
+    int addPasspointManagementObject(String mo);
+
+    int modifyPasspointManagementObject(String fqdn,
+                                        in List<PasspointManagementObjectDefinition> mos);
+
+    void queryPasspointIcon(long bssid, String fileName);
+
+    int matchProviderWithCurrentNetwork(String fqdn);
+
+    void deauthenticateNetwork(long holdoff, boolean ess);
+
     boolean removeNetwork(int netId);
 
     boolean enableNetwork(int netId, boolean disableOthers);
@@ -64,10 +75,6 @@
 
     void disconnect();
 
-    List<ScanInfo> getScanInfos(String callingPackage);
-
-    void setOsuSelection(int osuID);
-
     void reconnect();
 
     void reassociate();
diff --git a/wifi/java/android/net/wifi/ScanInfo.aidl b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl
similarity index 84%
rename from wifi/java/android/net/wifi/ScanInfo.aidl
rename to wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl
index 18ae508..eb7cc39 100644
--- a/wifi/java/android/net/wifi/ScanInfo.aidl
+++ b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.aidl
@@ -1,5 +1,5 @@
 /**
- * Copyright (c) 2015, The Android Open Source Project
+ * Copyright (c) 2008, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,4 +16,4 @@
 
 package android.net.wifi;
 
-parcelable ScanInfo;
+parcelable PasspointManagementObjectDefinition;
diff --git a/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
new file mode 100644
index 0000000..9fc1706
--- /dev/null
+++ b/wifi/java/android/net/wifi/PasspointManagementObjectDefinition.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This object describes a partial tree structure in the Hotspot 2.0 release 2 management object.
+ * The object is used during subscription remediation to modify parts of an existing PPS MO
+ * tree (Hotspot 2.0 specification section 9.1).
+ * @hide
+ */
+public class PasspointManagementObjectDefinition implements Parcelable {
+    private final String mBaseUri;
+    private final String mUrn;
+    private final String mMoTree;
+
+    public PasspointManagementObjectDefinition(String baseUri, String urn, String moTree) {
+        mBaseUri = baseUri;
+        mUrn = urn;
+        mMoTree = moTree;
+    }
+
+    public String getBaseUri() {
+        return mBaseUri;
+    }
+
+    public String getUrn() {
+        return mUrn;
+    }
+
+    public String getMoTree() {
+        return mMoTree;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mBaseUri);
+        dest.writeString(mUrn);
+        dest.writeString(mMoTree);
+    }
+
+    /**
+     * Implement the Parcelable interface {@hide}
+     */
+    public static final Creator<PasspointManagementObjectDefinition> CREATOR =
+            new Creator<PasspointManagementObjectDefinition>() {
+                public PasspointManagementObjectDefinition createFromParcel(Parcel in) {
+                    return new PasspointManagementObjectDefinition(
+                            in.readString(),    /* base URI */
+                            in.readString(),    /* URN */
+                            in.readString()     /* Tree XML */
+                    );
+                }
+
+                public PasspointManagementObjectDefinition[] newArray(int size) {
+                    return new PasspointManagementObjectDefinition[size];
+                }
+            };
+}
+
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 503e4a2..249f64f 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -136,6 +136,9 @@
     public static final int REASON_INVALID_REQUEST          = -4;
     /** Do not have required permission */
     public static final int REASON_PERMISSION_DENIED        = -5;
+    /** Ranging failed because responder role is enabled in STA mode.*/
+    public static final int
+            REASON_INITIATOR_NOT_ALLOWED_WHEN_RESPONDER_ON  = -6;
 
     public static final String DESCRIPTION_KEY  = "android.net.wifi.RttManager.Description";
 
@@ -191,6 +194,8 @@
         public int preambleSupported;
         //RTT bandwidth supported
         public int bwSupported;
+        // Whether STA responder role is supported.
+        public boolean responderSupported;
 
         @Override
         public String toString() {
@@ -244,6 +249,9 @@
 
             sb.append("is supported.");
 
+            sb.append(" STA responder role is ")
+                .append(responderSupported ? "supported" : "not supported.");
+
             return sb.toString();
         }
         /** Implement the Parcelable interface {@hide} */
@@ -261,7 +269,7 @@
             dest.writeInt(lcrSupported ? 1 : 0);
             dest.writeInt(preambleSupported);
             dest.writeInt(bwSupported);
-
+            dest.writeInt(responderSupported ? 1 : 0);
         }
 
         /** Implement the Parcelable interface {@hide} */
@@ -275,6 +283,7 @@
                         capabilities.lcrSupported = in.readInt() == 1 ? true : false;
                         capabilities.preambleSupported = in.readInt();
                         capabilities.bwSupported = in.readInt();
+                        capabilities.responderSupported = (in.readInt() == 1);
                         return capabilities;
                     }
                 /** Implement the Parcelable interface {@hide} */
@@ -315,6 +324,11 @@
         public int requestType;
 
         /**
+         * Whether the secure RTT protocol needs to be used for ranging this peer device.
+         */
+        public boolean secure;
+
+        /**
          * mac address of the device being ranged
          * Default value: null
          */
@@ -469,6 +483,7 @@
                 for (RttParams params : mParams) {
                     dest.writeInt(params.deviceType);
                     dest.writeInt(params.requestType);
+                    dest.writeByte(params.secure ? (byte) 1 : 0);
                     dest.writeString(params.bssid);
                     dest.writeInt(params.channelWidth);
                     dest.writeInt(params.frequency);
@@ -506,6 +521,7 @@
                             params[i] = new RttParams();
                             params[i].deviceType = in.readInt();
                             params[i].requestType = in.readInt();
+                            params[i].secure = (in.readByte() != 0);
                             params[i].bssid = in.readString();
                             params[i].channelWidth = in.readInt();
                             params[i].frequency = in.readInt();
@@ -681,6 +697,11 @@
 
         /** LCR information Element, only available to double side RTT. */
         public WifiInformationElement LCR;
+
+        /**
+         * Whether the secure RTT protocol was used for ranging.
+         */
+        public boolean secure;
     }
 
 
@@ -733,6 +754,7 @@
                         dest.writeInt((byte) result.LCR.data.length);
                         dest.writeByte(result.LCR.id);
                     }
+                    dest.writeByte(result.secure ? (byte) 1 : 0);
                 }
             } else {
                 dest.writeInt(0);
@@ -787,6 +809,7 @@
                                 results[i].LCR.data = new byte[length];
                                 in.readByteArray(results[i].LCR.data);
                             }
+                            results[i].secure = (in.readByte() != 0);
                         }
 
                         ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
@@ -898,6 +921,160 @@
         sAsyncChannel.sendMessage(CMD_OP_STOP_RANGING, 0, removeListener(listener));
     }
 
+    /**
+     * Callbacks for responder operations.
+     * <p>
+     * A {@link ResponderCallback} is the handle to the calling client. {@link RttManager} will keep
+     * a reference to the callback for the entire period when responder is enabled. The same
+     * callback as used in enabling responder needs to be passed for disabling responder.
+     * The client can freely destroy or reuse the callback after {@link RttManager#disableResponder}
+     * is called.
+     */
+    public abstract static class ResponderCallback {
+        /** Callback when responder is enabled. */
+        public abstract void onResponderEnabled(ResponderConfig config);
+        /** Callback when enabling responder failed. */
+        public abstract void onResponderEnableFailure(int reason);
+        // TODO: consider adding onResponderAborted once it's supported.
+    }
+
+    /**
+     * Enable Wi-Fi RTT responder mode on the device. The enabling result will be delivered via
+     * {@code callback}.
+     * <p>
+     * Note calling this method with the same callback when the responder is already enabled won't
+     * change the responder state, a cached {@link ResponderConfig} from the last enabling will be
+     * returned through the callback.
+     *
+     * @param callback Callback for responder enabling/disabling result.
+     * @throws IllegalArgumentException If {@code callback} is null.
+     */
+    public void enableResponder(ResponderCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        validateChannel();
+        int key = putListenerIfAbsent(callback);
+        sAsyncChannel.sendMessage(CMD_OP_ENABLE_RESPONDER, 0, key);
+    }
+
+    /**
+     * Disable Wi-Fi RTT responder mode on the device. The {@code callback} needs to be the
+     * same one used in {@link #enableResponder(ResponderCallback)}.
+     * <p>
+     * Calling this method when responder isn't enabled won't have any effect. The callback can be
+     * reused for enabling responder after this method is called.
+     *
+     * @param callback The same callback used for enabling responder.
+     * @throws IllegalArgumentException If {@code callback} is null.
+     */
+    public void disableResponder(ResponderCallback callback) {
+        if (callback == null) {
+            throw new IllegalArgumentException("callback cannot be null");
+        }
+        validateChannel();
+        int key = removeListener(callback);
+        if (key == INVALID_KEY) {
+            Log.e(TAG, "responder not enabled yet");
+            return;
+        }
+        sAsyncChannel.sendMessage(CMD_OP_DISABLE_RESPONDER, 0, key);
+    }
+
+    /**
+     * Configuration used for RTT responder mode. The configuration information can be used by a
+     * peer device to range the responder.
+     *
+     * @see ScanResult
+     */
+    public static class ResponderConfig implements Parcelable {
+
+        // TODO: make all fields final once we can get mac address from responder HAL APIs.
+        /**
+         * Wi-Fi mac address used for responder mode.
+         */
+        public String macAddress = "";
+
+        /**
+         * The primary 20 MHz frequency (in MHz) of the channel where responder is enabled.
+         * @see ScanResult#frequency
+         */
+        public int frequency;
+
+        /**
+         * Center frequency of the channel where responder is enabled on. Only in use when channel
+         * width is at least 40MHz.
+         * @see ScanResult#centerFreq0
+         */
+        public int centerFreq0;
+
+        /**
+         * Center frequency of the second segment when channel width is 80 + 80 MHz.
+         * @see ScanResult#centerFreq1
+         */
+        public int centerFreq1;
+
+        /**
+         * Width of the channel where responder is enabled on.
+         * @see ScanResult#channelWidth
+         */
+        public int channelWidth;
+
+        /**
+         * Preamble supported by responder.
+         */
+        public int preamble;
+
+        @Override
+        public String toString() {
+            StringBuilder builder = new StringBuilder();
+            builder.append("macAddress = ").append(macAddress)
+                    .append(" frequency = ").append(frequency)
+                    .append(" centerFreq0 = ").append(centerFreq0)
+                    .append(" centerFreq1 = ").append(centerFreq1)
+                    .append(" channelWidth = ").append(channelWidth)
+                    .append(" preamble = ").append(preamble);
+            return builder.toString();
+        }
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeString(macAddress);
+            dest.writeInt(frequency);
+            dest.writeInt(centerFreq0);
+            dest.writeInt(centerFreq1);
+            dest.writeInt(channelWidth);
+            dest.writeInt(preamble);
+        }
+
+        /** Implement {@link Parcelable} interface */
+        public static final Parcelable.Creator<ResponderConfig> CREATOR =
+                new Parcelable.Creator<ResponderConfig>() {
+            @Override
+            public ResponderConfig createFromParcel(Parcel in) {
+                ResponderConfig config = new ResponderConfig();
+                config.macAddress = in.readString();
+                config.frequency = in.readInt();
+                config.centerFreq0 = in.readInt();
+                config.centerFreq1 = in.readInt();
+                config.channelWidth = in.readInt();
+                config.preamble = in.readInt();
+                return config;
+            }
+
+            @Override
+            public ResponderConfig[] newArray(int size) {
+                return new ResponderConfig[size];
+            }
+        };
+
+    }
+
     /* private methods */
     public static final int BASE = Protocol.BASE_WIFI_RTT_MANAGER;
 
@@ -906,6 +1083,12 @@
     public static final int CMD_OP_FAILED               = BASE + 2;
     public static final int CMD_OP_SUCCEEDED            = BASE + 3;
     public static final int CMD_OP_ABORTED              = BASE + 4;
+    public static final int CMD_OP_ENABLE_RESPONDER     = BASE + 5;
+    public static final int CMD_OP_DISABLE_RESPONDER    = BASE + 6;
+    public static final int
+            CMD_OP_ENALBE_RESPONDER_SUCCEEDED           = BASE + 7;
+    public static final int
+            CMD_OP_ENALBE_RESPONDER_FAILED              = BASE + 8;
 
     private Context mContext;
     private IRttManager mService;
@@ -992,6 +1175,23 @@
         return key;
     }
 
+    // Insert a listener if it doesn't exist in sListenerMap. Returns the key of the listener.
+    private static int putListenerIfAbsent(Object listener) {
+        if (listener == null) return INVALID_KEY;
+        synchronized (sListenerMapLock) {
+            int key = getListenerKey(listener);
+            if (key != INVALID_KEY) {
+                return key;
+            }
+            do {
+                key = sListenerKey++;
+            } while (key == INVALID_KEY);
+            sListenerMap.put(key, listener);
+            return key;
+        }
+
+    }
+
     private static Object getListener(int key) {
         if (key == INVALID_KEY) return null;
         synchronized (sListenerMapLock) {
@@ -1047,9 +1247,9 @@
                         // to fail and throw an exception
                         sAsyncChannel = null;
                     }
-                    sConnected.countDown();
                     return;
                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
+                    sConnected.countDown();
                     return;
                 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
                     Log.e(TAG, "Channel connection lost");
@@ -1082,6 +1282,14 @@
                     ((RttListener) listener).onAborted();
                     removeListener(msg.arg2);
                     break;
+                case CMD_OP_ENALBE_RESPONDER_SUCCEEDED:
+                    ResponderConfig config = (ResponderConfig) msg.obj;
+                    ((ResponderCallback) (listener)).onResponderEnabled(config);
+                    break;
+                case CMD_OP_ENALBE_RESPONDER_FAILED:
+                    ((ResponderCallback) (listener)).onResponderEnableFailure(msg.arg1);
+                    removeListener(msg.arg2);
+                    break;
                 default:
                     if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
                     return;
diff --git a/wifi/java/android/net/wifi/ScanInfo.java b/wifi/java/android/net/wifi/ScanInfo.java
deleted file mode 100644
index 39186fa..0000000
--- a/wifi/java/android/net/wifi/ScanInfo.java
+++ /dev/null
@@ -1,189 +0,0 @@
-package android.net.wifi;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class ScanInfo implements Parcelable {
-    private final ScanResult mScanResult;
-
-    private final long mBSSID;          // The BSSID of the best AP with an SSID matching the OSU
-    private final int mRSSI;            // RSSI of the AP with BSSID
-    private final String mSSID;         // The SSID to connect to for an OSU connection.
-    private final String mName;
-    private final String mServiceDescription;
-    private final String mIconType;
-    private final byte[] mIconData;
-    private final int mOSUIdentity;
-
-    public ScanInfo(ScanResult scanResult) {
-        mScanResult = scanResult;
-
-        mBSSID = -1;
-        mRSSI = -1;
-        mSSID = null;
-        mName = null;
-        mServiceDescription = null;
-        mIconType = null;
-        mIconData = null;
-        mOSUIdentity = -1;
-    }
-
-    public ScanInfo(long BSSID, int rssi, String SSID, String name, String serviceDescription,
-                    String iconType, byte[] iconData, int OSUIdentity) {
-        mBSSID = BSSID;
-        mRSSI = rssi;
-        mSSID = SSID;
-        mName = name;
-        mServiceDescription = serviceDescription;
-        mIconType = iconType;
-        mIconData = iconData;
-        mOSUIdentity = OSUIdentity;
-
-        mScanResult = null;
-    }
-
-    /**
-     * Get the scan result of this ScanInfo.
-     * @return The ScanResult, if this ScanInfo contains a one. If the ScanInfo contains
-     * OSU information getScanResult will return null.
-     */
-    public ScanResult getScanResult() {
-        return mScanResult;
-    }
-
-    /**
-     * OSU only: The BSSID of the AP who advertises the OSU SSID. This value is not guaranteed to
-     * be correct; In the somewhat unlikely case that multiple APs advertise OSU SSIDs that matches
-     * an OSU information element returned through ANQP and one of those is not related to an OSU
-     * there is a (slight) risk that the BSSID is for a "spoof" OSU.
-     * The matching algorithm that produces the ScanInfo objects makes a best effort to get the
-     * matching right though and since it is (a) fair to assume that the OSU SSID resides on the
-     * same AP as the one advertising the OSU information, and (b) BSSIDs for multi-SSID APs are
-     * typically adjacent to each other, matching will prefer the BSSID closest to the advertising
-     * APs BSSID if multiple SSIDs match.
-     * @return The BSSID.
-     */
-    public long getBssid() {
-        return mBSSID;
-    }
-
-    /**
-     * OSU only.
-     * @return The signal level of the AP associated with the BSSID from getBSSID.
-     */
-    public int getRssi() {
-        return mRSSI;
-    }
-
-    /**
-     * OSU only.
-     * @return The SSID of the AP to which to associate to establish an OSU connection.
-     */
-    public String getSsid() {
-        return mSSID;
-    }
-
-    /**
-     * OSU only.
-     * @return The name of the Service Provider of the OSU.
-     */
-    public String getName() {
-        return mName;
-    }
-
-    /**
-     * OSU only.
-     * @return The service description of the OSU.
-     */
-    public String getServiceDescription() {
-        return mServiceDescription;
-    }
-
-    /**
-     * OSU only.
-     * Get the type of icon that icon data represents, e.g. JPG, PNG etc. This field is formatted
-     * using standard MIME encodings per RFC-4288 and IANA MIME media types.
-     * @return The icon type in icon data.
-     */
-    public String getIconType() {
-        return mIconType;
-    }
-
-    /**
-     * OSU only.
-     * @return The binary data of the icon.
-     */
-    public byte[] getIconData() {
-        return mIconData;
-    }
-
-    /**
-     * OSU only.
-     * @return a unique identity for the OSU. This value is generated by the framework and should
-     * be used to uniquely identify a specific OSU. Please note that values may be reused after
-     * a very long time-span (in any normal scenario, likely years) and implementations should make
-     * sure to not rely on any long term persisted values.
-     */
-    public int getOsuIdentity() {
-        return mOSUIdentity;
-    }
-
-    private static final int ScanResultMarker = 0;
-    private static final int OSUMarker = 1;
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final Creator<ScanInfo> CREATOR =
-            new Creator<ScanInfo>() {
-                @Override
-                public ScanInfo createFromParcel(Parcel source) {
-                    int marker = source.readInt();
-                    if (marker == ScanResultMarker) {
-                        return new ScanInfo(ScanResult.CREATOR.createFromParcel(source));
-                    }
-                    else if (marker == OSUMarker) {
-                        return new ScanInfo(
-                                source.readLong(),
-                                source.readInt(),
-                                source.readString(),
-                                source.readString(),
-                                source.readString(),
-                                source.readString(),
-                                source.createByteArray(),
-                                source.readInt()
-                                );
-                    }
-                    else {
-                        throw new RuntimeException("Bad ScanInfo data");
-                    }
-                }
-
-                @Override
-                public ScanInfo[] newArray(int size) {
-                    return new ScanInfo[0];
-                }
-            };
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        if (mScanResult != null) {
-            dest.writeInt(ScanResultMarker);
-            mScanResult.writeToParcel(dest, flags);
-            return;
-        }
-
-        dest.writeInt(OSUMarker);
-        dest.writeLong(mBSSID);
-        dest.writeInt(mRSSI);
-        dest.writeString(mSSID);
-        dest.writeString(mName);
-        dest.writeString(mServiceDescription);
-        dest.writeString(mIconType);
-        dest.writeByteArray(mIconData);
-        dest.writeInt(mOSUIdentity);
-    }
-}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index dc06789..a46aaec 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -18,7 +18,9 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Describes information about a detected access point. In addition
@@ -41,6 +43,19 @@
      * The address of the access point.
      */
     public String BSSID;
+
+    /**
+     * The HESSID from the beacon.
+     * @hide
+     */
+    public long hessid;
+
+    /**
+     * The ANQP Domain ID from the Hotspot 2.0 Indication element, if present.
+     * @hide
+     */
+    public int anqpDomainId;
+
     /**
      * Describes the authentication, key management, and encryption schemes
      * supported by the access point.
@@ -145,21 +160,6 @@
         }
     }
 
-    /** @hide */
-    public static final int ENABLED                                          = 0;
-    /** @hide */
-    public static final int AUTO_ROAM_DISABLED                               = 16;
-    /** @hide */
-    public static final int AUTO_JOIN_DISABLED                               = 32;
-    /** @hide */
-    public static final int AUTHENTICATION_ERROR                              = 128;
-
-    /**
-     * Status: indicating join status
-     * @hide
-     */
-    public int autoJoinStatus;
-
     /**
      * num IP configuration failures
      * @hide
@@ -172,17 +172,6 @@
      */
     public long blackListTimestamp;
 
-    /** @hide **/
-    public void setAutoJoinStatus(int status) {
-        if (status < 0) status = 0;
-        if (status == 0) {
-            blackListTimestamp = 0;
-        }  else if (status > autoJoinStatus) {
-            blackListTimestamp = System.currentTimeMillis();
-        }
-        autoJoinStatus = status;
-    }
-
     /**
      * Status: indicating the scan result is not a result
      * that is part of user's saved configurations
@@ -301,6 +290,12 @@
 
     /**
      *  @hide
+     * anqp lines from supplicant BSS response
+     */
+    public List<String> anqpLines;
+
+    /**
+     *  @hide
      * storing the raw bytes of full result IEs
      **/
     public byte[] bytes;
@@ -310,7 +305,9 @@
      */
     public static class InformationElement {
         public static final int EID_SSID = 0;
+        public static final int EID_TIM = 5;
         public static final int EID_BSS_LOAD = 11;
+        public static final int EID_RSN = 48;
         public static final int EID_HT_OPERATION = 61;
         public static final int EID_INTERWORKING = 107;
         public static final int EID_ROAMING_CONSORTIUM = 111;
@@ -333,14 +330,27 @@
     /** information elements found in the beacon
      * @hide
      */
-    public InformationElement informationElements[];
+    public InformationElement[] informationElements;
+
+    /** ANQP response elements.
+     * @hide
+     */
+    public AnqpInformationElement[] anqpElements;
 
     /** {@hide} */
-    public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
-            long tsf) {
+    public ScanResult(WifiSsid wifiSsid, String BSSID, long hessid, int anqpDomainId,
+            byte[] osuProviders, String caps, int level, int frequency, long tsf) {
         this.wifiSsid = wifiSsid;
         this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
         this.BSSID = BSSID;
+        this.hessid = hessid;
+        this.anqpDomainId = anqpDomainId;
+        if (osuProviders != null) {
+            this.anqpElements = new AnqpInformationElement[1];
+            this.anqpElements[0] =
+                    new AnqpInformationElement(AnqpInformationElement.HOTSPOT20_VENDOR_ID,
+                            AnqpInformationElement.HS_OSU_PROVIDERS, osuProviders);
+        }
         this.capabilities = caps;
         this.level = level;
         this.frequency = frequency;
@@ -372,11 +382,14 @@
     }
 
     /** {@hide} */
-    public ScanResult(String Ssid, String BSSID, String caps, int level, int frequency,
+    public ScanResult(String Ssid, String BSSID, long hessid, int anqpDomainId, String caps,
+            int level, int frequency,
             long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1,
             boolean is80211McRTTResponder) {
         this.SSID = Ssid;
         this.BSSID = BSSID;
+        this.hessid = hessid;
+        this.anqpDomainId = anqpDomainId;
         this.capabilities = caps;
         this.level = level;
         this.frequency = frequency;
@@ -394,11 +407,12 @@
     }
 
     /** {@hide} */
-    public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, String caps, int level,
+    public ScanResult(WifiSsid wifiSsid, String Ssid, String BSSID, long hessid, int anqpDomainId,
+                  String caps, int level,
                   int frequency, long tsf, int distCm, int distSdCm, int channelWidth,
                   int centerFreq0, int centerFreq1, boolean is80211McRTTResponder) {
-        this(Ssid, BSSID, caps,level, frequency, tsf, distCm, distSdCm, channelWidth, centerFreq0,
-                centerFreq1, is80211McRTTResponder);
+        this(Ssid, BSSID, hessid, anqpDomainId, caps, level, frequency, tsf, distCm,
+                distSdCm, channelWidth, centerFreq0, centerFreq1, is80211McRTTResponder);
         this.wifiSsid = wifiSsid;
     }
 
@@ -408,6 +422,10 @@
             wifiSsid = source.wifiSsid;
             SSID = source.SSID;
             BSSID = source.BSSID;
+            hessid = source.hessid;
+            anqpDomainId = source.anqpDomainId;
+            informationElements = source.informationElements;
+            anqpElements = source.anqpElements;
             capabilities = source.capabilities;
             level = source.level;
             frequency = source.frequency;
@@ -418,7 +436,6 @@
             distanceCm = source.distanceCm;
             distanceSdCm = source.distanceSdCm;
             seen = source.seen;
-            autoJoinStatus = source.autoJoinStatus;
             untrusted = source.untrusted;
             numConnection = source.numConnection;
             numUsage = source.numUsage;
@@ -462,9 +479,6 @@
 
         sb.append(", passpoint: ");
         sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no");
-        if (autoJoinStatus != 0) {
-            sb.append(", status: ").append(autoJoinStatus);
-        }
         sb.append(", ChannelBandwidth: ").append(channelWidth);
         sb.append(", centerFreq0: ").append(centerFreq0);
         sb.append(", centerFreq1: ").append(centerFreq1);
@@ -488,6 +502,8 @@
         }
         dest.writeString(SSID);
         dest.writeString(BSSID);
+        dest.writeLong(hessid);
+        dest.writeInt(anqpDomainId);
         dest.writeString(capabilities);
         dest.writeInt(level);
         dest.writeInt(frequency);
@@ -498,7 +514,6 @@
         dest.writeInt(centerFreq0);
         dest.writeInt(centerFreq1);
         dest.writeLong(seen);
-        dest.writeInt(autoJoinStatus);
         dest.writeInt(untrusted ? 1 : 0);
         dest.writeInt(numConnection);
         dest.writeInt(numUsage);
@@ -518,6 +533,27 @@
         } else {
             dest.writeInt(0);
         }
+
+        if (anqpLines != null) {
+            dest.writeInt(anqpLines.size());
+            for (int i = 0; i < anqpLines.size(); i++) {
+                dest.writeString(anqpLines.get(i));
+            }
+        }
+        else {
+            dest.writeInt(0);
+        }
+        if (anqpElements != null) {
+            dest.writeInt(anqpElements.length);
+            for (AnqpInformationElement element : anqpElements) {
+                dest.writeInt(element.getVendorId());
+                dest.writeInt(element.getElementId());
+                dest.writeInt(element.getPayload().length);
+                dest.writeByteArray(element.getPayload());
+            }
+        } else {
+            dest.writeInt(0);
+        }
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -529,23 +565,25 @@
                     wifiSsid = WifiSsid.CREATOR.createFromParcel(in);
                 }
                 ScanResult sr = new ScanResult(
-                    wifiSsid,
-                    in.readString(),                    /* SSID  */
-                    in.readString(),                    /* BSSID */
-                    in.readString(),                    /* capabilities */
-                    in.readInt(),                       /* level */
-                    in.readInt(),                       /* frequency */
-                    in.readLong(),                      /* timestamp */
-                    in.readInt(),                       /* distanceCm */
-                    in.readInt(),                       /* distanceSdCm */
-                    in.readInt(),                       /* channelWidth */
-                    in.readInt(),                       /* centerFreq0 */
-                    in.readInt(),                       /* centerFreq1 */
-                    false                               /* rtt responder, fixed with flags below */
+                        wifiSsid,
+                        in.readString(),                    /* SSID  */
+                        in.readString(),                    /* BSSID */
+                        in.readLong(),                      /* HESSID */
+                        in.readInt(),                       /* ANQP Domain ID */
+                        in.readString(),                    /* capabilities */
+                        in.readInt(),                       /* level */
+                        in.readInt(),                       /* frequency */
+                        in.readLong(),                      /* timestamp */
+                        in.readInt(),                       /* distanceCm */
+                        in.readInt(),                       /* distanceSdCm */
+                        in.readInt(),                       /* channelWidth */
+                        in.readInt(),                       /* centerFreq0 */
+                        in.readInt(),                       /* centerFreq1 */
+                        false                               /* rtt responder,
+                                                               fixed with flags below */
                 );
 
                 sr.seen = in.readLong();
-                sr.autoJoinStatus = in.readInt();
                 sr.untrusted = in.readInt() != 0;
                 sr.numConnection = in.readInt();
                 sr.numUsage = in.readInt();
@@ -565,6 +603,27 @@
                         in.readByteArray(sr.informationElements[i].bytes);
                     }
                 }
+
+                n = in.readInt();
+                if (n != 0) {
+                    sr.anqpLines = new ArrayList<String>();
+                    for (int i = 0; i < n; i++) {
+                        sr.anqpLines.add(in.readString());
+                    }
+                }
+                n = in.readInt();
+                if (n != 0) {
+                    sr.anqpElements = new AnqpInformationElement[n];
+                    for (int i = 0; i < n; i++) {
+                        int vendorId = in.readInt();
+                        int elementId = in.readInt();
+                        int len = in.readInt();
+                        byte[] payload = new byte[len];
+                        in.readByteArray(payload);
+                        sr.anqpElements[i] =
+                                new AnqpInformationElement(vendorId, elementId, payload);
+                    }
+                }
                 return sr;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 8838f3f..472d1ef 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -26,7 +26,12 @@
 import android.os.Parcelable;
 import android.os.UserHandle;
 import android.text.TextUtils;
+import android.util.BackupUtils;
 
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.BitSet;
 import java.util.HashMap;
@@ -37,6 +42,10 @@
  */
 public class WifiConfiguration implements Parcelable {
     private static final String TAG = "WifiConfiguration";
+    /**
+     * Current Version of the Backup Serializer.
+    */
+    private static final int BACKUP_VERSION = 2;
     /** {@hide} */
     public static final String ssidVarName = "ssid";
     /** {@hide} */
@@ -58,6 +67,9 @@
     /** {@hide} */
     public static final int INVALID_NETWORK_ID = -1;
 
+    /** {@hide} */
+    private String mPasspointManagementObjectTree;
+
     /**
      * Recognized key management schemes.
      */
@@ -79,11 +91,16 @@
           * @hide
           */
         public static final int WPA2_PSK = 4;
+        /**
+         * Hotspot 2.0 r2 OSEN:
+         * @hide
+         */
+        public static final int OSEN = 5;
 
         public static final String varName = "key_mgmt";
 
         public static final String[] strings = { "NONE", "WPA_PSK", "WPA_EAP", "IEEE8021X",
-                "WPA2_PSK" };
+                "WPA2_PSK", "OSEN" };
     }
 
     /**
@@ -96,10 +113,14 @@
         public static final int WPA = 0;
         /** WPA2/IEEE 802.11i */
         public static final int RSN = 1;
+        /** HS2.0 r2 OSEN
+         * @hide
+         */
+        public static final int OSEN = 2;
 
         public static final String varName = "proto";
 
-        public static final String[] strings = { "WPA", "RSN" };
+        public static final String[] strings = { "WPA", "RSN", "OSEN" };
     }
 
     /**
@@ -158,10 +179,15 @@
         public static final int TKIP = 2;
         /** AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0] */
         public static final int CCMP = 3;
+        /** Hotspot 2.0 r2 OSEN
+         * @hide
+         */
+        public static final int GTK_NOT_USED = 4;
 
         public static final String varName = "group";
 
-        public static final String[] strings = { "WEP40", "WEP104", "TKIP", "CCMP" };
+        public static final String[] strings =
+                { "WEP40", "WEP104", "TKIP", "CCMP", "GTK_NOT_USED" };
     }
 
     /** Possible status of a network configuration. */
@@ -212,12 +238,24 @@
     public String BSSID;
 
     /**
+     * 2GHz band.
+     * @hide
+     */
+    public static final int AP_BAND_2GHZ = 0;
+
+    /**
+     * 5GHz band.
+     * @hide
+     */
+    public static final int AP_BAND_5GHZ = 1;
+
+    /**
      * The band which AP resides on
      * 0-2G  1-5G
      * By default, 2G is chosen
      * @hide
      */
-    public int apBand = 0;
+    public int apBand = AP_BAND_2GHZ;
 
     /**
      * The channel which AP resides on,currently, US only
@@ -364,6 +402,15 @@
 
     /**
      * @hide
+     * The number of beacon intervals between Delivery Traffic Indication Maps (DTIM)
+     * This value is populated from scan results that contain Beacon Frames, which are infrequent.
+     * The value is not guaranteed to be set or current (Although it SHOULDNT change once set)
+     * Valid values are from 1 - 255. Initialized here as 0, use this to check if set.
+     */
+    public int dtimInterval = 0;
+
+    /**
+     * @hide
      * Uid of app creating the configuration
      */
     @SystemApi
@@ -703,24 +750,6 @@
      */
     public int numUserTriggeredJoinAttempts;
 
-    /**
-     * @hide
-     * Connect choices
-     *
-     * remember the keys identifying the known WifiConfiguration over which this configuration
-     * was preferred by user or a "WiFi Network Management app", that is,
-     * a WifiManager.CONNECT_NETWORK or SELECT_NETWORK was received while this configuration
-     * was visible to the user:
-     * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
-     *
-     * The integer represents the configuration's RSSI at that time (useful?)
-     *
-     * The overall auto-join algorithm make use of past connect choice so as to sort configuration,
-     * the exact algorithm still fluctuating as of 5/7/2014
-     *
-     */
-    public HashMap<String, Integer> connectChoices;
-
     /** @hide
      * Boost given to RSSI on a home network for the purpose of calculating the score
      * This adds stickiness to home networks, as defined by:
@@ -830,6 +859,16 @@
          */
         public static final long INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP = -1L;
 
+        /**
+         *  This constant indicates the current configuration has connect choice set
+         */
+        private static final int CONNECT_CHOICE_EXISTS = 1;
+
+        /**
+         *  This constant indicates the current configuration does not have connect choice set
+         */
+        private static final int CONNECT_CHOICE_NOT_EXISTS = -1;
+
         // fields for QualityNetwork Selection
         /**
          * Network selection status, should be in one of three status: enable, temporaily disabled
@@ -853,7 +892,128 @@
         private int[] mNetworkSeclectionDisableCounter = new int[NETWORK_SELECTION_DISABLED_MAX];
 
         /**
-         * return current Quality network selection status in String (for debug purpose)
+         * Connect Choice over this configuration
+         *
+         * When current wifi configuration is visible to the user but user explicitly choose to
+         * connect to another network X, the another networks X's configure key will be stored here.
+         * We will consider user has a preference of X over this network. And in the future,
+         * network selection will always give X a higher preference over this configuration.
+         * configKey is : "SSID"-WEP-WPA_PSK-WPA_EAP
+         */
+        private String mConnectChoice;
+
+        /**
+         * The system timestamp when we records the connectChoice. This value is obtained from
+         * System.currentTimeMillis
+         */
+        private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP;
+
+        /**
+         * Used to cache the temporary candidate during the network selection procedure. It will be
+         * kept updating once a new scan result has a higher score than current one
+         */
+        private ScanResult mCandidate;
+
+        /**
+         * Used to cache the score of the current temporary candidate during the network
+         * selection procedure.
+         */
+        private int mCandidateScore;
+
+        /**
+         * Indicate whether this network is visible in latest Qualified Network Selection. This
+         * means there is scan result found related to this Configuration and meet the minimum
+         * requirement. The saved network need not join latest Qualified Network Selection. For
+         * example, it is disabled. True means network is visible in latest Qualified Network
+         * Selection and false means network is invisible
+         */
+        private boolean mSeenInLastQualifiedNetworkSelection;
+
+        /**
+         * set whether this network is visible in latest Qualified Network Selection
+         * @param seen value set to candidate
+         */
+        public void setSeenInLastQualifiedNetworkSelection(boolean seen) {
+            mSeenInLastQualifiedNetworkSelection =  seen;
+        }
+
+        /**
+         * get whether this network is visible in latest Qualified Network Selection
+         * @return returns true -- network is visible in latest Qualified Network Selection
+         *         false -- network is invisible in latest Qualified Network Selection
+         */
+        public boolean getSeenInLastQualifiedNetworkSelection() {
+            return mSeenInLastQualifiedNetworkSelection;
+        }
+        /**
+         * set the temporary candidate of current network selection procedure
+         * @param scanCandidate {@link ScanResult} the candidate set to mCandidate
+         */
+        public void setCandidate(ScanResult scanCandidate) {
+            mCandidate = scanCandidate;
+        }
+
+        /**
+         * get the temporary candidate of current network selection procedure
+         * @return  returns {@link ScanResult} temporary candidate of current network selection
+         * procedure
+         */
+        public ScanResult getCandidate() {
+            return mCandidate;
+        }
+
+        /**
+         * set the score of the temporary candidate of current network selection procedure
+         * @param score value set to mCandidateScore
+         */
+        public void setCandidateScore(int score) {
+            mCandidateScore = score;
+        }
+
+        /**
+         * get the score of the temporary candidate of current network selection procedure
+         * @return returns score of the temporary candidate of current network selection procedure
+         */
+        public int getCandidateScore() {
+            return mCandidateScore;
+        }
+
+        /**
+         * get user preferred choice over this configuration
+         *@return returns configKey of user preferred choice over this configuration
+         */
+        public String getConnectChoice() {
+            return mConnectChoice;
+        }
+
+        /**
+         * set user preferred choice over this configuration
+         * @param newConnectChoice, the configKey of user preferred choice over this configuration
+         */
+        public void setConnectChoice(String newConnectChoice) {
+            mConnectChoice = newConnectChoice;
+        }
+
+        /**
+         * get the timeStamp when user select a choice over this configuration
+         * @return returns when current connectChoice is set (time from System.currentTimeMillis)
+         */
+        public long getConnectChoiceTimestamp() {
+            return mConnectChoiceTimestamp;
+        }
+
+        /**
+         * set the timeStamp when user select a choice over this configuration
+         * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should
+         *        be obtained from System.currentTimeMillis
+         */
+        public void setConnectChoiceTimestamp(long timeStamp) {
+            mConnectChoiceTimestamp = timeStamp;
+        }
+
+        /**
+         * get current Quality network selection status
+         * @return returns current Quality network selection status in String (for debug purpose)
          */
         public String getNetworkStatusString() {
             return QUALITY_NETWORK_SELECTION_STATUS[mStatus];
@@ -873,6 +1033,7 @@
             }
         }
         /**
+         * get current network disable reason
          * @return current network disable reason in String (for debug purpose)
          */
         public String getNetworkDisableReasonString() {
@@ -881,6 +1042,7 @@
 
         /**
          * get current network network selection status
+         * @return return current network network selection status
          */
         public int getNetworkSelectionStatus() {
             return mStatus;
@@ -900,12 +1062,14 @@
         }
 
         /**
-         * return whether current network is permanently disabled
+         * @return returns whether current network is permanently disabled
          */
         public boolean isNetworkPermanentlyDisabled() {
             return mStatus == NETWORK_SELECTION_PERMANENTLY_DISABLED;
         }
+
         /**
+         * set current networ work selection status
          * @param status network selection status to set
          */
         public void setNetworkSelectionStatus(int status) {
@@ -913,14 +1077,16 @@
                 mStatus = status;
             }
         }
+
         /**
-         * @return current network's disable reason
+         * @return returns current network's disable reason
          */
         public int getNetworkSelectionDisableReason() {
             return mNetworkSelectionDisableReason;
         }
 
         /**
+         * set Network disable reason
          * @param  reason Network disable reason
          */
         public void setNetworkSelectionDisableReason(int reason) {
@@ -930,12 +1096,17 @@
                 throw new IllegalArgumentException("Illegal reason value: " + reason);
             }
         }
+
         /**
-         * @param reason whether current network is disabled by this reason
+         * check whether network is disabled by this reason
+         * @param reason a specific disable reason
+         * @return true -- network is disabled for this reason
+         *         false -- network is not disabled for this reason
          */
         public boolean isDisabledByReason(int reason) {
             return mNetworkSelectionDisableReason == reason;
         }
+
         /**
          * @param timeStamp Set when current network is disabled in millisecond since January 1,
          * 1970 00:00:00.0 UTC
@@ -945,7 +1116,7 @@
         }
 
         /**
-         * @return Get when current network is disabled in millisecond since January 1,
+         * @return returns when current network is disabled in millisecond since January 1,
          * 1970 00:00:00.0 UTC
          */
         public long getDisableTime() {
@@ -953,6 +1124,7 @@
         }
 
         /**
+         * get the disable counter of a specific reason
          * @param  reason specific failure reason
          * @exception throw IllegalArgumentException for illegal input
          * @return counter number for specific error reason.
@@ -991,6 +1163,7 @@
                 throw new IllegalArgumentException("Illegal reason value: " + reason);
             }
         }
+
         /**
          * clear the counter of a specific failure reason
          * @hide
@@ -1004,6 +1177,7 @@
                 throw new IllegalArgumentException("Illegal reason value: " + reason);
             }
         }
+
         /**
          * clear all the failure reason counters
          */
@@ -1042,6 +1216,8 @@
             }
             mTemporarilyDisabledTimestamp = source.mTemporarilyDisabledTimestamp;
             mNetworkSelectionBSSID = source.mNetworkSelectionBSSID;
+            setConnectChoice(source.getConnectChoice());
+            setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
         }
 
         public void writeToParcel(Parcel dest) {
@@ -1053,6 +1229,13 @@
             }
             dest.writeLong(getDisableTime());
             dest.writeString(getNetworkSelectionBSSID());
+            if (getConnectChoice() != null) {
+                dest.writeInt(CONNECT_CHOICE_EXISTS);
+                dest.writeString(getConnectChoice());
+                dest.writeLong(getConnectChoiceTimestamp());
+            } else {
+                dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
+            }
         }
 
         public void readFromParcel(Parcel in) {
@@ -1064,6 +1247,13 @@
             }
             setDisableTime(in.readLong());
             setNetworkSelectionBSSID(in.readString());
+            if (in.readInt() == CONNECT_CHOICE_EXISTS) {
+                setConnectChoice(in.readString());
+                setConnectChoiceTimestamp(in.readLong());
+            } else {
+                setConnectChoice(null);
+                setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
+            }
         }
     }
 
@@ -1116,6 +1306,7 @@
         lastUpdateUid = -1;
         creatorUid = -1;
         shared = true;
+        dtimInterval = 0;
     }
 
     /**
@@ -1183,7 +1374,11 @@
                 }
             }
         }
-
+        if (mNetworkSelectionStatus.getConnectChoice() != null) {
+            sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice());
+            sbuf.append(" connect choice set time: ").append(mNetworkSelectionStatus
+                    .getConnectChoiceTimestamp());
+        }
 
         if (this.numAssociation > 0) {
             sbuf.append(" numAssociation ").append(this.numAssociation).append("\n");
@@ -1285,10 +1480,10 @@
             if (diff <= 0) {
                 sbuf.append(" blackListed since <incorrect>");
             } else {
-                sbuf.append(" blackListed: ").append(Long.toString(diff/1000)).append( "sec ");
+                sbuf.append(" blackListed: ").append(Long.toString(diff / 1000)).append("sec ");
             }
         }
-        if (creatorUid != 0)  sbuf.append(" cuid=" + Integer.toString(creatorUid));
+        if (creatorUid != 0) sbuf.append(" cuid=" + creatorUid);
         if (creatorName != null) sbuf.append(" cname=" + creatorName);
         if (lastUpdateUid != 0) sbuf.append(" luid=" + lastUpdateUid);
         if (lastUpdateName != null) sbuf.append(" lname=" + lastUpdateName);
@@ -1303,7 +1498,7 @@
             if (diff <= 0) {
                 sbuf.append("lastConnected since <incorrect>");
             } else {
-                sbuf.append("lastConnected: ").append(Long.toString(diff/1000)).append( "sec ");
+                sbuf.append("lastConnected: ").append(Long.toString(diff / 1000)).append("sec ");
             }
         }
         if (this.lastConnectionFailure != 0) {
@@ -1312,8 +1507,8 @@
             if (diff <= 0) {
                 sbuf.append("lastConnectionFailure since <incorrect> ");
             } else {
-                sbuf.append("lastConnectionFailure: ").append(Long.toString(diff/1000));
-                sbuf.append( "sec ");
+                sbuf.append("lastConnectionFailure: ").append(Long.toString(diff / 1000));
+                sbuf.append("sec ");
             }
         }
         if (this.lastRoamingFailure != 0) {
@@ -1322,29 +1517,19 @@
             if (diff <= 0) {
                 sbuf.append("lastRoamingFailure since <incorrect> ");
             } else {
-                sbuf.append("lastRoamingFailure: ").append(Long.toString(diff/1000));
-                sbuf.append( "sec ");
+                sbuf.append("lastRoamingFailure: ").append(Long.toString(diff / 1000));
+                sbuf.append("sec ");
             }
         }
         sbuf.append("roamingFailureBlackListTimeMilli: ").
                 append(Long.toString(this.roamingFailureBlackListTimeMilli));
         sbuf.append('\n');
         if (this.linkedConfigurations != null) {
-            for(String key : this.linkedConfigurations.keySet()) {
+            for (String key : this.linkedConfigurations.keySet()) {
                 sbuf.append(" linked: ").append(key);
                 sbuf.append('\n');
             }
         }
-        if (this.connectChoices != null) {
-            for(String key : this.connectChoices.keySet()) {
-                Integer choice = this.connectChoices.get(key);
-                if (choice != null) {
-                    sbuf.append(" choice: ").append(key);
-                    sbuf.append(" = ").append(choice);
-                    sbuf.append('\n');
-                }
-            }
-        }
         sbuf.append("triggeredLow: ").append(this.numUserTriggeredWifiDisableLowRSSI);
         sbuf.append(" triggeredBad: ").append(this.numUserTriggeredWifiDisableBadRSSI);
         sbuf.append(" triggeredNotHigh: ").append(this.numUserTriggeredWifiDisableNotHighRSSI);
@@ -1592,8 +1777,13 @@
     }
 
     /** @hide */
-    public boolean isVisibleToUser(int userId) {
-        return shared || (UserHandle.getUserId(creatorUid) == userId);
+    public void setPasspointManagementObjectTree(String passpointManagementObjectTree) {
+        mPasspointManagementObjectTree = passpointManagementObjectTree;
+    }
+
+    /** @hide */
+    public String getMoTree() {
+        return mPasspointManagementObjectTree;
     }
 
     /** copy constructor {@hide} */
@@ -1631,11 +1821,6 @@
 
             mIpConfiguration = new IpConfiguration(source.mIpConfiguration);
 
-            if ((source.connectChoices != null) && (source.connectChoices.size() > 0)) {
-                connectChoices = new HashMap<String, Integer>();
-                connectChoices.putAll(source.connectChoices);
-            }
-
             if ((source.linkedConfigurations != null)
                     && (source.linkedConfigurations.size() > 0)) {
                 linkedConfigurations = new HashMap<String, Integer>();
@@ -1752,6 +1937,7 @@
         dest.writeInt(numNoInternetAccessReports);
         dest.writeInt(noInternetAccessExpected ? 1 : 0);
         dest.writeInt(shared ? 1 : 0);
+        dest.writeString(mPasspointManagementObjectTree);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -1820,6 +2006,7 @@
                 config.numNoInternetAccessReports = in.readInt();
                 config.noInternetAccessExpected = in.readInt() != 0;
                 config.shared = in.readInt() != 0;
+                config.mPasspointManagementObjectTree = in.readString();
                 return config;
             }
 
@@ -1827,4 +2014,43 @@
                 return new WifiConfiguration[size];
             }
         };
+
+    /**
+     * Serializes the object for backup
+     * @hide
+     */
+    public byte[] getBytesForBackup() throws IOException {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+
+        out.writeInt(BACKUP_VERSION);
+        BackupUtils.writeString(out, SSID);
+        out.writeInt(apBand);
+        out.writeInt(apChannel);
+        BackupUtils.writeString(out, preSharedKey);
+        out.writeInt(getAuthType());
+        return baos.toByteArray();
+    }
+
+    /**
+     * Deserializes a byte array into the WiFiConfiguration Object
+     * @hide
+     */
+    public static WifiConfiguration getWifiConfigFromBackup(DataInputStream in) throws IOException,
+            BackupUtils.BadVersionException {
+        WifiConfiguration config = new WifiConfiguration();
+        int version = in.readInt();
+        if (version < 1 || version > BACKUP_VERSION) {
+            throw new BackupUtils.BadVersionException("Unknown Backup Serialization Version");
+        }
+
+        if (version == 1) return null; // Version 1 is a bad dataset.
+
+        config.SSID = BackupUtils.readString(in);
+        config.apBand = in.readInt();
+        config.apChannel = in.readInt();
+        config.preSharedKey = BackupUtils.readString(in);
+        config.allowedKeyManagement.set(in.readInt());
+        return config;
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 59b22bd..964bfa2 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -15,12 +15,15 @@
  */
 package android.net.wifi;
 
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.security.Credentials;
 import android.text.TextUtils;
+import android.util.Log;
 
 import java.io.ByteArrayInputStream;
+import java.nio.charset.StandardCharsets;
 import java.security.KeyFactory;
 import java.security.NoSuchAlgorithmException;
 import java.security.PrivateKey;
@@ -72,6 +75,13 @@
     public static final String KEYSTORE_URI = "keystore://";
 
     /**
+     * String representing the keystore URI used for wpa_supplicant,
+     * Unlike #KEYSTORE_URI, this supports a list of space-delimited aliases
+     * @hide
+     */
+    public static final String KEYSTORES_URI = "keystores://";
+
+    /**
      * String to set the engine value to when it should be enabled.
      * @hide
      */
@@ -92,6 +102,8 @@
     /** @hide */
     public static final String CA_CERT_KEY         = "ca_cert";
     /** @hide */
+    public static final String CA_PATH_KEY         = "ca_path";
+    /** @hide */
     public static final String ENGINE_KEY          = "engine";
     /** @hide */
     public static final String ENGINE_ID_KEY       = "engine_id";
@@ -103,19 +115,41 @@
     public static final String PLMN_KEY            = "plmn";
     /** @hide */
     public static final String PHASE1_KEY          = "phase1";
+    /** @hide */
+    public static final String CA_CERT_ALIAS_DELIMITER = " ";
 
     /** {@hide} */
     public static final String ENABLE_TLS_1_2 = "\"tls_disable_tlsv1_2=0\"";
     /** {@hide} */
     public static final String DISABLE_TLS_1_2 = "\"tls_disable_tlsv1_2=1\"";
 
+    // Fields to copy verbatim from wpa_supplicant.
+    private static final String[] SUPPLICANT_CONFIG_KEYS = new String[] {
+            IDENTITY_KEY,
+            ANON_IDENTITY_KEY,
+            PASSWORD_KEY,
+            CLIENT_CERT_KEY,
+            CA_CERT_KEY,
+            SUBJECT_MATCH_KEY,
+            ENGINE_KEY,
+            ENGINE_ID_KEY,
+            PRIVATE_KEY_ID_KEY,
+            ALTSUBJECT_MATCH_KEY,
+            DOM_SUFFIX_MATCH_KEY,
+            CA_PATH_KEY
+    };
+
     private HashMap<String, String> mFields = new HashMap<String, String>();
     //By default, we enable TLS1.2. However, due to a known bug on some radius, we may disable it to
     // fall back to TLS 1.1.
     private boolean mTls12Enable =  true;
-    private X509Certificate mCaCert;
+    private X509Certificate[] mCaCerts;
     private PrivateKey mClientPrivateKey;
     private X509Certificate mClientCertificate;
+    private int mEapMethod = Eap.NONE;
+    private int mPhase2Method = Phase2.NONE;
+
+    private static final String TAG = "WifiEnterpriseConfig";
 
     public WifiEnterpriseConfig() {
         // Do not set defaults so that the enterprise fields that are not changed
@@ -130,6 +164,8 @@
         for (String key : source.mFields.keySet()) {
             mFields.put(key, source.mFields.get(key));
         }
+        mEapMethod = source.mEapMethod;
+        mPhase2Method = source.mPhase2Method;
     }
 
     @Override
@@ -145,7 +181,9 @@
             dest.writeString(entry.getValue());
         }
 
-        writeCertificate(dest, mCaCert);
+        dest.writeInt(mEapMethod);
+        dest.writeInt(mPhase2Method);
+        writeCertificates(dest, mCaCerts);
 
         if (mClientPrivateKey != null) {
             String algorithm = mClientPrivateKey.getAlgorithm();
@@ -161,6 +199,17 @@
         dest.writeInt(mTls12Enable ? 1: 0);
     }
 
+    private void writeCertificates(Parcel dest, X509Certificate[] cert) {
+        if (cert != null && cert.length != 0) {
+            dest.writeInt(cert.length);
+            for (int i = 0; i < cert.length; i++) {
+                writeCertificate(dest, cert[i]);
+            }
+        } else {
+            dest.writeInt(0);
+        }
+    }
+
     private void writeCertificate(Parcel dest, X509Certificate cert) {
         if (cert != null) {
             try {
@@ -186,7 +235,9 @@
                         enterpriseConfig.mFields.put(key, value);
                     }
 
-                    enterpriseConfig.mCaCert = readCertificate(in);
+                    enterpriseConfig.mEapMethod = in.readInt();
+                    enterpriseConfig.mPhase2Method = in.readInt();
+                    enterpriseConfig.mCaCerts = readCertificates(in);
 
                     PrivateKey userKey = null;
                     int len = in.readInt();
@@ -210,6 +261,18 @@
                     return enterpriseConfig;
                 }
 
+                private X509Certificate[] readCertificates(Parcel in) {
+                    X509Certificate[] certs = null;
+                    int len = in.readInt();
+                    if (len > 0) {
+                        certs = new X509Certificate[len];
+                        for (int i = 0; i < len; i++) {
+                            certs[i] = readCertificate(in);
+                        }
+                    }
+                    return certs;
+                }
+
                 private X509Certificate readCertificate(Parcel in) {
                     X509Certificate cert = null;
                     int len = in.readInt();
@@ -250,8 +313,11 @@
         public static final int AKA     = 5;
         /** EAP-Authentication and Key Agreement Prime */
         public static final int AKA_PRIME = 6;
+        /** Hotspot 2.0 r2 OSEN */
+        public static final int UNAUTH_TLS = 7;
         /** @hide */
-        public static final String[] strings = { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'" };
+        public static final String[] strings =
+                { "PEAP", "TLS", "TTLS", "PWD", "SIM", "AKA", "AKA'", "WFA-UNAUTH-TLS" };
 
         /** Prevent initialization */
         private Eap() {}
@@ -268,7 +334,8 @@
         public static final int MSCHAPV2    = 3;
         /** Generic Token Card */
         public static final int GTC         = 4;
-        private static final String PREFIX = "auth=";
+        private static final String AUTH_PREFIX = "auth=";
+        private static final String AUTHEAP_PREFIX = "autheap=";
         /** @hide */
         public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP",
                 "MSCHAPV2", "GTC" };
@@ -277,11 +344,98 @@
         private Phase2() {}
     }
 
-    /** Internal use only
+    // Loader and saver interfaces for exchanging data with wpa_supplicant.
+    // TODO: Decouple this object (which is just a placeholder of the configuration)
+    // from the implementation that knows what wpa_supplicant wants.
+    /**
+     * Interface used for retrieving supplicant configuration from WifiEnterpriseConfig
      * @hide
      */
-    public HashMap<String, String> getFields() {
-        return mFields;
+    public interface SupplicantSaver {
+        /**
+         * Set a value within wpa_supplicant configuration
+         * @param key index to set within wpa_supplciant
+         * @param value the value for the key
+         * @return true if successful; false otherwise
+         */
+        boolean saveValue(String key, String value);
+    }
+
+    /**
+     * Interface used for populating a WifiEnterpriseConfig from supplicant configuration
+     * @hide
+     */
+    public interface SupplicantLoader {
+        /**
+         * Returns a value within wpa_supplicant configuration
+         * @param key index to set within wpa_supplciant
+         * @return string value if successful; null otherwise
+         */
+        String loadValue(String key);
+    }
+
+    /**
+     * Internal use only; supply field values to wpa_supplicant config.  The configuration
+     * process aborts on the first failed call on {@code saver}.
+     * @param saver proxy for setting configuration in wpa_supplciant
+     * @return whether the save succeeded on all attempts
+     * @hide
+     */
+    public boolean saveToSupplicant(SupplicantSaver saver) {
+        if (!isEapMethodValid()) {
+            return false;
+        }
+
+        for (String key : mFields.keySet()) {
+            if (!saver.saveValue(key, mFields.get(key))) {
+                return false;
+            }
+        }
+
+        if (!saver.saveValue(EAP_KEY, Eap.strings[mEapMethod])) {
+            return false;
+        }
+
+        if (mEapMethod != Eap.TLS && mPhase2Method != Phase2.NONE) {
+            boolean is_autheap = mEapMethod == Eap.TTLS && mPhase2Method == Phase2.GTC;
+            String prefix = is_autheap ? Phase2.AUTHEAP_PREFIX : Phase2.AUTH_PREFIX;
+            String value = convertToQuotedString(prefix + Phase2.strings[mPhase2Method]);
+            return saver.saveValue(PHASE2_KEY, value);
+        } else if (mPhase2Method == Phase2.NONE) {
+            // By default, send a null phase 2 to clear old configuration values.
+            return saver.saveValue(PHASE2_KEY, null);
+        } else {
+            Log.e(TAG, "WiFi enterprise configuration is invalid as it supplies a "
+                    + "phase 2 method but the phase1 method does not support it.");
+            return false;
+        }
+    }
+
+    /**
+     * Internal use only; retrieve configuration from wpa_supplicant config.
+     * @param loader proxy for retrieving configuration keys from wpa_supplicant
+     * @hide
+     */
+    public void loadFromSupplicant(SupplicantLoader loader) {
+        for (String key : SUPPLICANT_CONFIG_KEYS) {
+            String value = loader.loadValue(key);
+            if (value == null) {
+                mFields.put(key, EMPTY_VALUE);
+            } else {
+                mFields.put(key, value);
+            }
+        }
+        String eapMethod  = loader.loadValue(EAP_KEY);
+        mEapMethod = getStringIndex(Eap.strings, eapMethod, Eap.NONE);
+
+        String phase2Method = removeDoubleQuotes(loader.loadValue(PHASE2_KEY));
+        // Remove "auth=" or "autheap=" prefix.
+        if (phase2Method.startsWith(Phase2.AUTH_PREFIX)) {
+            phase2Method = phase2Method.substring(Phase2.AUTH_PREFIX.length());
+        } else if (phase2Method.startsWith(Phase2.AUTHEAP_PREFIX)) {
+            phase2Method = phase2Method.substring(Phase2.AUTHEAP_PREFIX.length());
+        }
+        mPhase2Method = getStringIndex(Phase2.strings, phase2Method, Phase2.NONE);
     }
 
     /**
@@ -302,7 +456,7 @@
             case Eap.SIM:
             case Eap.AKA:
             case Eap.AKA_PRIME:
-                mFields.put(EAP_KEY, Eap.strings[eapMethod]);
+                mEapMethod = eapMethod;
                 mFields.put(OPP_KEY_CACHING, "1");
                 break;
             default:
@@ -335,8 +489,7 @@
      * @return eap method configured
      */
     public int getEapMethod() {
-        String eapMethod  = mFields.get(EAP_KEY);
-        return getStringIndex(Eap.strings, eapMethod, Eap.NONE);
+        return mEapMethod;
     }
 
     /**
@@ -351,15 +504,11 @@
     public void setPhase2Method(int phase2Method) {
         switch (phase2Method) {
             case Phase2.NONE:
-                mFields.put(PHASE2_KEY, EMPTY_VALUE);
-                break;
-            /** Valid methods */
             case Phase2.PAP:
             case Phase2.MSCHAP:
             case Phase2.MSCHAPV2:
             case Phase2.GTC:
-                mFields.put(PHASE2_KEY, convertToQuotedString(
-                        Phase2.PREFIX + Phase2.strings[phase2Method]));
+                mPhase2Method = phase2Method;
                 break;
             default:
                 throw new IllegalArgumentException("Unknown Phase 2 method");
@@ -371,12 +520,7 @@
      * @return a phase 2 method defined at {@link Phase2}
      * */
     public int getPhase2Method() {
-        String phase2Method = removeDoubleQuotes(mFields.get(PHASE2_KEY));
-        // Remove auth= prefix
-        if (phase2Method.startsWith(Phase2.PREFIX)) {
-            phase2Method = phase2Method.substring(Phase2.PREFIX.length());
-        }
-        return getStringIndex(Phase2.strings, phase2Method, Phase2.NONE);
+        return mPhase2Method;
     }
 
     /**
@@ -404,7 +548,8 @@
         setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, "");
     }
 
-    /** Get the anonymous identity
+    /**
+     * Get the anonymous identity
      * @return anonymous identity
      */
     public String getAnonymousIdentity() {
@@ -430,6 +575,36 @@
     }
 
     /**
+     * Encode a CA certificate alias so it does not contain illegal character.
+     * @hide
+     */
+    public static String encodeCaCertificateAlias(String alias) {
+        byte[] bytes = alias.getBytes(StandardCharsets.UTF_8);
+        StringBuilder sb = new StringBuilder(bytes.length * 2);
+        for (byte o : bytes) {
+            sb.append(String.format("%02x", o & 0xFF));
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Decode a previously-encoded CA certificate alias.
+     * @hide
+     */
+    public static String decodeCaCertificateAlias(String alias) {
+        byte[] data = new byte[alias.length() >> 1];
+        for (int n = 0, position = 0; n < alias.length(); n += 2, position++) {
+            data[position] = (byte) Integer.parseInt(alias.substring(n,  n + 2), 16);
+        }
+        try {
+            return new String(data, StandardCharsets.UTF_8);
+        } catch (NumberFormatException e) {
+            e.printStackTrace();
+            return alias;
+        }
+    }
+
+    /**
      * Set CA certificate alias.
      *
      * <p> See the {@link android.security.KeyChain} for details on installing or choosing
@@ -443,6 +618,35 @@
     }
 
     /**
+     * Set CA certificate aliases. When creating installing the corresponding certificate to
+     * the keystore, please use alias encoded by {@link #encodeCaCertificateAlias(String)}.
+     *
+     * <p> See the {@link android.security.KeyChain} for details on installing or choosing
+     * a certificate.
+     * </p>
+     * @param aliases identifies the certificate
+     * @hide
+     */
+    public void setCaCertificateAliases(@Nullable String[] aliases) {
+        if (aliases == null) {
+            setFieldValue(CA_CERT_KEY, null, CA_CERT_PREFIX);
+        } else if (aliases.length == 1) {
+            // Backwards compatibility: use the original cert prefix if setting only one alias.
+            setCaCertificateAlias(aliases[0]);
+        } else {
+            // Use KEYSTORES_URI which supports multiple aliases.
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < aliases.length; i++) {
+                if (i > 0) {
+                    sb.append(CA_CERT_ALIAS_DELIMITER);
+                }
+                sb.append(encodeCaCertificateAlias(Credentials.CA_CERTIFICATE + aliases[i]));
+            }
+            setFieldValue(CA_CERT_KEY, sb.toString(), KEYSTORES_URI);
+        }
+    }
+
+    /**
      * Get CA certificate alias
      * @return alias to the CA certificate
      * @hide
@@ -452,6 +656,32 @@
     }
 
     /**
+     * Get CA certificate aliases
+     * @return alias to the CA certificate
+     * @hide
+     */
+    @Nullable public String[] getCaCertificateAliases() {
+        String value = getFieldValue(CA_CERT_KEY, "");
+        if (value.startsWith(CA_CERT_PREFIX)) {
+            // Backwards compatibility: parse the original alias prefix.
+            return new String[] {getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX)};
+        } else if (value.startsWith(KEYSTORES_URI)) {
+            String values = value.substring(KEYSTORES_URI.length());
+
+            String[] aliases = TextUtils.split(values, CA_CERT_ALIAS_DELIMITER);
+            for (int i = 0; i < aliases.length; i++) {
+                aliases[i] = decodeCaCertificateAlias(aliases[i]);
+                if (aliases[i].startsWith(Credentials.CA_CERTIFICATE)) {
+                    aliases[i] = aliases[i].substring(Credentials.CA_CERTIFICATE.length());
+                }
+            }
+            return aliases.length != 0 ? aliases : null;
+        } else {
+            return TextUtils.isEmpty(value) ? null : new String[] {value};
+        }
+    }
+
+    /**
      * Specify a X.509 certificate that identifies the server.
      *
      * <p>A default name is automatically assigned to the certificate and used
@@ -462,31 +692,103 @@
      * @param cert X.509 CA certificate
      * @throws IllegalArgumentException if not a CA certificate
      */
-    public void setCaCertificate(X509Certificate cert) {
+    public void setCaCertificate(@Nullable X509Certificate cert) {
         if (cert != null) {
             if (cert.getBasicConstraints() >= 0) {
-                mCaCert = cert;
+                mCaCerts = new X509Certificate[] {cert};
             } else {
                 throw new IllegalArgumentException("Not a CA certificate");
             }
         } else {
-            mCaCert = null;
+            mCaCerts = null;
         }
     }
 
     /**
-     * Get CA certificate
+     * Get CA certificate. If multiple CA certificates are configured previously,
+     * return the first one.
      * @return X.509 CA certificate
      */
-    public X509Certificate getCaCertificate() {
-        return mCaCert;
+    @Nullable public X509Certificate getCaCertificate() {
+        if (mCaCerts != null && mCaCerts.length > 0) {
+            return mCaCerts[0];
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Specify a list of X.509 certificates that identifies the server. The validation
+     * passes if the CA of server certificate matches one of the given certificates.
+
+     * <p>Default names are automatically assigned to the certificates and used
+     * with this configuration. The framework takes care of installing the
+     * certificates when the config is saved and removing the certificates when
+     * the config is removed.
+     *
+     * @param certs X.509 CA certificates
+     * @throws IllegalArgumentException if any of the provided certificates is
+     *     not a CA certificate
+     */
+    public void setCaCertificates(@Nullable X509Certificate[] certs) {
+        if (certs != null) {
+            X509Certificate[] newCerts = new X509Certificate[certs.length];
+            for (int i = 0; i < certs.length; i++) {
+                if (certs[i].getBasicConstraints() >= 0) {
+                    newCerts[i] = certs[i];
+                } else {
+                    throw new IllegalArgumentException("Not a CA certificate");
+                }
+            }
+            mCaCerts = newCerts;
+        } else {
+            mCaCerts = null;
+        }
+    }
+
+    /**
+     * Get CA certificates.
+     */
+    @Nullable public X509Certificate[] getCaCertificates() {
+        if (mCaCerts != null || mCaCerts.length > 0) {
+            return mCaCerts;
+        } else {
+            return null;
+        }
     }
 
     /**
      * @hide
      */
     public void resetCaCertificate() {
-        mCaCert = null;
+        mCaCerts = null;
+    }
+
+    /**
+     * Set the ca_path directive on wpa_supplicant.
+     *
+     * From wpa_supplicant documentation:
+     *
+     * Directory path for CA certificate files (PEM). This path may contain
+     * multiple CA certificates in OpenSSL format. Common use for this is to
+     * point to system trusted CA list which is often installed into directory
+     * like /etc/ssl/certs. If configured, these certificates are added to the
+     * list of trusted CAs. ca_cert may also be included in that case, but it is
+     * not required.
+     * @param domain The path for CA certificate files
+     * @hide
+     */
+    public void setCaPath(String path) {
+        setFieldValue(CA_PATH_KEY, path);
+    }
+
+    /**
+     * Get the domain_suffix_match value. See setDomSuffixMatch.
+     * @return The path for CA certificate files.
+     * @hide
+     */
+    public String getCaPath() {
+        return getFieldValue(CA_PATH_KEY, "");
     }
 
     /** Set Client certificate alias.
@@ -674,18 +976,15 @@
     }
 
     /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
-    String getKeyId(WifiEnterpriseConfig current) {
-        String eap = mFields.get(EAP_KEY);
-        String phase2 = mFields.get(PHASE2_KEY);
-
-        // If either eap or phase2 are not initialized, use current config details
-        if (TextUtils.isEmpty((eap))) {
-            eap = current.mFields.get(EAP_KEY);
+    public String getKeyId(WifiEnterpriseConfig current) {
+        // If EAP method is not initialized, use current config details
+        if (mEapMethod == Eap.NONE) {
+            return (current != null) ? current.getKeyId(null) : EMPTY_VALUE;
         }
-        if (TextUtils.isEmpty(phase2)) {
-            phase2 = current.mFields.get(PHASE2_KEY);
+        if (!isEapMethodValid()) {
+            return EMPTY_VALUE;
         }
-        return eap + "_" + phase2;
+        return Eap.strings[mEapMethod] + "_" + Phase2.strings[mPhase2Method];
     }
 
     private String removeDoubleQuotes(String string) {
@@ -702,7 +1001,8 @@
         return "\"" + string + "\"";
     }
 
-    /** Returns the index at which the toBeFound string is found in the array.
+    /**
+     * Returns the index at which the toBeFound string is found in the array.
      * @param arr array of strings
      * @param toBeFound string to be found
      * @param defaultIndex default index to be returned when string is not found
@@ -716,13 +1016,16 @@
         return defaultIndex;
     }
 
-    /** Returns the field value for the key.
+    /**
+     * Returns the field value for the key.
      * @param key into the hash
      * @param prefix is the prefix that the value may have
      * @return value
      * @hide
      */
     public String getFieldValue(String key, String prefix) {
+        // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+        // neither of these keys should be retrieved in this manner.
         String value = mFields.get(key);
         // Uninitialized or known to be empty after reading from supplicant
         if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return "";
@@ -735,13 +1038,16 @@
         }
     }
 
-    /** Set a value with an optional prefix at key
+    /**
+     * Set a value with an optional prefix at key
      * @param key into the hash
      * @param value to be set
      * @param prefix an optional value to be prefixed to actual value
      * @hide
      */
     public void setFieldValue(String key, String value, String prefix) {
+        // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+        // neither of these keys should be set in this manner.
         if (TextUtils.isEmpty(value)) {
             mFields.put(key, EMPTY_VALUE);
         } else {
@@ -750,13 +1056,16 @@
     }
 
 
-    /** Set a value with an optional prefix at key
+    /**
+     * Set a value with an optional prefix at key
      * @param key into the hash
      * @param value to be set
      * @param prefix an optional value to be prefixed to actual value
      * @hide
      */
     public void setFieldValue(String key, String value) {
+        // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since
+        // neither of these keys should be set in this manner.
         if (TextUtils.isEmpty(value)) {
            mFields.put(key, EMPTY_VALUE);
         } else {
@@ -772,4 +1081,25 @@
         }
         return sb.toString();
     }
+
+    /**
+     * Returns whether the EAP method data is valid, i.e., whether mEapMethod and mPhase2Method
+     * are valid indices into {@code Eap.strings[]} and {@code Phase2.strings[]} respectively.
+     */
+    private boolean isEapMethodValid() {
+        if (mEapMethod == Eap.NONE) {
+            Log.e(TAG, "WiFi enterprise configuration is invalid as it supplies no EAP method.");
+            return false;
+        }
+        if (mEapMethod < 0 || mEapMethod >= Eap.strings.length) {
+            Log.e(TAG, "mEapMethod is invald for WiFi enterprise configuration: " + mEapMethod);
+            return false;
+        }
+        if (mPhase2Method < 0 || mPhase2Method >= Phase2.strings.length) {
+            Log.e(TAG, "mPhase2Method is invald for WiFi enterprise configuration: "
+                    + mPhase2Method);
+            return false;
+        }
+        return true;
+    }
 }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 50f2cf0..55b9182 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -26,28 +26,27 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
-import android.net.wifi.ScanSettings;
 import android.os.Binder;
 import android.os.Build;
-import android.os.IBinder;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.Messenger;
 import android.os.RemoteException;
 import android.os.WorkSource;
-import android.os.Messenger;
 import android.util.Log;
 import android.util.SparseArray;
 
-import java.net.InetAddress;
-import java.util.concurrent.CountDownLatch;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
 
+import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
 
 /**
  * This class provides the primary API for managing all aspects of Wi-Fi
@@ -114,6 +113,51 @@
     public static final int WIFI_CREDENTIAL_FORGOT = 1;
 
     /**
+     * Broadcast intent action indicating that the a Passpoint release 2 icon has been received.
+     * @hide
+     */
+    public static final String PASSPOINT_ICON_RECEIVED_ACTION =
+            "android.net.wifi.PASSPOINT_ICON_RECEIVED";
+    /** @hide */
+    public static final String EXTRA_PASSPOINT_ICON_BSSID = "bssid";
+    /** @hide */
+    public static final String EXTRA_PASSPOINT_ICON_FILE = "file";
+    /** @hide */
+    public static final String EXTRA_PASSPOINT_ICON_DATA = "icon";
+
+    /**
+     * Broadcast intent action indicating that the a Passpoint release
+     * 2 WNM frame has been received.
+     * @hide
+     */
+    public static final String PASSPOINT_WNM_FRAME_RECEIVED_ACTION =
+            "android.net.wifi.PASSPOINT_WNM_FRAME_RECEIVED";
+    /**
+     * Originating BSS
+     * @hide */
+    public static final String EXTRA_PASSPOINT_WNM_BSSID = "bssid";
+    /**
+     * SOAP-XML or OMA-DM
+     * @hide */
+    public static final String EXTRA_PASSPOINT_WNM_METHOD = "method";
+    /**
+     * Type of Passpoint match
+     * @hide */
+    public static final String EXTRA_PASSPOINT_WNM_PPOINT_MATCH = "match";
+    /**
+     * String
+     * @hide */
+    public static final String EXTRA_PASSPOINT_WNM_URL = "url";
+    /**
+     * Boolean true=ess, false=bss
+     * @hide */
+    public static final String EXTRA_PASSPOINT_WNM_ESS = "ess";
+    /**
+     * Delay in seconds
+     * @hide */
+    public static final String EXTRA_PASSPOINT_WNM_DELAY = "delay";
+
+    /**
      * Broadcast intent action indicating that Wi-Fi has been enabled, disabled,
      * enabling, disabling, or unknown. One extra provides this state as an int.
      * Another extra provides the previous state, if available.
@@ -771,6 +815,94 @@
     }
 
     /**
+     * Add a Hotspot 2.0 release 2 Management Object
+     * @param mo The MO in XML form
+     * @return -1 for failure
+     * @hide
+     */
+    public int addPasspointManagementObject(String mo) {
+        try {
+            return mService.addPasspointManagementObject(mo);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Modify a Hotspot 2.0 release 2 Management Object
+     * @param fqdn The FQDN of the service provider
+     * @param mos A List of MO definitions to be updated
+     * @return the number of nodes updated, or -1 for failure
+     * @hide
+     */
+    public int modifyPasspointManagementObject(String fqdn,
+                                               List<PasspointManagementObjectDefinition> mos) {
+        try {
+            return mService.modifyPasspointManagementObject(fqdn, mos);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Query for a Hotspot 2.0 release 2 OSU icon
+     * @param bssid The BSSID of the AP
+     * @param fileName Icon file name
+     * @hide
+     */
+    public void queryPasspointIcon(long bssid, String fileName) {
+        try {
+            mService.queryPasspointIcon(bssid, fileName);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Match the currently associated network against the SP matching the given FQDN
+     * @param fqdn FQDN of the SP
+     * @return ordinal [HomeProvider, RoamingProvider, Incomplete, None, Declined]
+     * @hide
+     */
+    public int matchProviderWithCurrentNetwork(String fqdn) {
+        try {
+            return mService.matchProviderWithCurrentNetwork(fqdn);
+        } catch (RemoteException e) {
+            return -1;
+        }
+    }
+
+    /**
+     * Deauthenticate and set the re-authentication hold off time for the current network
+     * @param holdoff hold off time in milliseconds
+     * @param ess set if the hold off pertains to an ESS rather than a BSS
+     * @hide
+     */
+    public void deauthenticateNetwork(long holdoff, boolean ess) {
+        try {
+            mService.deauthenticateNetwork(holdoff, ess);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
+     * Sets whether or not the given network is metered from a network policy
+     * point of view. A network should be classified as metered when the user is
+     * sensitive to heavy data usage on that connection due to monetary costs,
+     * data limitations or battery/performance issues. A typical example would
+     * be a wifi connection where the user was being charged for usage.
+     * @param netId the integer that identifies the network configuration
+     * to the supplicant.
+     * @param isMetered True to mark the network as metered.
+     * @return {@code true} if the operation succeeded.
+     * @hide
+     */
+    @SystemApi
+    public boolean setMetered(int netId, boolean isMetered) {
+        // TODO(jjoslin): Implement
+        return false;
+    }
+
+    /**
      * Remove the specified network from the list of configured networks.
      * This may result in the asynchronous delivery of state change
      * events.
@@ -1180,37 +1312,15 @@
      * @return the list of access points found in the most recent scan. An app must hold
      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
      * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
-     * in order to get valid results.
+     * in order to get valid results.  If there is a remote exception (e.g., either a communication
+     * problem with the system service or an exception within the framework) an empty list will be
+     * returned.
      */
     public List<ScanResult> getScanResults() {
         try {
             return mService.getScanResults(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * An augmented version of getScanResults that returns ScanResults as well as OSU information
-     * wrapped in ScanInfo objects.
-     * @return
-     */
-    public List<ScanInfo> getScanInfos() {
-        try {
-            return mService.getScanInfos(mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Notify the OSU framework about the currently selected OSU.
-     * @param osuID The OSU ID from ScanInfo.getOsuIdentity()
-     */
-    public void setOsuSelection(int osuID) {
-        try {
-            mService.setOsuSelection(osuID);
-        } catch (RemoteException e) {
+            return new ArrayList<ScanResult>();
         }
     }
 
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 76c679c..69e179d 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -30,7 +30,9 @@
 import android.util.Log;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.AsyncChannel;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.Protocol;
 
 import java.util.List;
@@ -78,6 +80,8 @@
     public static final int REASON_INVALID_REQUEST = -3;
     /** Invalid request */
     public static final int REASON_NOT_AUTHORIZED = -4;
+    /** An outstanding request with the same listener hasn't finished yet. */
+    public static final int REASON_DUPLICATE_REQEUST = -5;
 
     /** @hide */
     public static final String GET_AVAILABLE_CHANNELS_EXTRA = "Channels";
@@ -136,17 +140,25 @@
         }
     }
 
-    /** reports {@link ScanListener#onResults} when underlying buffers are full
+    /**
+     * reports {@link ScanListener#onResults} when underlying buffers are full
+     * this is simply the lack of the {@link #REPORT_EVENT_AFTER_EACH_SCAN} flag
      * @deprecated
      */
     @Deprecated
     public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
-    /** reports {@link ScanListener#onResults} after each scan */
-    public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1;
-    /** reports {@link ScanListener#onFullResult} whenever each beacon is discovered */
-    public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2;
-    /** do not batch */
-    public static final int REPORT_EVENT_NO_BATCH = 4;
+    /**
+     * reports {@link ScanListener#onResults} after each scan
+     */
+    public static final int REPORT_EVENT_AFTER_EACH_SCAN = (1 << 0);
+    /**
+     * reports {@link ScanListener#onFullResult} whenever each beacon is discovered
+     */
+    public static final int REPORT_EVENT_FULL_SCAN_RESULT = (1 << 1);
+    /**
+     * Do not place scans in the chip's scan history buffer
+     */
+    public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
 
     /**
      * scan configuration parameters to be sent to {@link #startBackgroundScan}
@@ -452,8 +464,11 @@
      *                 scans should also not share this object.
      */
     public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings);
+        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, settings);
     }
     /**
      * stop an ongoing wifi scan
@@ -461,8 +476,11 @@
      *  #startBackgroundScan}
      */
     public void stopBackgroundScan(ScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
+        sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
     }
     /**
      * reports currently available scan results on appropriate listeners
@@ -483,8 +501,11 @@
      *                 scans should also not share this object.
      */
     public void startScan(ScanSettings settings, ScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, putListener(listener), settings);
+        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, settings);
     }
 
     /**
@@ -493,8 +514,11 @@
      * @param listener
      */
     public void stopScan(ScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, removeListener(listener));
+        sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
     }
 
     /** specifies information about an access point of interest */
@@ -626,8 +650,11 @@
      *                 provided on {@link #stopTrackingWifiChange}
      */
     public void startTrackingWifiChange(WifiChangeListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener));
+        sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
     }
 
     /**
@@ -636,8 +663,10 @@
      * #stopTrackingWifiChange}
      */
     public void stopTrackingWifiChange(WifiChangeListener listener) {
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener));
+        sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
     }
 
     /** @hide */
@@ -722,11 +751,14 @@
      */
     public void startTrackingBssids(BssidInfo[] bssidInfos,
                                     int apLostThreshold, BssidListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
         HotlistSettings settings = new HotlistSettings();
         settings.bssidInfos = bssidInfos;
         settings.apLostThreshold = apLostThreshold;
-        sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings);
+        sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
     }
 
     /**
@@ -734,8 +766,11 @@
      * @param listener same object provided in {@link #startTrackingBssids}
      */
     public void stopTrackingBssids(BssidListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener));
+        sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
     }
 
 
@@ -804,7 +839,7 @@
 
     private static final Object sThreadRefLock = new Object();
     private static int sThreadRefCount;
-    private static HandlerThread sHandlerThread;
+    private static Handler sInternalHandler;
 
     /**
      * Create a new WifiScanner instance.
@@ -816,12 +851,29 @@
      * @hide
      */
     public WifiScanner(Context context, IWifiScanner service) {
-        mContext = context;
-        mService = service;
-        init();
+        this(context, service, null, true);
     }
 
-    private void init() {
+    /**
+     * Create a new WifiScanner instance.
+     *
+     * @param context The application context.
+     * @param service The IWifiScanner Binder interface
+     * @param looper Looper for running WifiScanner operations. If null, a handler thread will be
+     *          created for running WifiScanner operations.
+     * @param waitForConnection If true, this will not return until a connection to Wifi Scanner
+     *          service is established.
+     * @hide
+     */
+    @VisibleForTesting
+    public WifiScanner(Context context, IWifiScanner service, Looper looper,
+            boolean waitForConnection) {
+        mContext = context;
+        mService = service;
+        init(looper, waitForConnection);
+    }
+
+    private void init(Looper looper, boolean waitForConnection) {
         synchronized (sThreadRefLock) {
             if (++sThreadRefCount == 1) {
                 Messenger messenger = null;
@@ -838,17 +890,23 @@
                     return;
                 }
 
-                sHandlerThread = new HandlerThread("WifiScanner");
                 sAsyncChannel = new AsyncChannel();
                 sConnected = new CountDownLatch(1);
 
-                sHandlerThread.start();
-                Handler handler = new ServiceHandler(sHandlerThread.getLooper());
-                sAsyncChannel.connect(mContext, handler, messenger);
-                try {
-                    sConnected.await();
-                } catch (InterruptedException e) {
-                    Log.e(TAG, "interrupted wait at init");
+                if (looper == null) {
+                    HandlerThread thread = new HandlerThread("WifiScanner");
+                    thread.start();
+                    sInternalHandler = new ServiceHandler(thread.getLooper());
+                } else {
+                    sInternalHandler = new ServiceHandler(looper);
+                }
+                sAsyncChannel.connect(mContext, sInternalHandler, messenger);
+                if (waitForConnection) {
+                    try {
+                        sConnected.await();
+                    } catch (InterruptedException e) {
+                        Log.e(TAG, "interrupted wait at init");
+                    }
                 }
             }
         }
@@ -859,6 +917,30 @@
                 "No permission to access and change wifi or a bad initialization");
     }
 
+    // Add a listener into listener map. If the listener already exists, return INVALID_KEY and
+    // send an error message to internal handler; Otherwise add the listener to the listener map and
+    // return the key of the listener.
+    private int addListener(ActionListener listener) {
+        synchronized (sListenerMap) {
+            boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
+            // Note we need to put the listener into listener map even if it's a duplicate as the
+            // internal handler will need the key to find the listener. In case of duplicates,
+            // removing duplicate key logic will be handled in internal handler.
+            int key = putListener(listener);
+            if (keyExists) {
+                if (DBG) Log.d(TAG, "listener key already exists");
+                OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
+                        "Outstanding request with same key not stopped yet");
+                Message message = Message.obtain(sInternalHandler, CMD_OP_FAILED, 0, key,
+                        operationResult);
+                message.sendToTarget();
+                return INVALID_KEY;
+            } else {
+                return key;
+            }
+        }
+    }
+
     private static int putListener(Object listener) {
         if (listener == null) return INVALID_KEY;
         int key;
@@ -902,7 +984,10 @@
 
     private static int removeListener(Object listener) {
         int key = getListenerKey(listener);
-        if (key == INVALID_KEY) return key;
+        if (key == INVALID_KEY) {
+            Log.e(TAG, "listener cannot be found");
+            return key;
+        }
         synchronized (sListenerMapLock) {
             sListenerMap.remove(key);
             return key;
diff --git a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
index 17cc29f..f5cad13 100644
--- a/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
+++ b/wifi/java/android/net/wifi/WifiWakeReasonAndCounts.java
@@ -16,8 +16,8 @@
 
 package android.net.wifi;
 
-import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.Parcelable;
 
 /**
  * A class representing wifi wake reason accounting.
@@ -52,6 +52,8 @@
     public int ipv4RxMulticast;
     public int ipv6Multicast;
     public int otherRxMulticast;
+    public int[] cmdEventWakeCntArray;
+    public int[] driverFWLocalWakeCntArray;
 
     /* {@hide} */
     public WifiWakeReasonAndCounts () {
@@ -78,6 +80,13 @@
         sb.append(" ipv4RxMulticast ").append(ipv4RxMulticast);
         sb.append(" ipv6Multicast ").append(ipv6Multicast);
         sb.append(" otherRxMulticast ").append(otherRxMulticast);
+        for (int i = 0; i < cmdEventWakeCntArray.length; i++) {
+            sb.append(" cmdEventWakeCntArray[" + i + "] " + cmdEventWakeCntArray[i]);
+        }
+        for (int i = 0; i < driverFWLocalWakeCntArray.length; i++) {
+            sb.append(" driverFWLocalWakeCntArray[" + i + "] " + driverFWLocalWakeCntArray[i]);
+        }
+
         return sb.toString();
     }
 
@@ -111,6 +120,8 @@
         dest.writeInt(ipv4RxMulticast);
         dest.writeInt(ipv6Multicast);
         dest.writeInt(otherRxMulticast);
+        dest.writeIntArray(cmdEventWakeCntArray);
+        dest.writeIntArray(driverFWLocalWakeCntArray);
     }
 
     /* Implement the Parcelable interface
@@ -137,6 +148,8 @@
                 counts.ipv4RxMulticast = in.readInt();
                 counts.ipv6Multicast = in.readInt();
                 counts.otherRxMulticast = in.readInt();
+                in.readIntArray(counts.cmdEventWakeCntArray);
+                in.readIntArray(counts.driverFWLocalWakeCntArray);
                 return counts;
             }
             /* Implement the Parcelable interface
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
similarity index 78%
rename from wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl
rename to wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
index 13efc36..c4ba928 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanEventListener.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanEventCallback.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -23,10 +23,10 @@
  *
  * {@hide}
  */
-oneway interface IWifiNanEventListener
+oneway interface IWifiNanEventCallback
 {
     void onConfigCompleted(in ConfigRequest completedConfig);
-    void onConfigFailed(int reason);
+    void onConfigFailed(in ConfigRequest failedConfig, int reason);
     void onNanDown(int reason);
     void onIdentityChanged();
 }
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
index ff3d29f..d1cf90d 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanManager.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -19,12 +19,10 @@
 import android.app.PendingIntent;
 
 import android.net.wifi.nan.ConfigRequest;
-import android.net.wifi.nan.IWifiNanEventListener;
-import android.net.wifi.nan.IWifiNanSessionListener;
-import android.net.wifi.nan.PublishData;
-import android.net.wifi.nan.PublishSettings;
-import android.net.wifi.nan.SubscribeData;
-import android.net.wifi.nan.SubscribeSettings;
+import android.net.wifi.nan.IWifiNanEventCallback;
+import android.net.wifi.nan.IWifiNanSessionCallback;
+import android.net.wifi.nan.PublishConfig;
+import android.net.wifi.nan.SubscribeConfig;
 
 /**
  * Interface that WifiNanService implements
@@ -34,16 +32,16 @@
 interface IWifiNanManager
 {
     // client API
-    void connect(in IBinder binder, in IWifiNanEventListener listener, int events);
-    void disconnect(in IBinder binder);
-    void requestConfig(in ConfigRequest configRequest);
+    int connect(in IBinder binder, in IWifiNanEventCallback callback, int events);
+    void disconnect(int clientId, in IBinder binder);
+    void requestConfig(int clientId, in ConfigRequest configRequest);
 
     // session API
-    int createSession(in IWifiNanSessionListener listener, int events);
-    void publish(int sessionId, in PublishData publishData, in PublishSettings publishSettings);
-    void subscribe(int sessionId, in SubscribeData subscribeData,
-            in SubscribeSettings subscribeSettings);
-    void sendMessage(int sessionId, int peerId, in byte[] message, int messageLength);
-    void stopSession(int sessionId);
-    void destroySession(int sessionId);
+    int createSession(int clientId, in IWifiNanSessionCallback callback, int events);
+    void publish(int clientId, int sessionId, in PublishConfig publishConfig);
+    void subscribe(int clientId, int sessionId, in SubscribeConfig subscribeConfig);
+    void sendMessage(int clientId, int sessionId, int peerId, in byte[] message, int messageLength,
+            int messageId);
+    void stopSession(int clientId, int sessionId);
+    void destroySession(int clientId, int sessionId);
 }
diff --git a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl
similarity index 79%
rename from wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
rename to wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl
index 773f83b..c79f2f8 100644
--- a/wifi/java/android/net/wifi/nan/IWifiNanSessionListener.aidl
+++ b/wifi/java/android/net/wifi/nan/IWifiNanSessionCallback.aidl
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2016, The Android Open Source Project
+/*
+ * Copyright (C) 2016 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- *     http://www.apache.org/licenses/LICENSE-2.0
+ *      http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -21,7 +21,7 @@
  *
  * {@hide}
  */
-oneway interface IWifiNanSessionListener
+oneway interface IWifiNanSessionCallback
 {
     void onPublishFail(int reason);
     void onPublishTerminated(int reason);
@@ -32,7 +32,7 @@
     void onMatch(int peerId, in byte[] serviceSpecificInfo,
             int serviceSpecificInfoLength, in byte[] matchFilter, int matchFilterLength);
 
-    void onMessageSendSuccess();
-    void onMessageSendFail(int reason);
+    void onMessageSendSuccess(int messageId);
+    void onMessageSendFail(int messageId, int reason);
     void onMessageReceived(int peerId, in byte[] message, int messageLength);
 }
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl b/wifi/java/android/net/wifi/nan/PublishConfig.aidl
similarity index 95%
rename from wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
rename to wifi/java/android/net/wifi/nan/PublishConfig.aidl
index 44849bc..5f66d16 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
+++ b/wifi/java/android/net/wifi/nan/PublishConfig.aidl
@@ -16,4 +16,4 @@
 
 package android.net.wifi.nan;
 
-parcelable SubscribeSettings;
+parcelable PublishConfig;
diff --git a/wifi/java/android/net/wifi/nan/PublishData.java b/wifi/java/android/net/wifi/nan/PublishConfig.java
similarity index 63%
rename from wifi/java/android/net/wifi/nan/PublishData.java
rename to wifi/java/android/net/wifi/nan/PublishConfig.java
index 80119eb..cf5251c 100644
--- a/wifi/java/android/net/wifi/nan/PublishData.java
+++ b/wifi/java/android/net/wifi/nan/PublishConfig.java
@@ -22,13 +22,29 @@
 import java.util.Arrays;
 
 /**
- * Defines the data for a NAN publish session. Built using
- * {@link PublishData.Builder}. Publish is done using
- * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)}
- * or {@link WifiNanPublishSession#publish(PublishData, PublishSettings)}.
+ * Defines the configuration of a NAN publish session. Built using
+ * {@link PublishConfig.Builder}. Publish is done using
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionListener, int)} or
+ * {@link WifiNanPublishSession#publish(PublishConfig)}.
+ *
  * @hide PROPOSED_NAN_API
  */
-public class PublishData implements Parcelable {
+public class PublishConfig implements Parcelable {
+    /**
+     * Defines an unsolicited publish session - i.e. a publish session where
+     * publish packets are transmitted over-the-air. Configuration is done using
+     * {@link PublishConfig.Builder#setPublishType(int)}.
+     */
+    public static final int PUBLISH_TYPE_UNSOLICITED = 0;
+
+    /**
+     * Defines a solicited publish session - i.e. a publish session where
+     * publish packets are not transmitted over-the-air and the device listens
+     * and matches to transmitted subscribe packets. Configuration is done using
+     * {@link PublishConfig.Builder#setPublishType(int)}.
+     */
+    public static final int PUBLISH_TYPE_SOLICITED = 1;
+
     /**
      * @hide
      */
@@ -64,9 +80,24 @@
      */
     public final byte[] mRxFilter;
 
-    private PublishData(String serviceName, byte[] serviceSpecificInfo,
+    /**
+     * @hide
+     */
+    public final int mPublishType;
+
+    /**
+     * @hide
+     */
+    public final int mPublishCount;
+
+    /**
+     * @hide
+     */
+    public final int mTtlSec;
+
+    private PublishConfig(String serviceName, byte[] serviceSpecificInfo,
             int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter,
-            int rxFilterLength) {
+            int rxFilterLength, int publishType, int publichCount, int ttlSec) {
         mServiceName = serviceName;
         mServiceSpecificInfoLength = serviceSpecificInfoLength;
         mServiceSpecificInfo = serviceSpecificInfo;
@@ -74,17 +105,21 @@
         mTxFilter = txFilter;
         mRxFilterLength = rxFilterLength;
         mRxFilter = rxFilter;
+        mPublishType = publishType;
+        mPublishCount = publichCount;
+        mTtlSec = ttlSec;
     }
 
     @Override
     public String toString() {
-        return "PublishData [mServiceName='" + mServiceName + "', mServiceSpecificInfo='"
+        return "PublishConfig [mServiceName='" + mServiceName + "', mServiceSpecificInfo='"
                 + (new String(mServiceSpecificInfo, 0, mServiceSpecificInfoLength))
                 + "', mTxFilter="
                 + (new TlvBufferUtils.TlvIterable(0, 1, mTxFilter, mTxFilterLength)).toString()
                 + ", mRxFilter="
                 + (new TlvBufferUtils.TlvIterable(0, 1, mRxFilter, mRxFilterLength)).toString()
-                + "']";
+                + ", mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount
+                + ", mTtlSec=" + mTtlSec + "']";
     }
 
     @Override
@@ -92,7 +127,6 @@
         return 0;
     }
 
-
     @Override
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mServiceName);
@@ -108,16 +142,19 @@
         if (mRxFilterLength != 0) {
             dest.writeByteArray(mRxFilter, 0, mRxFilterLength);
         }
+        dest.writeInt(mPublishType);
+        dest.writeInt(mPublishCount);
+        dest.writeInt(mTtlSec);
     }
 
-    public static final Creator<PublishData> CREATOR = new Creator<PublishData>() {
+    public static final Creator<PublishConfig> CREATOR = new Creator<PublishConfig>() {
         @Override
-        public PublishData[] newArray(int size) {
-            return new PublishData[size];
+        public PublishConfig[] newArray(int size) {
+            return new PublishConfig[size];
         }
 
         @Override
-        public PublishData createFromParcel(Parcel in) {
+        public PublishConfig createFromParcel(Parcel in) {
             String serviceName = in.readString();
             int ssiLength = in.readInt();
             byte[] ssi = new byte[ssiLength];
@@ -134,9 +171,11 @@
             if (rxFilterLength != 0) {
                 in.readByteArray(rxFilter);
             }
-
-            return new PublishData(serviceName, ssi, ssiLength, txFilter, txFilterLength, rxFilter,
-                    rxFilterLength);
+            int publishType = in.readInt();
+            int publishCount = in.readInt();
+            int ttlSec = in.readInt();
+            return new PublishConfig(serviceName, ssi, ssiLength, txFilter, txFilterLength,
+                    rxFilter, rxFilterLength, publishType, publishCount, ttlSec);
         }
     };
 
@@ -146,11 +185,11 @@
             return true;
         }
 
-        if (!(o instanceof PublishData)) {
+        if (!(o instanceof PublishConfig)) {
             return false;
         }
 
-        PublishData lhs = (PublishData) o;
+        PublishConfig lhs = (PublishConfig) o;
 
         if (!mServiceName.equals(lhs.mServiceName)
                 || mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength
@@ -189,7 +228,8 @@
             return false; // invalid != invalid
         }
 
-        return true;
+        return mPublishType == lhs.mPublishType && mPublishCount == lhs.mPublishCount
+                && mTtlSec == lhs.mTtlSec;
     }
 
     @Override
@@ -203,12 +243,15 @@
         result = 31 * result + Arrays.hashCode(mTxFilter);
         result = 31 * result + mRxFilterLength;
         result = 31 * result + Arrays.hashCode(mRxFilter);
+        result = 31 * result + mPublishType;
+        result = 31 * result + mPublishCount;
+        result = 31 * result + mTtlSec;
 
         return result;
     }
 
     /**
-     * Builder used to build {@link PublishData} objects.
+     * Builder used to build {@link PublishConfig} objects.
      */
     public static final class Builder {
         private String mServiceName;
@@ -218,6 +261,9 @@
         private byte[] mTxFilter = new byte[0];
         private int mRxFilterLength;
         private byte[] mRxFilter = new byte[0];
+        private int mPublishType;
+        private int mPublishCount;
+        private int mTtlSec;
 
         /**
          * Specify the service name of the publish session. The actual on-air
@@ -260,7 +306,7 @@
 
         /**
          * Specify service specific information for the publish session - same
-         * as {@link PublishData.Builder#setServiceSpecificInfo(byte[], int)}
+         * as {@link PublishConfig.Builder#setServiceSpecificInfo(byte[], int)}
          * but obtaining the data from a String.
          *
          * @param serviceSpecificInfoStr The service specific information string
@@ -277,8 +323,8 @@
 
         /**
          * The transmit filter for an active publish session
-         * {@link PublishSettings.Builder#setPublishType(int)} and
-         * {@link PublishSettings#PUBLISH_TYPE_UNSOLICITED}. Included in
+         * {@link PublishConfig.Builder#setPublishType(int)} and
+         * {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED}. Included in
          * transmitted publish packets and used by receivers (subscribers) to
          * determine whether they match - in addition to just relying on the
          * service name.
@@ -305,8 +351,8 @@
 
         /**
          * The transmit filter for a passive publish session
-         * {@link PublishSettings.Builder#setPublishType(int)} and
-         * {@link PublishSettings#PUBLISH_TYPE_SOLICITED}. Used by the publisher
+         * {@link PublishConfig.Builder#setPublishType(int)} and
+         * {@link PublishConfig#PUBLISH_TYPE_SOLICITED}. Used by the publisher
          * to determine whether they match transmitted subscriber packets
          * (active subscribers) - in addition to just relying on the service
          * name.
@@ -332,12 +378,73 @@
         }
 
         /**
-         * Build {@link PublishData} given the current requests made on the
+         * Sets the type of the publish session: solicited (aka active - publish
+         * packets are transmitted over-the-air), or unsolicited (aka passive -
+         * no publish packets are transmitted, a match is made against an active
+         * subscribe session whose packets are transmitted over-the-air).
+         *
+         * @param publishType Publish session type: solicited (
+         *            {@link PublishConfig#PUBLISH_TYPE_SOLICITED}) or
+         *            unsolicited (
+         *            {@link PublishConfig#PUBLISH_TYPE_UNSOLICITED}).
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setPublishType(int publishType) {
+            if (publishType < PUBLISH_TYPE_UNSOLICITED || publishType > PUBLISH_TYPE_SOLICITED) {
+                throw new IllegalArgumentException("Invalid publishType - " + publishType);
+            }
+            mPublishType = publishType;
+            return this;
+        }
+
+        /**
+         * Sets the number of times a solicited (
+         * {@link PublishConfig.Builder#setPublishType(int)}) publish session
+         * will transmit a packet. When the count is reached an event will be
+         * generated for {@link WifiNanSessionListener#onPublishTerminated(int)}
+         * with reason={@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
+         *
+         * @param publishCount Number of publish packets to transmit.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setPublishCount(int publishCount) {
+            if (publishCount < 0) {
+                throw new IllegalArgumentException("Invalid publishCount - must be non-negative");
+            }
+            mPublishCount = publishCount;
+            return this;
+        }
+
+        /**
+         * Sets the time interval (in seconds) a solicited (
+         * {@link PublishConfig.Builder#setPublishCount(int)}) publish session
+         * will be alive - i.e. transmitting a packet. When the TTL is reached
+         * an event will be generated for
+         * {@link WifiNanSessionListener#onPublishTerminated(int)} with reason=
+         * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
+         *
+         * @param ttlSec Lifetime of a publish session in seconds.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setTtlSec(int ttlSec) {
+            if (ttlSec < 0) {
+                throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
+            }
+            mTtlSec = ttlSec;
+            return this;
+        }
+
+        /**
+         * Build {@link PublishConfig} given the current requests made on the
          * builder.
          */
-        public PublishData build() {
-            return new PublishData(mServiceName, mServiceSpecificInfo, mServiceSpecificInfoLength,
-                    mTxFilter, mTxFilterLength, mRxFilter, mRxFilterLength);
+        public PublishConfig build() {
+            return new PublishConfig(mServiceName, mServiceSpecificInfo, mServiceSpecificInfoLength,
+                    mTxFilter, mTxFilterLength, mRxFilter, mRxFilterLength, mPublishType,
+                    mPublishCount, mTtlSec);
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/PublishData.aidl b/wifi/java/android/net/wifi/nan/PublishData.aidl
deleted file mode 100644
index 15e4ddf..0000000
--- a/wifi/java/android/net/wifi/nan/PublishData.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.nan;
-
-parcelable PublishData;
diff --git a/wifi/java/android/net/wifi/nan/PublishSettings.aidl b/wifi/java/android/net/wifi/nan/PublishSettings.aidl
deleted file mode 100644
index ff69293..0000000
--- a/wifi/java/android/net/wifi/nan/PublishSettings.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.nan;
-
-parcelable PublishSettings;
diff --git a/wifi/java/android/net/wifi/nan/PublishSettings.java b/wifi/java/android/net/wifi/nan/PublishSettings.java
deleted file mode 100644
index bbc5340..0000000
--- a/wifi/java/android/net/wifi/nan/PublishSettings.java
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.nan;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Defines the settings (configuration) for a NAN publish session. Built using
- * {@link PublishSettings.Builder}. Publish is done using
- * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)}
- * or {@link WifiNanPublishSession#publish(PublishData, PublishSettings)}.
- *
- * @hide PROPOSED_NAN_API
- */
-public class PublishSettings implements Parcelable {
-
-    /**
-     * Defines an unsolicited publish session - i.e. a publish session where
-     * publish packets are transmitted over-the-air. Configuration is done using
-     * {@link PublishSettings.Builder#setPublishType(int)}.
-     */
-    public static final int PUBLISH_TYPE_UNSOLICITED = 0;
-
-    /**
-     * Defines a solicited publish session - i.e. a publish session where
-     * publish packets are not transmitted over-the-air and the device listens
-     * and matches to transmitted subscribe packets. Configuration is done using
-     * {@link PublishSettings.Builder#setPublishType(int)}.
-     */
-    public static final int PUBLISH_TYPE_SOLICITED = 1;
-
-    /**
-     * @hide
-     */
-    public final int mPublishType;
-
-    /**
-     * @hide
-     */
-    public final int mPublishCount;
-
-    /**
-     * @hide
-     */
-    public final int mTtlSec;
-
-    private PublishSettings(int publishType, int publichCount, int ttlSec) {
-        mPublishType = publishType;
-        mPublishCount = publichCount;
-        mTtlSec = ttlSec;
-    }
-
-    @Override
-    public String toString() {
-        return "PublishSettings [mPublishType=" + mPublishType + ", mPublishCount=" + mPublishCount
-                + ", mTtlSec=" + mTtlSec + "]";
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mPublishType);
-        dest.writeInt(mPublishCount);
-        dest.writeInt(mTtlSec);
-    }
-
-    public static final Creator<PublishSettings> CREATOR = new Creator<PublishSettings>() {
-        @Override
-        public PublishSettings[] newArray(int size) {
-            return new PublishSettings[size];
-        }
-
-        @Override
-        public PublishSettings createFromParcel(Parcel in) {
-            int publishType = in.readInt();
-            int publishCount = in.readInt();
-            int ttlSec = in.readInt();
-            return new PublishSettings(publishType, publishCount, ttlSec);
-        }
-    };
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-
-        if (!(o instanceof PublishSettings)) {
-            return false;
-        }
-
-        PublishSettings lhs = (PublishSettings) o;
-
-        return mPublishType == lhs.mPublishType && mPublishCount == lhs.mPublishCount
-                && mTtlSec == lhs.mTtlSec;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-
-        result = 31 * result + mPublishType;
-        result = 31 * result + mPublishCount;
-        result = 31 * result + mTtlSec;
-
-        return result;
-    }
-
-    /**
-     * Builder used to build {@link PublishSettings} objects.
-     */
-    public static final class Builder {
-        int mPublishType;
-        int mPublishCount;
-        int mTtlSec;
-
-        /**
-         * Sets the type of the publish session: solicited (aka active - publish
-         * packets are transmitted over-the-air), or unsolicited (aka passive -
-         * no publish packets are transmitted, a match is made against an active
-         * subscribe session whose packets are transmitted over-the-air).
-         *
-         * @param publishType Publish session type: solicited (
-         *            {@link PublishSettings#PUBLISH_TYPE_SOLICITED}) or
-         *            unsolicited (
-         *            {@link PublishSettings#PUBLISH_TYPE_UNSOLICITED}).
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setPublishType(int publishType) {
-            if (publishType < PUBLISH_TYPE_UNSOLICITED || publishType > PUBLISH_TYPE_SOLICITED) {
-                throw new IllegalArgumentException("Invalid publishType - " + publishType);
-            }
-            mPublishType = publishType;
-            return this;
-        }
-
-        /**
-         * Sets the number of times a solicited (
-         * {@link PublishSettings.Builder#setPublishType(int)}) publish session
-         * will transmit a packet. When the count is reached an event will be
-         * generated for {@link WifiNanSessionListener#onPublishTerminated(int)}
-         * with reason={@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
-         *
-         * @param publishCount Number of publish packets to transmit.
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setPublishCount(int publishCount) {
-            if (publishCount < 0) {
-                throw new IllegalArgumentException("Invalid publishCount - must be non-negative");
-            }
-            mPublishCount = publishCount;
-            return this;
-        }
-
-        /**
-         * Sets the time interval (in seconds) a solicited (
-         * {@link PublishSettings.Builder#setPublishCount(int)}) publish session
-         * will be alive - i.e. transmitting a packet. When the TTL is reached
-         * an event will be generated for
-         * {@link WifiNanSessionListener#onPublishTerminated(int)} with reason=
-         * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
-         *
-         * @param ttlSec Lifetime of a publish session in seconds.
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setTtlSec(int ttlSec) {
-            if (ttlSec < 0) {
-                throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
-            }
-            mTtlSec = ttlSec;
-            return this;
-        }
-
-        /**
-         * Build {@link PublishSettings} given the current requests made on the
-         * builder.
-         */
-        public PublishSettings build() {
-            return new PublishSettings(mPublishType, mPublishCount, mTtlSec);
-        }
-    }
-}
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl b/wifi/java/android/net/wifi/nan/SubscribeConfig.aidl
similarity index 95%
copy from wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
copy to wifi/java/android/net/wifi/nan/SubscribeConfig.aidl
index 44849bc..92344a4 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeSettings.aidl
+++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.aidl
@@ -16,4 +16,4 @@
 
 package android.net.wifi.nan;
 
-parcelable SubscribeSettings;
+parcelable SubscribeConfig;
diff --git a/wifi/java/android/net/wifi/nan/SubscribeData.java b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
similarity index 60%
rename from wifi/java/android/net/wifi/nan/SubscribeData.java
rename to wifi/java/android/net/wifi/nan/SubscribeConfig.java
index cd6e918..4798293 100644
--- a/wifi/java/android/net/wifi/nan/SubscribeData.java
+++ b/wifi/java/android/net/wifi/nan/SubscribeConfig.java
@@ -22,14 +22,30 @@
 import java.util.Arrays;
 
 /**
- * Defines the data for a NAN subscribe session. Built using
- * {@link SubscribeData.Builder}. Subscribe is done using
- * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)}
- * or
- * {@link WifiNanSubscribeSession#subscribe(SubscribeData, SubscribeSettings)}.
+ * Defines the configuration of a NAN subscribe session. Built using
+ * {@link SubscribeConfig.Builder}. Subscribe is done using
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionListener, int)}
+ * or {@link WifiNanSubscribeSession#subscribe(SubscribeConfig)}.
+ *
  * @hide PROPOSED_NAN_API
  */
-public class SubscribeData implements Parcelable {
+public class SubscribeConfig implements Parcelable {
+
+    /**
+     * Defines a passive subscribe session - i.e. a subscribe session where
+     * subscribe packets are not transmitted over-the-air and the device listens
+     * and matches to transmitted publish packets. Configuration is done using
+     * {@link SubscribeConfig.Builder#setSubscribeType(int)}.
+     */
+    public static final int SUBSCRIBE_TYPE_PASSIVE = 0;
+
+    /**
+     * Defines an active subscribe session - i.e. a subscribe session where
+     * subscribe packets are transmitted over-the-air. Configuration is done
+     * using {@link SubscribeConfig.Builder#setSubscribeType(int)}.
+     */
+    public static final int SUBSCRIBE_TYPE_ACTIVE = 1;
+
     /**
      * @hide
      */
@@ -65,9 +81,24 @@
      */
     public final byte[] mRxFilter;
 
-    private SubscribeData(String serviceName, byte[] serviceSpecificInfo,
+    /**
+     * @hide
+     */
+    public final int mSubscribeType;
+
+    /**
+     * @hide
+     */
+    public final int mSubscribeCount;
+
+    /**
+     * @hide
+     */
+    public final int mTtlSec;
+
+    private SubscribeConfig(String serviceName, byte[] serviceSpecificInfo,
             int serviceSpecificInfoLength, byte[] txFilter, int txFilterLength, byte[] rxFilter,
-            int rxFilterLength) {
+            int rxFilterLength, int subscribeType, int publichCount, int ttlSec) {
         mServiceName = serviceName;
         mServiceSpecificInfoLength = serviceSpecificInfoLength;
         mServiceSpecificInfo = serviceSpecificInfo;
@@ -75,17 +106,21 @@
         mTxFilter = txFilter;
         mRxFilterLength = rxFilterLength;
         mRxFilter = rxFilter;
+        mSubscribeType = subscribeType;
+        mSubscribeCount = publichCount;
+        mTtlSec = ttlSec;
     }
 
     @Override
     public String toString() {
-        return "SubscribeData [mServiceName='" + mServiceName + "', mServiceSpecificInfo='"
+        return "SubscribeConfig [mServiceName='" + mServiceName + "', mServiceSpecificInfo='"
                 + (new String(mServiceSpecificInfo, 0, mServiceSpecificInfoLength))
                 + "', mTxFilter="
                 + (new TlvBufferUtils.TlvIterable(0, 1, mTxFilter, mTxFilterLength)).toString()
                 + ", mRxFilter="
                 + (new TlvBufferUtils.TlvIterable(0, 1, mRxFilter, mRxFilterLength)).toString()
-                + "']";
+                + ", mSubscribeType=" + mSubscribeType + ", mSubscribeCount=" + mSubscribeCount
+                + ", mTtlSec=" + mTtlSec + "']";
     }
 
     @Override
@@ -108,16 +143,19 @@
         if (mRxFilterLength != 0) {
             dest.writeByteArray(mRxFilter, 0, mRxFilterLength);
         }
+        dest.writeInt(mSubscribeType);
+        dest.writeInt(mSubscribeCount);
+        dest.writeInt(mTtlSec);
     }
 
-    public static final Creator<SubscribeData> CREATOR = new Creator<SubscribeData>() {
+    public static final Creator<SubscribeConfig> CREATOR = new Creator<SubscribeConfig>() {
         @Override
-        public SubscribeData[] newArray(int size) {
-            return new SubscribeData[size];
+        public SubscribeConfig[] newArray(int size) {
+            return new SubscribeConfig[size];
         }
 
         @Override
-        public SubscribeData createFromParcel(Parcel in) {
+        public SubscribeConfig createFromParcel(Parcel in) {
             String serviceName = in.readString();
             int ssiLength = in.readInt();
             byte[] ssi = new byte[ssiLength];
@@ -134,9 +172,11 @@
             if (rxFilterLength != 0) {
                 in.readByteArray(rxFilter);
             }
-
-            return new SubscribeData(serviceName, ssi, ssiLength, txFilter, txFilterLength,
-                    rxFilter, rxFilterLength);
+            int subscribeType = in.readInt();
+            int subscribeCount = in.readInt();
+            int ttlSec = in.readInt();
+            return new SubscribeConfig(serviceName, ssi, ssiLength, txFilter, txFilterLength,
+                    rxFilter, rxFilterLength, subscribeType, subscribeCount, ttlSec);
         }
     };
 
@@ -146,11 +186,11 @@
             return true;
         }
 
-        if (!(o instanceof SubscribeData)) {
+        if (!(o instanceof SubscribeConfig)) {
             return false;
         }
 
-        SubscribeData lhs = (SubscribeData) o;
+        SubscribeConfig lhs = (SubscribeConfig) o;
 
         if (!mServiceName.equals(lhs.mServiceName)
                 || mServiceSpecificInfoLength != lhs.mServiceSpecificInfoLength
@@ -189,7 +229,8 @@
             return false; // invalid != invalid
         }
 
-        return true;
+        return mSubscribeType == lhs.mSubscribeType && mSubscribeCount == lhs.mSubscribeCount
+                && mTtlSec == lhs.mTtlSec;
     }
 
     @Override
@@ -203,12 +244,15 @@
         result = 31 * result + Arrays.hashCode(mTxFilter);
         result = 31 * result + mRxFilterLength;
         result = 31 * result + Arrays.hashCode(mRxFilter);
+        result = 31 * result + mSubscribeType;
+        result = 31 * result + mSubscribeCount;
+        result = 31 * result + mTtlSec;
 
         return result;
     }
 
     /**
-     * Builder used to build {@link SubscribeData} objects.
+     * Builder used to build {@link SubscribeConfig} objects.
      */
     public static final class Builder {
         private String mServiceName;
@@ -218,6 +262,9 @@
         private byte[] mTxFilter = new byte[0];
         private int mRxFilterLength;
         private byte[] mRxFilter = new byte[0];
+        private int mSubscribeType;
+        private int mSubscribeCount;
+        private int mTtlSec;
 
         /**
          * Specify the service name of the subscribe session. The actual on-air
@@ -255,7 +302,8 @@
 
         /**
          * Specify service specific information for the subscribe session - same
-         * as {@link SubscribeData.Builder#setServiceSpecificInfo(byte[], int)}
+         * as
+         * {@link SubscribeConfig.Builder#setServiceSpecificInfo(byte[], int)}
          * but obtaining the data from a String.
          *
          * @param serviceSpecificInfoStr The service specific information string
@@ -272,8 +320,8 @@
 
         /**
          * The transmit filter for an active subscribe session
-         * {@link SubscribeSettings.Builder#setSubscribeType(int)} and
-         * {@link SubscribeSettings#SUBSCRIBE_TYPE_ACTIVE}. Included in
+         * {@link SubscribeConfig.Builder#setSubscribeType(int)} and
+         * {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}. Included in
          * transmitted subscribe packets and used by receivers (passive
          * publishers) to determine whether they match - in addition to just
          * relying on the service name.
@@ -296,8 +344,8 @@
 
         /**
          * The transmit filter for a passive subsribe session
-         * {@link SubscribeSettings.Builder#setSubscribeType(int)} and
-         * {@link SubscribeSettings#SUBSCRIBE_TYPE_PASSIVE}. Used by the
+         * {@link SubscribeConfig.Builder#setSubscribeType(int)} and
+         * {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE}. Used by the
          * subscriber to determine whether they match transmitted publish
          * packets - in addition to just relying on the service name.
          * <p>
@@ -318,12 +366,73 @@
         }
 
         /**
-         * Build {@link SubscribeData} given the current requests made on the
+         * Sets the type of the subscribe session: active (subscribe packets are
+         * transmitted over-the-air), or passive (no subscribe packets are
+         * transmitted, a match is made against a solicited/active publish
+         * session whose packets are transmitted over-the-air).
+         *
+         * @param subscribeType Subscribe session type: active (
+         *            {@link SubscribeConfig#SUBSCRIBE_TYPE_ACTIVE}) or passive
+         *            ( {@link SubscribeConfig#SUBSCRIBE_TYPE_PASSIVE} ).
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setSubscribeType(int subscribeType) {
+            if (subscribeType < SUBSCRIBE_TYPE_PASSIVE || subscribeType > SUBSCRIBE_TYPE_ACTIVE) {
+                throw new IllegalArgumentException("Invalid subscribeType - " + subscribeType);
+            }
+            mSubscribeType = subscribeType;
+            return this;
+        }
+
+        /**
+         * Sets the number of times an active (
+         * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe
+         * session will transmit a packet. When the count is reached an event
+         * will be generated for
+         * {@link WifiNanSessionListener#onSubscribeTerminated(int)} with
+         * reason= {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
+         *
+         * @param subscribeCount Number of subscribe packets to transmit.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setSubscribeCount(int subscribeCount) {
+            if (subscribeCount < 0) {
+                throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative");
+            }
+            mSubscribeCount = subscribeCount;
+            return this;
+        }
+
+        /**
+         * Sets the time interval (in seconds) an active (
+         * {@link SubscribeConfig.Builder#setSubscribeType(int)}) subscribe
+         * session will be alive - i.e. transmitting a packet. When the TTL is
+         * reached an event will be generated for
+         * {@link WifiNanSessionListener#onSubscribeTerminated(int)} with
+         * reason= {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
+         *
+         * @param ttlSec Lifetime of a subscribe session in seconds.
+         * @return The builder to facilitate chaining
+         *         {@code builder.setXXX(..).setXXX(..)}.
+         */
+        public Builder setTtlSec(int ttlSec) {
+            if (ttlSec < 0) {
+                throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
+            }
+            mTtlSec = ttlSec;
+            return this;
+        }
+
+        /**
+         * Build {@link SubscribeConfig} given the current requests made on the
          * builder.
          */
-        public SubscribeData build() {
-            return new SubscribeData(mServiceName, mServiceSpecificInfo, mServiceSpecificInfoLength,
-                    mTxFilter, mTxFilterLength, mRxFilter, mRxFilterLength);
+        public SubscribeConfig build() {
+            return new SubscribeConfig(mServiceName, mServiceSpecificInfo,
+                    mServiceSpecificInfoLength, mTxFilter, mTxFilterLength, mRxFilter,
+                    mRxFilterLength, mSubscribeType, mSubscribeCount, mTtlSec);
         }
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/SubscribeData.aidl b/wifi/java/android/net/wifi/nan/SubscribeData.aidl
deleted file mode 100644
index 662fdb8..0000000
--- a/wifi/java/android/net/wifi/nan/SubscribeData.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.nan;
-
-parcelable SubscribeData;
diff --git a/wifi/java/android/net/wifi/nan/SubscribeSettings.java b/wifi/java/android/net/wifi/nan/SubscribeSettings.java
deleted file mode 100644
index 5c4f8fb..0000000
--- a/wifi/java/android/net/wifi/nan/SubscribeSettings.java
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.nan;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Defines the settings (configuration) for a NAN subscribe session. Built using
- * {@link SubscribeSettings.Builder}. Subscribe is done using
- * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)}
- * or {@link WifiNanSubscribeSession#subscribe(SubscribeData, SubscribeSettings)}.
- *
- * @hide PROPOSED_NAN_API
- */
-public class SubscribeSettings implements Parcelable {
-
-    /**
-     * Defines a passive subscribe session - i.e. a subscribe session where
-     * subscribe packets are not transmitted over-the-air and the device listens
-     * and matches to transmitted publish packets. Configuration is done using
-     * {@link SubscribeSettings.Builder#setSubscribeType(int)}.
-     */
-    public static final int SUBSCRIBE_TYPE_PASSIVE = 0;
-
-    /**
-     * Defines an active subscribe session - i.e. a subscribe session where
-     * subscribe packets are transmitted over-the-air. Configuration is done
-     * using {@link SubscribeSettings.Builder#setSubscribeType(int)}.
-     */
-    public static final int SUBSCRIBE_TYPE_ACTIVE = 1;
-
-    /**
-     * @hide
-     */
-    public final int mSubscribeType;
-
-    /**
-     * @hide
-     */
-    public final int mSubscribeCount;
-
-    /**
-     * @hide
-     */
-    public final int mTtlSec;
-
-    private SubscribeSettings(int subscribeType, int publichCount, int ttlSec) {
-        mSubscribeType = subscribeType;
-        mSubscribeCount = publichCount;
-        mTtlSec = ttlSec;
-    }
-
-    @Override
-    public String toString() {
-        return "SubscribeSettings [mSubscribeType=" + mSubscribeType + ", mSubscribeCount="
-                + mSubscribeCount + ", mTtlSec=" + mTtlSec + "]";
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mSubscribeType);
-        dest.writeInt(mSubscribeCount);
-        dest.writeInt(mTtlSec);
-    }
-
-    public static final Creator<SubscribeSettings> CREATOR = new Creator<SubscribeSettings>() {
-        @Override
-        public SubscribeSettings[] newArray(int size) {
-            return new SubscribeSettings[size];
-        }
-
-        @Override
-        public SubscribeSettings createFromParcel(Parcel in) {
-            int subscribeType = in.readInt();
-            int subscribeCount = in.readInt();
-            int ttlSec = in.readInt();
-            return new SubscribeSettings(subscribeType, subscribeCount, ttlSec);
-        }
-    };
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-
-        if (!(o instanceof SubscribeSettings)) {
-            return false;
-        }
-
-        SubscribeSettings lhs = (SubscribeSettings) o;
-
-        return mSubscribeType == lhs.mSubscribeType && mSubscribeCount == lhs.mSubscribeCount
-                && mTtlSec == lhs.mTtlSec;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 17;
-
-        result = 31 * result + mSubscribeType;
-        result = 31 * result + mSubscribeCount;
-        result = 31 * result + mTtlSec;
-
-        return result;
-    }
-
-    /**
-     * Builder used to build {@link SubscribeSettings} objects.
-     */
-    public static final class Builder {
-        int mSubscribeType;
-        int mSubscribeCount;
-        int mTtlSec;
-
-        /**
-         * Sets the type of the subscribe session: active (subscribe packets are
-         * transmitted over-the-air), or passive (no subscribe packets are
-         * transmitted, a match is made against a solicited/active publish
-         * session whose packets are transmitted over-the-air).
-         *
-         * @param subscribeType Subscribe session type: active (
-         *            {@link SubscribeSettings#SUBSCRIBE_TYPE_ACTIVE}) or
-         *            passive ( {@link SubscribeSettings#SUBSCRIBE_TYPE_PASSIVE}
-         *            ).
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setSubscribeType(int subscribeType) {
-            if (subscribeType < SUBSCRIBE_TYPE_PASSIVE || subscribeType > SUBSCRIBE_TYPE_ACTIVE) {
-                throw new IllegalArgumentException("Invalid subscribeType - " + subscribeType);
-            }
-            mSubscribeType = subscribeType;
-            return this;
-        }
-
-        /**
-         * Sets the number of times an active (
-         * {@link SubscribeSettings.Builder#setSubscribeType(int)}) subscribe
-         * session will transmit a packet. When the count is reached an event
-         * will be generated for
-         * {@link WifiNanSessionListener#onSubscribeTerminated(int)} with reason=
-         * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
-         *
-         * @param subscribeCount Number of subscribe packets to transmit.
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setSubscribeCount(int subscribeCount) {
-            if (subscribeCount < 0) {
-                throw new IllegalArgumentException("Invalid subscribeCount - must be non-negative");
-            }
-            mSubscribeCount = subscribeCount;
-            return this;
-        }
-
-        /**
-         * Sets the time interval (in seconds) an active (
-         * {@link SubscribeSettings.Builder#setSubscribeType(int)}) subscribe
-         * session will be alive - i.e. transmitting a packet. When the TTL is
-         * reached an event will be generated for
-         * {@link WifiNanSessionListener#onSubscribeTerminated(int)} with reason=
-         * {@link WifiNanSessionListener#TERMINATE_REASON_DONE}.
-         *
-         * @param ttlSec Lifetime of a subscribe session in seconds.
-         * @return The builder to facilitate chaining
-         *         {@code builder.setXXX(..).setXXX(..)}.
-         */
-        public Builder setTtlSec(int ttlSec) {
-            if (ttlSec < 0) {
-                throw new IllegalArgumentException("Invalid ttlSec - must be non-negative");
-            }
-            mTtlSec = ttlSec;
-            return this;
-        }
-
-        /**
-         * Build {@link SubscribeSettings} given the current requests made on
-         * the builder.
-         */
-        public SubscribeSettings build() {
-            return new SubscribeSettings(mSubscribeType, mSubscribeCount, mTtlSec);
-        }
-    }
-}
diff --git a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
similarity index 62%
rename from wifi/java/android/net/wifi/nan/WifiNanEventListener.java
rename to wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
index eae0a55..a0f7023 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanEventListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanEventCallback.java
@@ -25,81 +25,83 @@
  * Base class for NAN events callbacks. Should be extended by applications
  * wanting notifications. These are callbacks applying to the NAN connection as
  * a whole - not to specific publish or subscribe sessions - for that see
- * {@link WifiNanSessionListener}.
+ * {@link WifiNanSessionCallback}.
  * <p>
  * During registration specify which specific events are desired using a set of
- * {@code NanEventListener.LISTEN_*} flags OR'd together. Only those events will
- * be delivered to the registered listener. Override those callbacks
- * {@code NanEventListener.on*} for the registered events.
+ * {@code NanEventCallback.LISTEN_*} flags OR'd together. Only those events will
+ * be delivered to the registered callback. Override those callbacks
+ * {@code WifiNanEventCallback.on*} for the registered events.
  *
  * @hide PROPOSED_NAN_API
  */
-public class WifiNanEventListener {
-    private static final String TAG = "WifiNanEventListener";
-    private static final boolean DBG = true;
+public class WifiNanEventCallback {
+    private static final String TAG = "WifiNanEventCallback";
+    private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     /**
      * Configuration completion callback event registration flag. Corresponding
-     * callback is {@link WifiNanEventListener#onConfigCompleted(ConfigRequest)}.
+     * callback is {@link WifiNanEventCallback#onConfigCompleted(ConfigRequest)}
+     * .
      */
-    public static final int LISTEN_CONFIG_COMPLETED = 0x1 << 0;
+    public static final int FLAG_LISTEN_CONFIG_COMPLETED = 0x1 << 0;
 
     /**
      * Configuration failed callback event registration flag. Corresponding
-     * callback is {@link WifiNanEventListener#onConfigFailed(int)}.
+     * callback is
+     * {@link WifiNanEventCallback#onConfigFailed(ConfigRequest, int)}.
      */
-    public static final int LISTEN_CONFIG_FAILED = 0x1 << 1;
+    public static final int FLAG_LISTEN_CONFIG_FAILED = 0x1 << 1;
 
     /**
      * NAN cluster is down callback event registration flag. Corresponding
-     * callback is {@link WifiNanEventListener#onNanDown(int)}.
+     * callback is {@link WifiNanEventCallback#onNanDown(int)}.
      */
-    public static final int LISTEN_NAN_DOWN = 0x1 << 2;
+    public static final int FLAG_LISTEN_NAN_DOWN = 0x1 << 2;
 
     /**
      * NAN identity has changed event registration flag. This may be due to
      * joining a cluster, starting a cluster, or discovery interface change. The
      * implication is that peers you've been communicating with may no longer
      * recognize you and you need to re-establish your identity. Corresponding
-     * callback is {@link WifiNanEventListener#onIdentityChanged()}.
+     * callback is {@link WifiNanEventCallback#onIdentityChanged()}.
      */
-    public static final int LISTEN_IDENTITY_CHANGED = 0x1 << 3;
+    public static final int FLAG_LISTEN_IDENTITY_CHANGED = 0x1 << 3;
 
     private final Handler mHandler;
 
     /**
-     * Constructs a {@link WifiNanEventListener} using the looper of the current
+     * Constructs a {@link WifiNanEventCallback} using the looper of the current
      * thread. I.e. all callbacks will be delivered on the current thread.
      */
-    public WifiNanEventListener() {
+    public WifiNanEventCallback() {
         this(Looper.myLooper());
     }
 
     /**
-     * Constructs a {@link WifiNanEventListener} using the specified looper. I.e.
-     * all callbacks will delivered on the thread of the specified looper.
+     * Constructs a {@link WifiNanEventCallback} using the specified looper.
+     * I.e. all callbacks will delivered on the thread of the specified looper.
      *
      * @param looper The looper on which to execute the callbacks.
      */
-    public WifiNanEventListener(Looper looper) {
+    public WifiNanEventCallback(Looper looper) {
         if (VDBG) Log.v(TAG, "ctor: looper=" + looper);
         mHandler = new Handler(looper) {
             @Override
             public void handleMessage(Message msg) {
                 if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg);
                 switch (msg.what) {
-                    case LISTEN_CONFIG_COMPLETED:
-                        WifiNanEventListener.this.onConfigCompleted((ConfigRequest) msg.obj);
+                    case FLAG_LISTEN_CONFIG_COMPLETED:
+                        WifiNanEventCallback.this.onConfigCompleted((ConfigRequest) msg.obj);
                         break;
-                    case LISTEN_CONFIG_FAILED:
-                        WifiNanEventListener.this.onConfigFailed(msg.arg1);
+                    case FLAG_LISTEN_CONFIG_FAILED:
+                        WifiNanEventCallback.this.onConfigFailed((ConfigRequest) msg.obj, msg.arg1);
                         break;
-                    case LISTEN_NAN_DOWN:
-                        WifiNanEventListener.this.onNanDown(msg.arg1);
+                    case FLAG_LISTEN_NAN_DOWN:
+                        WifiNanEventCallback.this.onNanDown(msg.arg1);
                         break;
-                    case LISTEN_IDENTITY_CHANGED:
-                        WifiNanEventListener.this.onIdentityChanged();
+                    case FLAG_LISTEN_IDENTITY_CHANGED:
+                        WifiNanEventCallback.this.onIdentityChanged();
                         break;
                 }
             }
@@ -108,8 +110,8 @@
 
     /**
      * Called when NAN configuration is completed. Event will only be delivered
-     * if registered using {@link WifiNanEventListener#LISTEN_CONFIG_COMPLETED}. A
-     * dummy (empty implementation printing out a warning). Make sure to
+     * if registered using {@link WifiNanEventCallback#FLAG_LISTEN_CONFIG_COMPLETED}.
+     * A dummy (empty implementation printing out a warning). Make sure to
      * override if registered.
      *
      * @param completedConfig The actual configuration request which was
@@ -123,23 +125,25 @@
 
     /**
      * Called when NAN configuration failed. Event will only be delivered if
-     * registered using {@link WifiNanEventListener#LISTEN_CONFIG_FAILED}. A dummy
-     * (empty implementation printing out a warning). Make sure to override if
-     * registered.
+     * registered using {@link WifiNanEventCallback#FLAG_LISTEN_CONFIG_FAILED}. A
+     * dummy (empty implementation printing out a warning). Make sure to
+     * override if registered.
      *
-     * @param reason Failure reason code, see {@code NanSessionListener.FAIL_*}.
+     * @param reason Failure reason code, see
+     *            {@code WifiNanSessionCallback.FAIL_*}.
      */
-    public void onConfigFailed(int reason) {
+    public void onConfigFailed(ConfigRequest failedConfig, int reason) {
         Log.w(TAG, "onConfigFailed: called in stub - override if interested or disable");
     }
 
     /**
      * Called when NAN cluster is down. Event will only be delivered if
-     * registered using {@link WifiNanEventListener#LISTEN_NAN_DOWN}. A dummy (empty
-     * implementation printing out a warning). Make sure to override if
+     * registered using {@link WifiNanEventCallback#FLAG_LISTEN_NAN_DOWN}. A dummy
+     * (empty implementation printing out a warning). Make sure to override if
      * registered.
      *
-     * @param reason Reason code for event, see {@code NanSessionListener.FAIL_*}.
+     * @param reason Reason code for event, see
+     *            {@code WifiNanSessionCallback.FAIL_*}.
      */
     public void onNanDown(int reason) {
         Log.w(TAG, "onNanDown: called in stub - override if interested or disable");
@@ -151,7 +155,7 @@
      * implication is that peers you've been communicating with may no longer
      * recognize you and you need to re-establish your identity. Event will only
      * be delivered if registered using
-     * {@link WifiNanEventListener#LISTEN_IDENTITY_CHANGED}. A dummy (empty
+     * {@link WifiNanEventCallback#FLAG_LISTEN_IDENTITY_CHANGED}. A dummy (empty
      * implementation printing out a warning). Make sure to override if
      * registered.
      */
@@ -162,22 +166,25 @@
     /**
      * {@hide}
      */
-    public IWifiNanEventListener callback = new IWifiNanEventListener.Stub() {
+    public IWifiNanEventCallback callback = new IWifiNanEventCallback.Stub() {
         @Override
         public void onConfigCompleted(ConfigRequest completedConfig) {
             if (VDBG) Log.v(TAG, "onConfigCompleted: configRequest=" + completedConfig);
 
-            Message msg = mHandler.obtainMessage(LISTEN_CONFIG_COMPLETED);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_CONFIG_COMPLETED);
             msg.obj = completedConfig;
             mHandler.sendMessage(msg);
         }
 
         @Override
-        public void onConfigFailed(int reason) {
-            if (VDBG) Log.v(TAG, "onConfigFailed: reason=" + reason);
+        public void onConfigFailed(ConfigRequest failedConfig, int reason) {
+            if (VDBG) {
+                Log.v(TAG, "onConfigFailed: failedConfig=" + failedConfig + ", reason=" + reason);
+            }
 
-            Message msg = mHandler.obtainMessage(LISTEN_CONFIG_FAILED);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_CONFIG_FAILED);
             msg.arg1 = reason;
+            msg.obj = failedConfig;
             mHandler.sendMessage(msg);
         }
 
@@ -185,7 +192,7 @@
         public void onNanDown(int reason) {
             if (VDBG) Log.v(TAG, "onNanDown: reason=" + reason);
 
-            Message msg = mHandler.obtainMessage(LISTEN_NAN_DOWN);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_NAN_DOWN);
             msg.arg1 = reason;
             mHandler.sendMessage(msg);
         }
@@ -194,7 +201,7 @@
         public void onIdentityChanged() {
             if (VDBG) Log.v(TAG, "onIdentityChanged");
 
-            Message msg = mHandler.obtainMessage(LISTEN_IDENTITY_CHANGED);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_IDENTITY_CHANGED);
             mHandler.sendMessage(msg);
         }
     };
diff --git a/wifi/java/android/net/wifi/nan/WifiNanManager.java b/wifi/java/android/net/wifi/nan/WifiNanManager.java
index 877f993..d483bc0 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanManager.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanManager.java
@@ -38,11 +38,11 @@
  */
 public class WifiNanManager {
     private static final String TAG = "WifiNanManager";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     private IBinder mBinder;
-
+    private int mClientId = -1;
     private IWifiNanManager mService;
 
     /**
@@ -59,21 +59,25 @@
      * have explicitly {@link WifiNanManager#disconnect()} need to call this
      * function to re-connect.
      *
-     * @param listener A listener extended from {@link WifiNanEventListener}.
-     * @param events The set of events to be delivered to the {@code listener}.
-     *            OR'd event flags from {@link WifiNanEventListener
-     *            NanEventListener.LISTEN*}.
+     * @param callback A callback extended from {@link WifiNanEventCallback}.
+     * @param events The set of events to be delivered to the {@code callback}.
+     *            OR'd event flags from {@link WifiNanEventCallback
+     *            WifiNanEventCallback.LISTEN*}.
      */
-    public void connect(WifiNanEventListener listener, int events) {
+    public void connect(WifiNanEventCallback callback, int events) {
         try {
             if (VDBG) Log.v(TAG, "connect()");
-            if (listener == null) {
-                throw new IllegalArgumentException("Invalid listener - must not be null");
+            if (callback == null) {
+                throw new IllegalArgumentException("Invalid callback - must not be null");
+            }
+            if (mClientId != -1) {
+                Log.w(TAG, "connect(): mClientId=" + mClientId
+                        + ": seems to calling connect() without disconnecting() first!");
             }
             if (mBinder == null) {
                 mBinder = new Binder();
             }
-            mService.connect(mBinder, listener.callback, events);
+            mClientId = mService.connect(mBinder, callback.callback, events);
         } catch (RemoteException e) {
             Log.w(TAG, "connect RemoteException (FYI - ignoring): " + e);
         }
@@ -86,13 +90,14 @@
      * are cancelled.
      * <p>
      * An application may then re-connect using
-     * {@link WifiNanManager#connect(WifiNanEventListener, int)} .
+     * {@link WifiNanManager#connect(WifiNanEventCallback, int)} .
      */
     public void disconnect() {
         try {
             if (VDBG) Log.v(TAG, "disconnect()");
-            mService.disconnect(mBinder);
+            mService.disconnect(mClientId, mBinder);
             mBinder = null;
+            mClientId = -1;
         } catch (RemoteException e) {
             Log.w(TAG, "disconnect RemoteException (FYI - ignoring): " + e);
         }
@@ -105,8 +110,8 @@
      * multiple applications and configure NAN differently from individual
      * requests.
      * <p>
-     * The {@link WifiNanEventListener#onConfigCompleted(ConfigRequest)} will be
-     * called when configuration is completed (if a listener is registered for
+     * The {@link WifiNanEventCallback#onConfigCompleted(ConfigRequest)} will be
+     * called when configuration is completed (if a callback is registered for
      * this specific event).
      *
      * @param configRequest The requested NAN configuration.
@@ -114,7 +119,7 @@
     public void requestConfig(ConfigRequest configRequest) {
         if (VDBG) Log.v(TAG, "requestConfig(): configRequest=" + configRequest);
         try {
-            mService.requestConfig(configRequest);
+            mService.requestConfig(mClientId, configRequest);
         } catch (RemoteException e) {
             Log.w(TAG, "requestConfig RemoteException (FYI - ignoring): " + e);
         }
@@ -122,25 +127,23 @@
 
     /**
      * Request a NAN publish session. The results of the publish session
-     * operation will result in callbacks to the indicated listener:
-     * {@link WifiNanSessionListener NanSessionListener.on*}.
+     * operation will result in callbacks to the indicated callback:
+     * {@link WifiNanSessionCallback NanSessionCallback.on*}.
      *
-     * @param publishData The {@link PublishData} specifying the contents of the
-     *            publish session.
-     * @param publishSettings The {@link PublishSettings} specifying the
-     *            settings for the publish session.
-     * @param listener The {@link WifiNanSessionListener} derived objects to be used
-     *            for the event callbacks specified by {@code events}.
-     * @param events The list of events to be delivered to the {@code listener}
-     *            object. An OR'd value of {@link WifiNanSessionListener
-     *            NanSessionListener.LISTEN_*}.
+     * @param publishConfig The {@link PublishConfig} specifying the
+     *            configuration of the publish session.
+     * @param callback The {@link WifiNanSessionCallback} derived objects to be
+     *            used for the event callbacks specified by {@code events}.
+     * @param events The list of events to be delivered to the {@code callback}
+     *            object. An OR'd value of {@link WifiNanSessionCallback
+     *            WifiNanSessionCallback.LISTEN_*}.
      * @return The {@link WifiNanPublishSession} which can be used to further
      *         control the publish session.
      */
-    public WifiNanPublishSession publish(PublishData publishData, PublishSettings publishSettings,
-            WifiNanSessionListener listener, int events) {
-        return publishRaw(publishData, publishSettings, listener,
-                events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS);
+    public WifiNanPublishSession publish(PublishConfig publishConfig,
+            WifiNanSessionCallback callback, int events) {
+        return publishRaw(publishConfig, callback,
+                events | WifiNanSessionCallback.LISTEN_HIDDEN_FLAGS);
     }
 
     /**
@@ -148,30 +151,30 @@
      *
      * @hide
      */
-    public WifiNanPublishSession publishRaw(PublishData publishData,
-            PublishSettings publishSettings, WifiNanSessionListener listener, int events) {
-        if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings);
+    public WifiNanPublishSession publishRaw(PublishConfig publishConfig,
+            WifiNanSessionCallback callback, int events) {
+        if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig);
 
-        if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED
-                && publishData.mRxFilterLength != 0) {
-            throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED "
+        if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED
+                && publishConfig.mRxFilterLength != 0) {
+            throw new IllegalArgumentException("Invalid publish config: UNSOLICITED "
                     + "publishes (active) can't have an Rx filter");
         }
-        if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED
-                && publishData.mTxFilterLength != 0) {
-            throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED "
+        if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_SOLICITED
+                && publishConfig.mTxFilterLength != 0) {
+            throw new IllegalArgumentException("Invalid publish config: SOLICITED "
                     + "publishes (passive) can't have a Tx filter");
         }
-        if (listener == null) {
-            throw new IllegalArgumentException("Invalid listener - must not be null");
+        if (callback == null) {
+            throw new IllegalArgumentException("Invalid callback - must not be null");
         }
 
         int sessionId;
 
         try {
-            sessionId = mService.createSession(listener.callback, events);
+            sessionId = mService.createSession(mClientId, callback.callback, events);
             if (DBG) Log.d(TAG, "publish: session created - sessionId=" + sessionId);
-            mService.publish(sessionId, publishData, publishSettings);
+            mService.publish(mClientId, sessionId, publishConfig);
         } catch (RemoteException e) {
             Log.w(TAG, "createSession/publish RemoteException: " + e);
             return null;
@@ -183,48 +186,46 @@
     /**
      * {@hide}
      */
-    public void publish(int sessionId, PublishData publishData, PublishSettings publishSettings) {
-        if (VDBG) Log.v(TAG, "publish(): data='" + publishData + "', settings=" + publishSettings);
+    public void publish(int sessionId, PublishConfig publishConfig) {
+        if (VDBG) Log.v(TAG, "publish(): config=" + publishConfig);
 
-        if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_UNSOLICITED
-                && publishData.mRxFilterLength != 0) {
-            throw new IllegalArgumentException("Invalid publish data & settings: UNSOLICITED "
+        if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_UNSOLICITED
+                && publishConfig.mRxFilterLength != 0) {
+            throw new IllegalArgumentException("Invalid publish config: UNSOLICITED "
                     + "publishes (active) can't have an Rx filter");
         }
-        if (publishSettings.mPublishType == PublishSettings.PUBLISH_TYPE_SOLICITED
-                && publishData.mTxFilterLength != 0) {
-            throw new IllegalArgumentException("Invalid publish data & settings: SOLICITED "
+        if (publishConfig.mPublishType == PublishConfig.PUBLISH_TYPE_SOLICITED
+                && publishConfig.mTxFilterLength != 0) {
+            throw new IllegalArgumentException("Invalid publish config: SOLICITED "
                     + "publishes (passive) can't have a Tx filter");
         }
 
         try {
-            mService.publish(sessionId, publishData, publishSettings);
+            mService.publish(mClientId, sessionId, publishConfig);
         } catch (RemoteException e) {
             Log.w(TAG, "publish RemoteException: " + e);
         }
     }
+
     /**
      * Request a NAN subscribe session. The results of the subscribe session
-     * operation will result in callbacks to the indicated listener:
-     * {@link WifiNanSessionListener NanSessionListener.on*}.
+     * operation will result in callbacks to the indicated callback:
+     * {@link WifiNanSessionCallback WifiNanSessionCallback.on*}.
      *
-     * @param subscribeData The {@link SubscribeData} specifying the contents of
-     *            the subscribe session.
-     * @param subscribeSettings The {@link SubscribeSettings} specifying the
-     *            settings for the subscribe session.
-     * @param listener The {@link WifiNanSessionListener} derived objects to be used
-     *            for the event callbacks specified by {@code events}.
-     * @param events The list of events to be delivered to the {@code listener}
-     *            object. An OR'd value of {@link WifiNanSessionListener
-     *            NanSessionListener.LISTEN_*}.
+     * @param subscribeConfig The {@link SubscribeConfig} specifying the
+     *            configuration of the subscribe session.
+     * @param callback The {@link WifiNanSessionCallback} derived objects to be
+     *            used for the event callbacks specified by {@code events}.
+     * @param events The list of events to be delivered to the {@code callback}
+     *            object. An OR'd value of {@link WifiNanSessionCallback
+     *            WifiNanSessionCallback.LISTEN_*}.
      * @return The {@link WifiNanSubscribeSession} which can be used to further
      *         control the subscribe session.
      */
-    public WifiNanSubscribeSession subscribe(SubscribeData subscribeData,
-            SubscribeSettings subscribeSettings,
-            WifiNanSessionListener listener, int events) {
-        return subscribeRaw(subscribeData, subscribeSettings, listener,
-                events | WifiNanSessionListener.LISTEN_HIDDEN_FLAGS);
+    public WifiNanSubscribeSession subscribe(SubscribeConfig subscribeConfig,
+            WifiNanSessionCallback callback, int events) {
+        return subscribeRaw(subscribeConfig, callback,
+                events | WifiNanSessionCallback.LISTEN_HIDDEN_FLAGS);
     }
 
     /**
@@ -232,29 +233,29 @@
      *
      * @hide
      */
-    public WifiNanSubscribeSession subscribeRaw(SubscribeData subscribeData,
-            SubscribeSettings subscribeSettings, WifiNanSessionListener listener, int events) {
+    public WifiNanSubscribeSession subscribeRaw(SubscribeConfig subscribeConfig,
+            WifiNanSessionCallback callback, int events) {
         if (VDBG) {
-            Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings);
+            Log.v(TAG, "subscribe(): config=" + subscribeConfig);
         }
 
-        if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE
-                && subscribeData.mRxFilterLength != 0) {
+        if (subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE
+                && subscribeConfig.mRxFilterLength != 0) {
             throw new IllegalArgumentException(
-                    "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter");
+                    "Invalid subscribe config: ACTIVE subscribes can't have an Rx filter");
         }
-        if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE
-                && subscribeData.mTxFilterLength != 0) {
+        if (subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE
+                && subscribeConfig.mTxFilterLength != 0) {
             throw new IllegalArgumentException(
-                    "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter");
+                    "Invalid subscribe config: PASSIVE subscribes can't have a Tx filter");
         }
 
         int sessionId;
 
         try {
-            sessionId = mService.createSession(listener.callback, events);
+            sessionId = mService.createSession(mClientId, callback.callback, events);
             if (DBG) Log.d(TAG, "subscribe: session created - sessionId=" + sessionId);
-            mService.subscribe(sessionId, subscribeData, subscribeSettings);
+            mService.subscribe(mClientId, sessionId, subscribeConfig);
         } catch (RemoteException e) {
             Log.w(TAG, "createSession/subscribe RemoteException: " + e);
             return null;
@@ -266,25 +267,24 @@
     /**
      * {@hide}
      */
-    public void subscribe(int sessionId, SubscribeData subscribeData,
-            SubscribeSettings subscribeSettings) {
+    public void subscribe(int sessionId, SubscribeConfig subscribeConfig) {
         if (VDBG) {
-            Log.v(TAG, "subscribe(): data='" + subscribeData + "', settings=" + subscribeSettings);
+            Log.v(TAG, "subscribe(): config=" + subscribeConfig);
         }
 
-        if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_ACTIVE
-                && subscribeData.mRxFilterLength != 0) {
+        if (subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_ACTIVE
+                && subscribeConfig.mRxFilterLength != 0) {
             throw new IllegalArgumentException(
-                    "Invalid subscribe data & settings: ACTIVE subscribes can't have an Rx filter");
+                    "Invalid subscribe config: ACTIVE subscribes can't have an Rx filter");
         }
-        if (subscribeSettings.mSubscribeType == SubscribeSettings.SUBSCRIBE_TYPE_PASSIVE
-                && subscribeData.mTxFilterLength != 0) {
+        if (subscribeConfig.mSubscribeType == SubscribeConfig.SUBSCRIBE_TYPE_PASSIVE
+                && subscribeConfig.mTxFilterLength != 0) {
             throw new IllegalArgumentException(
-                    "Invalid subscribe data & settings: PASSIVE subscribes can't have a Tx filter");
+                    "Invalid subscribe config: PASSIVE subscribes can't have a Tx filter");
         }
 
         try {
-            mService.subscribe(sessionId, subscribeData, subscribeSettings);
+            mService.subscribe(mClientId, sessionId, subscribeConfig);
         } catch (RemoteException e) {
             Log.w(TAG, "subscribe RemoteException: " + e);
         }
@@ -297,7 +297,7 @@
         if (DBG) Log.d(TAG, "Stop NAN session #" + sessionId);
 
         try {
-            mService.stopSession(sessionId);
+            mService.stopSession(mClientId, sessionId);
         } catch (RemoteException e) {
             Log.w(TAG, "stopSession RemoteException (FYI - ignoring): " + e);
         }
@@ -310,7 +310,7 @@
         if (DBG) Log.d(TAG, "Destroy NAN session #" + sessionId);
 
         try {
-            mService.destroySession(sessionId);
+            mService.destroySession(mClientId, sessionId);
         } catch (RemoteException e) {
             Log.w(TAG, "destroySession RemoteException (FYI - ignoring): " + e);
         }
@@ -319,13 +319,14 @@
     /**
      * {@hide}
      */
-    public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength) {
+    public void sendMessage(int sessionId, int peerId, byte[] message, int messageLength,
+            int messageId) {
         try {
             if (VDBG) {
                 Log.v(TAG, "sendMessage(): sessionId=" + sessionId + ", peerId=" + peerId
-                        + ", messageLength=" + messageLength);
+                        + ", messageLength=" + messageLength + ", messageId=" + messageId);
             }
-            mService.sendMessage(sessionId, peerId, message, messageLength);
+            mService.sendMessage(mClientId, sessionId, peerId, message, messageLength, messageId);
         } catch (RemoteException e) {
             Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
         }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
index 81b38f4..eae9c65 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanPublishSession.java
@@ -18,8 +18,8 @@
 
 /**
  * A representation of a NAN publish session. Created when
- * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)}
- * is executed. The object can be used to stop and re-start (re-configure) the
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionListener, int)} is
+ * executed. The object can be used to stop and re-start (re-configure) the
  * publish session.
  *
  * @hide PROPOSED_NAN_API
@@ -34,14 +34,13 @@
 
     /**
      * Restart/re-configure the publish session. Note that the
-     * {@link WifiNanSessionListener} is not replaced - the same listener used at
-     * creation is still used.
+     * {@link WifiNanSessionListener} is not replaced - the same listener used
+     * at creation is still used.
      *
-     * @param publishData The data ({@link PublishData}) to publish.
-     * @param publishSettings The settings ({@link PublishSettings}) of the
+     * @param publishConfig The configuration ({@link PublishConfig}) of the
      *            publish session.
      */
-    public void publish(PublishData publishData, PublishSettings publishSettings) {
-        mManager.publish(mSessionId, publishData, publishSettings);
+    public void publish(PublishConfig publishConfig) {
+        mManager.publish(mSessionId, publishConfig);
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSession.java b/wifi/java/android/net/wifi/nan/WifiNanSession.java
index c6b384e..a903583 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSession.java
@@ -27,7 +27,7 @@
  */
 public class WifiNanSession {
     private static final String TAG = "WifiNanSession";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     /**
@@ -94,17 +94,20 @@
      * Sends a message to the specified destination. Message transmission is
      * part of the current discovery session - i.e. executed subsequent to a
      * publish/subscribe
-     * {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)}
+     * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)}
      * event.
      *
      * @param peerId The peer's ID for the message. Must be a result of an
-     *            {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)}
+     *            {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)}
      *            event.
      * @param message The message to be transmitted.
      * @param messageLength The number of bytes from the {@code message} to be
      *            transmitted.
+     * @param messageId An arbitrary integer used by the caller to identify the
+     *            message. The same integer ID will be returned in the callbacks
+     *            indicated message send success or failure.
      */
-    public void sendMessage(int peerId, byte[] message, int messageLength) {
-        mManager.sendMessage(mSessionId, peerId, message, messageLength);
+    public void sendMessage(int peerId, byte[] message, int messageLength, int messageId) {
+        mManager.sendMessage(mSessionId, peerId, message, messageLength, messageId);
     }
 }
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
similarity index 63%
rename from wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
rename to wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
index c9d08c7..8a5c685 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSessionListener.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSessionCallback.java
@@ -26,86 +26,86 @@
  * Base class for NAN session events callbacks. Should be extended by
  * applications wanting notifications. The callbacks are registered when a
  * publish or subscribe session is created using
- * {@link WifiNanManager#publish(PublishData, PublishSettings, WifiNanSessionListener, int)}
- * or
- * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)}
+ * {@link WifiNanManager#publish(PublishConfig, WifiNanSessionCallback, int)} or
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionCallback, int)}
  * . These are callbacks applying to a specific NAN session. Events
- * corresponding to the NAN link are delivered using {@link WifiNanEventListener}.
+ * corresponding to the NAN link are delivered using
+ * {@link WifiNanEventCallback}.
  * <p>
- * A single listener is registered at session creation - it cannot be replaced.
+ * A single callback is registered at session creation - it cannot be replaced.
  * <p>
  * During registration specify which specific events are desired using a set of
- * {@code NanSessionListener.LISTEN_*} flags OR'd together. Only those events
- * will be delivered to the registered listener. Override those callbacks
- * {@code NanSessionListener.on*} for the registered events.
+ * {@code WifiNanSessionCallback.LISTEN_*} flags OR'd together. Only those
+ * events will be delivered to the registered callback. Override those callbacks
+ * {@code WifiNanSessionCallback.on*} for the registered events.
  *
  * @hide PROPOSED_NAN_API
  */
-public class WifiNanSessionListener {
-    private static final String TAG = "WifiNanSessionListener";
-    private static final boolean DBG = true;
+public class WifiNanSessionCallback {
+    private static final String TAG = "WifiNanSessionCallback";
+    private static final boolean DBG = false;
     private static final boolean VDBG = false; // STOPSHIP if true
 
     /**
      * Publish fail callback event registration flag. Corresponding callback is
-     * {@link WifiNanSessionListener#onPublishFail(int)}.
+     * {@link WifiNanSessionCallback#onPublishFail(int)}.
      *
      * @hide
      */
-    public static final int LISTEN_PUBLISH_FAIL = 0x1 << 0;
+    public static final int FLAG_LISTEN_PUBLISH_FAIL = 0x1 << 0;
 
     /**
      * Publish terminated callback event registration flag. Corresponding
-     * callback is {@link WifiNanSessionListener#onPublishTerminated(int)}.
+     * callback is {@link WifiNanSessionCallback#onPublishTerminated(int)}.
      */
-    public static final int LISTEN_PUBLISH_TERMINATED = 0x1 << 1;
+    public static final int FLAG_LISTEN_PUBLISH_TERMINATED = 0x1 << 1;
 
     /**
      * Subscribe fail callback event registration flag. Corresponding callback
-     * is {@link WifiNanSessionListener#onSubscribeFail(int)}.
+     * is {@link WifiNanSessionCallback#onSubscribeFail(int)}.
      *
      * @hide
      */
-    public static final int LISTEN_SUBSCRIBE_FAIL = 0x1 << 2;
+    public static final int FLAG_LISTEN_SUBSCRIBE_FAIL = 0x1 << 2;
 
     /**
      * Subscribe terminated callback event registration flag. Corresponding
-     * callback is {@link WifiNanSessionListener#onSubscribeTerminated(int)}.
+     * callback is {@link WifiNanSessionCallback#onSubscribeTerminated(int)}.
      */
-    public static final int LISTEN_SUBSCRIBE_TERMINATED = 0x1 << 3;
+    public static final int FLAG_LISTEN_SUBSCRIBE_TERMINATED = 0x1 << 3;
 
     /**
      * Match (discovery: publish or subscribe) callback event registration flag.
      * Corresponding callback is
-     * {@link WifiNanSessionListener#onMatch(int, byte[], int, byte[], int)}.
+     * {@link WifiNanSessionCallback#onMatch(int, byte[], int, byte[], int)}.
      *
      * @hide
      */
-    public static final int LISTEN_MATCH = 0x1 << 4;
+    public static final int FLAG_LISTEN_MATCH = 0x1 << 4;
 
     /**
      * Message sent successfully callback event registration flag. Corresponding
-     * callback is {@link WifiNanSessionListener#onMessageSendSuccess()}.
+     * callback is {@link WifiNanSessionCallback#onMessageSendSuccess()}.
      *
      * @hide
      */
-    public static final int LISTEN_MESSAGE_SEND_SUCCESS = 0x1 << 5;
+    public static final int FLAG_LISTEN_MESSAGE_SEND_SUCCESS = 0x1 << 5;
 
     /**
      * Message sending failure callback event registration flag. Corresponding
-     * callback is {@link WifiNanSessionListener#onMessageSendFail(int)}.
+     * callback is {@link WifiNanSessionCallback#onMessageSendFail(int)}.
      *
      * @hide
      */
-    public static final int LISTEN_MESSAGE_SEND_FAIL = 0x1 << 6;
+    public static final int FLAG_LISTEN_MESSAGE_SEND_FAIL = 0x1 << 6;
 
     /**
      * Message received callback event registration flag. Corresponding callback
-     * is {@link WifiNanSessionListener#onMessageReceived(int, byte[], int)}.
+     * is {@link WifiNanSessionCallback#onMessageReceived(int, byte[], int)}.
      *
      * @hide
      */
-    public static final int LISTEN_MESSAGE_RECEIVED = 0x1 << 7;
+    public static final int FLAG_LISTEN_MESSAGE_RECEIVED = 0x1 << 7;
 
     /**
      * List of hidden events: which are mandatory - i.e. they will be added to
@@ -113,52 +113,52 @@
      *
      * @hide
      */
-    public static final int LISTEN_HIDDEN_FLAGS = LISTEN_PUBLISH_FAIL | LISTEN_SUBSCRIBE_FAIL
-            | LISTEN_MATCH | LISTEN_MESSAGE_SEND_SUCCESS | LISTEN_MESSAGE_SEND_FAIL
-            | LISTEN_MESSAGE_RECEIVED;
+    public static final int LISTEN_HIDDEN_FLAGS = FLAG_LISTEN_PUBLISH_FAIL
+            | FLAG_LISTEN_SUBSCRIBE_FAIL | FLAG_LISTEN_MATCH | FLAG_LISTEN_MESSAGE_SEND_SUCCESS
+            | FLAG_LISTEN_MESSAGE_SEND_FAIL | FLAG_LISTEN_MESSAGE_RECEIVED;
 
     /**
-     * Failure reason flag for {@link WifiNanEventListener} and
-     * {@link WifiNanSessionListener} callbacks. Indicates no resources to execute
-     * the requested operation.
+     * Failure reason flag for {@link WifiNanEventCallback} and
+     * {@link WifiNanSessionCallback} callbacks. Indicates no resources to
+     * execute the requested operation.
      */
     public static final int FAIL_REASON_NO_RESOURCES = 0;
 
     /**
-     * Failure reason flag for {@link WifiNanEventListener} and
-     * {@link WifiNanSessionListener} callbacks. Indicates invalid argument in the
-     * requested operation.
+     * Failure reason flag for {@link WifiNanEventCallback} and
+     * {@link WifiNanSessionCallback} callbacks. Indicates invalid argument in
+     * the requested operation.
      */
     public static final int FAIL_REASON_INVALID_ARGS = 1;
 
     /**
-     * Failure reason flag for {@link WifiNanEventListener} and
-     * {@link WifiNanSessionListener} callbacks. Indicates a message is transmitted
-     * without a match (i.e. a discovery) occurring first.
+     * Failure reason flag for {@link WifiNanEventCallback} and
+     * {@link WifiNanSessionCallback} callbacks. Indicates a message is
+     * transmitted without a match (i.e. a discovery) occurring first.
      */
     public static final int FAIL_REASON_NO_MATCH_SESSION = 2;
 
     /**
-     * Failure reason flag for {@link WifiNanEventListener} and
-     * {@link WifiNanSessionListener} callbacks. Indicates an unspecified error
+     * Failure reason flag for {@link WifiNanEventCallback} and
+     * {@link WifiNanSessionCallback} callbacks. Indicates an unspecified error
      * occurred during the operation.
      */
     public static final int FAIL_REASON_OTHER = 3;
 
     /**
      * Failure reason flag for
-     * {@link WifiNanSessionListener#onPublishTerminated(int)} and
-     * {@link WifiNanSessionListener#onSubscribeTerminated(int)} callbacks.
+     * {@link WifiNanSessionCallback#onPublishTerminated(int)} and
+     * {@link WifiNanSessionCallback#onSubscribeTerminated(int)} callbacks.
      * Indicates that publish or subscribe session is done - i.e. all the
-     * requested operations (per {@link PublishSettings} or
-     * {@link SubscribeSettings}) have been executed.
+     * requested operations (per {@link PublishConfig} or
+     * {@link SubscribeConfig}) have been executed.
      */
     public static final int TERMINATE_REASON_DONE = 0;
 
     /**
      * Failure reason flag for
-     * {@link WifiNanSessionListener#onPublishTerminated(int)} and
-     * {@link WifiNanSessionListener#onSubscribeTerminated(int)} callbacks.
+     * {@link WifiNanSessionCallback#onPublishTerminated(int)} and
+     * {@link WifiNanSessionCallback#onSubscribeTerminated(int)} callbacks.
      * Indicates that publish or subscribe session is terminated due to a
      * failure.
      */
@@ -171,52 +171,53 @@
     private final Handler mHandler;
 
     /**
-     * Constructs a {@link WifiNanSessionListener} using the looper of the current
-     * thread. I.e. all callbacks will be delivered on the current thread.
+     * Constructs a {@link WifiNanSessionCallback} using the looper of the
+     * current thread. I.e. all callbacks will be delivered on the current
+     * thread.
      */
-    public WifiNanSessionListener() {
+    public WifiNanSessionCallback() {
         this(Looper.myLooper());
     }
 
     /**
-     * Constructs a {@link WifiNanSessionListener} using the specified looper. I.e.
-     * all callbacks will delivered on the thread of the specified looper.
+     * Constructs a {@link WifiNanSessionCallback} using the specified looper.
+     * I.e. all callbacks will delivered on the thread of the specified looper.
      *
      * @param looper The looper on which to execute the callbacks.
      */
-    public WifiNanSessionListener(Looper looper) {
+    public WifiNanSessionCallback(Looper looper) {
         if (VDBG) Log.v(TAG, "ctor: looper=" + looper);
         mHandler = new Handler(looper) {
             @Override
             public void handleMessage(Message msg) {
                 if (DBG) Log.d(TAG, "What=" + msg.what + ", msg=" + msg);
                 switch (msg.what) {
-                    case LISTEN_PUBLISH_FAIL:
-                        WifiNanSessionListener.this.onPublishFail(msg.arg1);
+                    case FLAG_LISTEN_PUBLISH_FAIL:
+                        WifiNanSessionCallback.this.onPublishFail(msg.arg1);
                         break;
-                    case LISTEN_PUBLISH_TERMINATED:
-                        WifiNanSessionListener.this.onPublishTerminated(msg.arg1);
+                    case FLAG_LISTEN_PUBLISH_TERMINATED:
+                        WifiNanSessionCallback.this.onPublishTerminated(msg.arg1);
                         break;
-                    case LISTEN_SUBSCRIBE_FAIL:
-                        WifiNanSessionListener.this.onSubscribeFail(msg.arg1);
+                    case FLAG_LISTEN_SUBSCRIBE_FAIL:
+                        WifiNanSessionCallback.this.onSubscribeFail(msg.arg1);
                         break;
-                    case LISTEN_SUBSCRIBE_TERMINATED:
-                        WifiNanSessionListener.this.onSubscribeTerminated(msg.arg1);
+                    case FLAG_LISTEN_SUBSCRIBE_TERMINATED:
+                        WifiNanSessionCallback.this.onSubscribeTerminated(msg.arg1);
                         break;
-                    case LISTEN_MATCH:
-                        WifiNanSessionListener.this.onMatch(
+                    case FLAG_LISTEN_MATCH:
+                        WifiNanSessionCallback.this.onMatch(
                                 msg.getData().getInt(MESSAGE_BUNDLE_KEY_PEER_ID),
                                 msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.arg1,
                                 msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2), msg.arg2);
                         break;
-                    case LISTEN_MESSAGE_SEND_SUCCESS:
-                        WifiNanSessionListener.this.onMessageSendSuccess();
+                    case FLAG_LISTEN_MESSAGE_SEND_SUCCESS:
+                        WifiNanSessionCallback.this.onMessageSendSuccess(msg.arg1);
                         break;
-                    case LISTEN_MESSAGE_SEND_FAIL:
-                        WifiNanSessionListener.this.onMessageSendFail(msg.arg1);
+                    case FLAG_LISTEN_MESSAGE_SEND_FAIL:
+                        WifiNanSessionCallback.this.onMessageSendFail(msg.arg1, msg.arg2);
                         break;
-                    case LISTEN_MESSAGE_RECEIVED:
-                        WifiNanSessionListener.this.onMessageReceived(msg.arg2,
+                    case FLAG_LISTEN_MESSAGE_RECEIVED:
+                        WifiNanSessionCallback.this.onMessageReceived(msg.arg2,
                                 msg.getData().getByteArray(MESSAGE_BUNDLE_KEY_MESSAGE), msg.arg1);
                         break;
                 }
@@ -229,8 +230,8 @@
      * implementation printing out a log message). Override to implement your
      * custom response.
      *
-     * @param reason The failure reason using {@code NanSessionListener.FAIL_*}
-     *            codes.
+     * @param reason The failure reason using
+     *            {@code WifiNanSessionCallback.FAIL_*} codes.
      */
     public void onPublishFail(int reason) {
         if (VDBG) Log.v(TAG, "onPublishFail: called in stub - override if interested");
@@ -238,12 +239,13 @@
 
     /**
      * Called when a publish operation terminates. Event will only be delivered
-     * if registered using {@link WifiNanSessionListener#LISTEN_PUBLISH_TERMINATED}.
-     * A dummy (empty implementation printing out a warning). Make sure to
-     * override if registered.
+     * if registered using
+     * {@link WifiNanSessionCallback#FLAG_LISTEN_PUBLISH_TERMINATED}. A dummy (empty
+     * implementation printing out a warning). Make sure to override if
+     * registered.
      *
      * @param reason The termination reason using
-     *            {@code NanSessionListener.TERMINATE_*} codes.
+     *            {@code WifiNanSessionCallback.TERMINATE_*} codes.
      */
     public void onPublishTerminated(int reason) {
         Log.w(TAG, "onPublishTerminated: called in stub - override if interested or disable");
@@ -254,8 +256,8 @@
      * implementation printing out a log message). Override to implement your
      * custom response.
      *
-     * @param reason The failure reason using {@code NanSessionListener.FAIL_*}
-     *            codes.
+     * @param reason The failure reason using
+     *            {@code WifiNanSessionCallback.FAIL_*} codes.
      */
     public void onSubscribeFail(int reason) {
         if (VDBG) Log.v(TAG, "onSubscribeFail: called in stub - override if interested");
@@ -264,12 +266,12 @@
     /**
      * Called when a subscribe operation terminates. Event will only be
      * delivered if registered using
-     * {@link WifiNanSessionListener#LISTEN_SUBSCRIBE_TERMINATED}. A dummy (empty
-     * implementation printing out a warning). Make sure to override if
+     * {@link WifiNanSessionCallback#FLAG_LISTEN_SUBSCRIBE_TERMINATED}. A dummy
+     * (empty implementation printing out a warning). Make sure to override if
      * registered.
      *
      * @param reason The termination reason using
-     *            {@code NanSessionListener.TERMINATE_*} codes.
+     *            {@code WifiNanSessionCallback.TERMINATE_*} codes.
      */
     public void onSubscribeTerminated(int reason) {
         Log.w(TAG, "onSubscribeTerminated: called in stub - override if interested or disable");
@@ -303,10 +305,10 @@
      * message). Override to implement your custom response.
      * <p>
      * Note that either this callback or
-     * {@link WifiNanSessionListener#onMessageSendFail(int)} will be received -
-     * never both.
+     * {@link WifiNanSessionCallback#onMessageSendFail(int, int)} will be
+     * received - never both.
      */
-    public void onMessageSendSuccess() {
+    public void onMessageSendSuccess(int messageId) {
         if (VDBG) Log.v(TAG, "onMessageSendSuccess: called in stub - override if interested");
     }
 
@@ -319,13 +321,13 @@
      * message). Override to implement your custom response.
      * <p>
      * Note that either this callback or
-     * {@link WifiNanSessionListener#onMessageSendSuccess()} will be received -
-     * never both
+     * {@link WifiNanSessionCallback#onMessageSendSuccess(int)} will be received
+     * - never both
      *
-     * @param reason The failure reason using {@code NanSessionListener.FAIL_*}
-     *            codes.
+     * @param reason The failure reason using
+     *            {@code WifiNanSessionCallback.FAIL_*} codes.
      */
-    public void onMessageSendFail(int reason) {
+    public void onMessageSendFail(int messageId, int reason) {
         if (VDBG) Log.v(TAG, "onMessageSendFail: called in stub - override if interested");
     }
 
@@ -346,12 +348,12 @@
     /**
      * {@hide}
      */
-    public IWifiNanSessionListener callback = new IWifiNanSessionListener.Stub() {
+    public IWifiNanSessionCallback callback = new IWifiNanSessionCallback.Stub() {
         @Override
         public void onPublishFail(int reason) {
             if (VDBG) Log.v(TAG, "onPublishFail: reason=" + reason);
 
-            Message msg = mHandler.obtainMessage(LISTEN_PUBLISH_FAIL);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_PUBLISH_FAIL);
             msg.arg1 = reason;
             mHandler.sendMessage(msg);
         }
@@ -360,7 +362,7 @@
         public void onPublishTerminated(int reason) {
             if (VDBG) Log.v(TAG, "onPublishResponse: reason=" + reason);
 
-            Message msg = mHandler.obtainMessage(LISTEN_PUBLISH_TERMINATED);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_PUBLISH_TERMINATED);
             msg.arg1 = reason;
             mHandler.sendMessage(msg);
         }
@@ -369,7 +371,7 @@
         public void onSubscribeFail(int reason) {
             if (VDBG) Log.v(TAG, "onSubscribeFail: reason=" + reason);
 
-            Message msg = mHandler.obtainMessage(LISTEN_SUBSCRIBE_FAIL);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_SUBSCRIBE_FAIL);
             msg.arg1 = reason;
             mHandler.sendMessage(msg);
         }
@@ -378,7 +380,7 @@
         public void onSubscribeTerminated(int reason) {
             if (VDBG) Log.v(TAG, "onSubscribeTerminated: reason=" + reason);
 
-            Message msg = mHandler.obtainMessage(LISTEN_SUBSCRIBE_TERMINATED);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_SUBSCRIBE_TERMINATED);
             msg.arg1 = reason;
             mHandler.sendMessage(msg);
         }
@@ -393,7 +395,7 @@
             data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, serviceSpecificInfo);
             data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE2, matchFilter);
 
-            Message msg = mHandler.obtainMessage(LISTEN_MATCH);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_MATCH);
             msg.arg1 = serviceSpecificInfoLength;
             msg.arg2 = matchFilterLength;
             msg.setData(data);
@@ -401,19 +403,21 @@
         }
 
         @Override
-        public void onMessageSendSuccess() {
+        public void onMessageSendSuccess(int messageId) {
             if (VDBG) Log.v(TAG, "onMessageSendSuccess");
 
-            Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_SUCCESS);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_MESSAGE_SEND_SUCCESS);
+            msg.arg1 = messageId;
             mHandler.sendMessage(msg);
         }
 
         @Override
-        public void onMessageSendFail(int reason) {
+        public void onMessageSendFail(int messageId, int reason) {
             if (VDBG) Log.v(TAG, "onMessageSendFail: reason=" + reason);
 
-            Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_SEND_FAIL);
-            msg.arg1 = reason;
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_MESSAGE_SEND_FAIL);
+            msg.arg1 = messageId;
+            msg.arg2 = reason;
             mHandler.sendMessage(msg);
         }
 
@@ -427,7 +431,7 @@
             Bundle data = new Bundle();
             data.putByteArray(MESSAGE_BUNDLE_KEY_MESSAGE, message);
 
-            Message msg = mHandler.obtainMessage(LISTEN_MESSAGE_RECEIVED);
+            Message msg = mHandler.obtainMessage(FLAG_LISTEN_MESSAGE_RECEIVED);
             msg.arg1 = messageLength;
             msg.arg2 = peerId;
             msg.setData(data);
diff --git a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
index 7dfdd32..d2f13c8 100644
--- a/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
+++ b/wifi/java/android/net/wifi/nan/WifiNanSubscribeSession.java
@@ -18,7 +18,7 @@
 
 /**
  * A representation of a NAN subscribe session. Created when
- * {@link WifiNanManager#subscribe(SubscribeData, SubscribeSettings, WifiNanSessionListener, int)}
+ * {@link WifiNanManager#subscribe(SubscribeConfig, WifiNanSessionListener, int)}
  * is executed. The object can be used to stop and re-start (re-configure) the
  * subscribe session.
  *
@@ -34,14 +34,13 @@
 
     /**
      * Restart/re-configure the subscribe session. Note that the
-     * {@link WifiNanSessionListener} is not replaced - the same listener used at
-     * creation is still used.
+     * {@link WifiNanSessionListener} is not replaced - the same listener used
+     * at creation is still used.
      *
-     * @param subscribeData The data ({@link SubscribeData}) to subscribe.
-     * @param subscribeSettings The settings ({@link SubscribeSettings}) of the
+     * @param subscribeConfig The configuration ({@link SubscribeConfig}) of the
      *            subscribe session.
      */
-    public void subscribe(SubscribeData subscribeData, SubscribeSettings subscribeSettings) {
-        mManager.subscribe(mSessionId, subscribeData, subscribeSettings);
+    public void subscribe(SubscribeConfig subscribeConfig) {
+        mManager.subscribe(mSessionId, subscribeConfig);
     }
 }
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
deleted file mode 100644
index 50bec33..0000000
--- a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
+++ /dev/null
@@ -1,45 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.ScanResult;
-import android.net.wifi.passpoint.WifiPasspointPolicy;
-import android.net.wifi.passpoint.WifiPasspointCredential;
-import android.os.Messenger;
-
-/**
- * Interface that allows controlling and querying Wifi Passpoint connectivity.
- *
- * {@hide}
- */
-interface IWifiPasspointManager
-{
-    Messenger getMessenger();
-
-    int getPasspointState();
-
-    List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
-
-    List<WifiPasspointCredential> getCredentials();
-
-    boolean addCredential(in WifiPasspointCredential cred);
-
-    boolean updateCredential(in WifiPasspointCredential cred);
-
-    boolean removeCredential(in WifiPasspointCredential cred);
-}
-
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
deleted file mode 100644
index cfd3605..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointCredential;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
deleted file mode 100644
index a100aed..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.WifiEnterpriseConfig;
-import android.os.Parcelable;
-import android.os.Parcel;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-
-
-/**
- * A class representing a Wi-Fi Passpoint credential.
- * @hide
- */
-public class WifiPasspointCredential implements Parcelable {
-
-    private final static String TAG = "PasspointCredential";
-    private final static boolean DBG = true;
-
-    /** Wi-Fi nodes**/
-    private String mWifiSpFqdn;
-
-    /** PerProviderSubscription nodes **/
-    private String mCredentialName;
-
-    /** SubscriptionUpdate nodes **/
-    private String mSubscriptionUpdateInterval;
-    private String mSubscriptionUpdateMethod;
-    private String mSubscriptionUpdateRestriction;
-    private String mSubscriptionUpdateURI;
-    private String mSubscriptionUpdateUsername;
-    private String mSubscriptionUpdatePassword;
-
-    /** HomeSP nodes **/
-    private String mHomeSpFqdn;
-    private String mFriendlyName;
-    private Collection<WifiPasspointDmTree.HomeOIList> mHomeOIList;
-    private Collection<WifiPasspointDmTree.OtherHomePartners> mOtherHomePartnerList;
-
-    /** SubscriptionParameters nodes**/
-    private String mCreationDate;
-    private String mExpirationDate;
-
-    /** Credential nodes **/
-    private String mType;
-    private String mInnerMethod;
-    private String mCertType;
-    private String mCertSha256Fingerprint;
-    private String mUpdateIdentifier;
-    private String mUsername;
-    private String mPasswd;
-    private String mRealm;
-    private String mImsi;
-    private String mMcc;
-    private String mMnc;
-    private String mCaRootCert;
-    private String mClientCert;
-    private boolean mCheckAaaServerCertStatus;
-
-    /** Policy nodes **/
-    private String mPolicyUpdateUri;
-    private String mPolicyUpdateInterval;
-    private String mPolicyUpdateUsername;
-    private String mPolicyUpdatePassword;
-    private String mPolicyUpdateRestriction;
-    private String mPolicyUpdateMethod;
-    private Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> mPreferredRoamingPartnerList;
-    private Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> mMinBackhaulThresholdNetwork;
-    private Collection<WifiPasspointDmTree.SPExclusionList> mSpExclusionList;
-    private Collection<WifiPasspointDmTree.RequiredProtoPortTuple> mRequiredProtoPortTuple;
-    private String mMaxBssLoad;
-
-    /** CrednetialPriority node **/
-    private int mCrednetialPriority;
-
-    /** AAAServerTrustRoot nodes **/
-    private String mAaaCertUrl;
-    private String mAaaSha256Fingerprint;
-
-    /** Others **/
-    private boolean mIsMachineRemediation;
-    private boolean mUserPreferred = false;
-    private String mWifiTreePath;
-    private WifiEnterpriseConfig mEnterpriseConfig;
-
-    /** @hide */
-    public WifiPasspointCredential() {}
-
-    /**
-     * Constructor
-     * @param realm Realm of the passpoint credential
-     * @param fqdn Fully qualified domain name (FQDN) of the credential
-     * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
-     * @see WifiEnterpriseConfig
-     */
-    public WifiPasspointCredential(String realm, String fqdn, WifiEnterpriseConfig config) {
-        mRealm = realm;
-        switch (config.getEapMethod()) {
-            case WifiEnterpriseConfig.Eap.TLS:
-            case WifiEnterpriseConfig.Eap.TTLS:
-                mEnterpriseConfig = new WifiEnterpriseConfig(config);
-                break;
-            default:
-                // ignore
-        }
-    }
-
-    /** @hide */
-    public WifiPasspointCredential(String type,
-            String caroot,
-            String clientcert,
-            String mcc,
-            String mnc,
-            WifiPasspointDmTree.SpFqdn sp,
-            WifiPasspointDmTree.CredentialInfo credinfo) {
-
-        if (credinfo == null) {
-            return;
-        }
-
-        mType = type;
-        mCaRootCert = caroot;
-        mClientCert = clientcert;
-
-        mWifiSpFqdn = sp.nodeName;
-        mUpdateIdentifier = sp.perProviderSubscription.UpdateIdentifier;
-
-        mCredentialName = credinfo.nodeName;
-        mOtherHomePartnerList = credinfo.homeSP.otherHomePartners.values();
-
-        Set set = credinfo.aAAServerTrustRoot.entrySet();
-        Iterator i = set.iterator();
-        if (i.hasNext()) {
-            Map.Entry entry3 = (Map.Entry) i.next();
-            WifiPasspointDmTree.AAAServerTrustRoot aaa = (WifiPasspointDmTree.AAAServerTrustRoot) entry3.getValue();
-            mAaaCertUrl = aaa.CertURL;
-            mAaaSha256Fingerprint = aaa.CertSHA256Fingerprint;
-        }
-
-        mCertType = credinfo.credential.digitalCertificate.CertificateType;
-        mCertSha256Fingerprint = credinfo.credential.digitalCertificate.CertSHA256Fingerprint;
-        mUsername = credinfo.credential.usernamePassword.Username;
-        mPasswd = credinfo.credential.usernamePassword.Password;
-        mIsMachineRemediation = credinfo.credential.usernamePassword.MachineManaged;
-        mInnerMethod = credinfo.credential.usernamePassword.eAPMethod.InnerMethod;
-        mImsi = credinfo.credential.sim.IMSI;
-        mMcc = mcc;
-        mMnc = mnc;
-        mCreationDate = credinfo.credential.CreationDate;
-        mExpirationDate = credinfo.credential.ExpirationDate;
-        mRealm = credinfo.credential.Realm;
-
-        if (credinfo.credentialPriority == null) {
-            mCrednetialPriority = 128;
-        } else {
-            mCrednetialPriority = Integer.parseInt(credinfo.credentialPriority);
-        }
-
-        mHomeSpFqdn = credinfo.homeSP.FQDN;
-
-        mSubscriptionUpdateInterval = credinfo.subscriptionUpdate.UpdateInterval;
-        mSubscriptionUpdateMethod = credinfo.subscriptionUpdate.UpdateMethod;
-        mSubscriptionUpdateRestriction = credinfo.subscriptionUpdate.Restriction;
-        mSubscriptionUpdateURI = credinfo.subscriptionUpdate.URI;
-        mSubscriptionUpdateUsername = credinfo.subscriptionUpdate.usernamePassword.Username;
-        mSubscriptionUpdatePassword = credinfo.subscriptionUpdate.usernamePassword.Password;
-
-        mPolicyUpdateUri = credinfo.policy.policyUpdate.URI;
-        mPolicyUpdateInterval = credinfo.policy.policyUpdate.UpdateInterval;
-        mPolicyUpdateUsername = credinfo.policy.policyUpdate.usernamePassword.Username;
-        mPolicyUpdatePassword = credinfo.policy.policyUpdate.usernamePassword.Password;
-        mPolicyUpdateRestriction = credinfo.policy.policyUpdate.Restriction;
-        mPolicyUpdateMethod = credinfo.policy.policyUpdate.UpdateMethod;
-        mPreferredRoamingPartnerList = credinfo.policy.preferredRoamingPartnerList.values();
-        mMinBackhaulThresholdNetwork = credinfo.policy.minBackhaulThreshold.values();
-        mRequiredProtoPortTuple = credinfo.policy.requiredProtoPortTuple.values();
-        mMaxBssLoad = credinfo.policy.maximumBSSLoadValue;
-        mSpExclusionList = credinfo.policy.sPExclusionList.values();
-
-        mHomeOIList = credinfo.homeSP.homeOIList.values();
-        mFriendlyName = credinfo.homeSP.FriendlyName;
-        mCheckAaaServerCertStatus = credinfo.credential.CheckAAAServerCertStatus;
-    }
-
-    /** @hide */
-    public String getUpdateIdentifier() {
-        return mUpdateIdentifier;
-    }
-
-    /** @hide */
-    public String getUpdateMethod() {
-        return mSubscriptionUpdateMethod;
-    }
-
-    /** @hide */
-    public void setUpdateMethod(String method) {
-        mSubscriptionUpdateMethod = method;
-    }
-
-    /** @hide */
-    public String getWifiSpFqdn() {
-        return mWifiSpFqdn;
-    }
-
-    /** @hide */
-    public String getCredName() {
-        return mCredentialName;
-    }
-
-    /** @hide */
-    public String getType() {
-        return mType;
-    }
-
-    /**
-     * Get enterprise config of this Passpoint credential.
-     * @return Enterprise config
-     * @see WifiEnterpriseConfig
-     */
-    public WifiEnterpriseConfig getEnterpriseConfig() {
-        return new WifiEnterpriseConfig(mEnterpriseConfig);
-    }
-
-    /**
-     * Set enterprise config of this Passpoint credential.
-     * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
-     * @see WifiEnterpriseConfig
-     */
-    public void setEnterpriseConfig(WifiEnterpriseConfig config) {
-        // TODO
-    }
-
-    /** @hide */
-    public String getCertType() {
-        return mCertType;
-    }
-
-    /** @hide */
-    public String getCertSha256Fingerprint() {
-        return mCertSha256Fingerprint;
-    }
-
-    /** @hide */
-    public String getUserName() {
-        return mUsername;
-    }
-
-    /** @hide */
-    public String getPassword() {
-        // TODO: guarded by connectivity internal
-        return mPasswd;
-    }
-
-    /** @hide */
-    public String getImsi() {
-        return mImsi;
-    }
-
-    /** @hide */
-    public String getMcc() {
-        return mMcc;
-    }
-
-    /** @hide */
-    public String getMnc() {
-        return mMnc;
-    }
-
-    /** @hide */
-    public String getCaRootCertPath() {
-        return mCaRootCert;
-    }
-
-    /** @hide */
-    public String getClientCertPath() {
-        return mClientCert;
-    }
-
-    /**
-     * Get the realm of this Passpoint credential.
-     * @return Realm
-     */
-    public String getRealm() {
-        return mRealm;
-    }
-
-    /**
-     * Set the ream of this Passpoint credential.
-     * @param realm Realm
-     */
-    public void setRealm(String realm) {
-        mRealm = realm;
-    }
-
-    /** @hide */
-    public int getPriority() {
-        if (mUserPreferred) {
-            return 0;
-        }
-
-        return mCrednetialPriority;
-    }
-
-    /**
-     * Get the fully qualified domain name (FQDN) of this Passpoint credential.
-     * @return FQDN
-     */
-    public String getHomeSpFqdn() {
-        return mHomeSpFqdn;
-    }
-
-    /**
-     * Set the fully qualified domain name (FQDN) of this Passpoint credential.
-     * @param fqdn FQDN
-     */
-    public void setHomeFqdn(String fqdn) {
-        mHomeSpFqdn = fqdn;
-    }
-
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.OtherHomePartners> getOtherHomePartnerList() {
-        return mOtherHomePartnerList;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdateUsername() {
-        return mSubscriptionUpdateUsername;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdatePassword() {
-        return mSubscriptionUpdatePassword;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateUri() {
-        return mPolicyUpdateUri;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateInterval() {
-        return mPolicyUpdateInterval;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateUsername() {
-        return mPolicyUpdateUsername;
-    }
-
-    /** @hide */
-    public String getPolicyUpdatePassword() {
-        return mPolicyUpdatePassword;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateRestriction() {
-        return mPolicyUpdateRestriction;
-    }
-
-    /** @hide */
-    public String getPolicyUpdateMethod() {
-        return mPolicyUpdateMethod;
-    }
-
-    /** @hide */
-    public String getCreationDate() {
-        return mCreationDate;
-    }
-
-    /** @hide */
-    public String getExpirationDate() {
-        return mExpirationDate;
-    }
-
-    /** @hide */
-    public void setExpirationDate(String expirationdate) {
-        mExpirationDate = expirationdate;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> getPreferredRoamingPartnerList() {
-        return mPreferredRoamingPartnerList;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.HomeOIList> getHomeOiList() {
-        return mHomeOIList;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> getBackhaulThresholdList() {
-        return mMinBackhaulThresholdNetwork;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.RequiredProtoPortTuple> getRequiredProtoPortList() {
-        return mRequiredProtoPortTuple;
-    }
-
-    /** @hide */
-    public Collection<WifiPasspointDmTree.SPExclusionList> getSPExclusionList() {
-        return mSpExclusionList;
-    }
-
-    /** @hide */
-    public boolean getIsMachineRemediation() {
-        return mIsMachineRemediation;
-    }
-
-    /** @hide */
-    public String getAaaCertUrl() {
-        return mAaaCertUrl;
-    }
-
-    /** @hide */
-    public String getAaaSha256Fingerprint() {
-        return mAaaSha256Fingerprint;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdateRestriction() {
-        return mSubscriptionUpdateRestriction;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdateURI() {
-        return mSubscriptionUpdateURI;
-    }
-
-    /** @hide */
-    public String getSubscriptionUpdateInterval() {
-        return mSubscriptionUpdateInterval;
-    }
-
-    /** @hide */
-    public String getFriendlyName() {
-        return mFriendlyName;
-    }
-
-    /** @hide */
-    public String getMaxBssLoad() {
-        return mMaxBssLoad;
-    }
-
-    /** @hide */
-    public boolean getUserPreference() {
-        return mUserPreferred;
-    }
-
-    /** @hide */
-    public boolean getCheckAaaServerCertStatus() {
-        return mCheckAaaServerCertStatus;
-    }
-
-    /** @hide */
-    public void setUserPreference(boolean value) {
-        mUserPreferred = value;
-    }
-
-    @Override
-    /** @hide */
-    public boolean equals(Object obj) {
-        boolean result = false;
-        if (obj instanceof WifiPasspointCredential) {
-            final WifiPasspointCredential other = (WifiPasspointCredential) obj;
-            if (this.mType.equals(other.mType)) {
-                if (this.mType.equals("TTLS")) {
-                    result = this.mUsername.equals(other.mUsername) &&
-                            this.mPasswd.equals(other.mPasswd) &&
-                            this.mRealm.equals(other.mRealm) &&
-                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
-                }
-                if (this.mType.equals("TLS")) {
-                    result = this.mRealm.equals(other.mRealm) &&
-                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn) &&
-                            this.mClientCert.equals(other.mClientCert);
-                }
-                if (this.mType.equals("SIM")) {
-                    result = this.mMcc.equals(other.mMcc) &&
-                            this.mMnc.equals(other.mMnc) &&
-                            this.mImsi.equals(other.mImsi) &&
-                            this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
-                }
-            }
-        }
-        return result;
-    }
-
-    @Override
-    /** @hide */
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        String none = "<none>";
-
-        if (!DBG) {
-            sb.append(none);
-        } else {
-            sb.append(", UpdateIdentifier: ")
-            .append(mUpdateIdentifier == null ? none : mUpdateIdentifier)
-            .append(", SubscriptionUpdateMethod: ")
-            .append(mSubscriptionUpdateMethod == null ? none : mSubscriptionUpdateMethod)
-            .append(", Type: ").append(mType == null ? none : mType)
-            .append(", Username: ").append(mUsername == null ? none : mUsername)
-            .append(", Passwd: ").append(mPasswd == null ? none : mPasswd)
-            .append(", SubDMAccUsername: ")
-            .append(mSubscriptionUpdateUsername == null ? none : mSubscriptionUpdateUsername)
-            .append(", SubDMAccPassword: ")
-            .append(mSubscriptionUpdatePassword == null ? none : mSubscriptionUpdatePassword)
-            .append(", PolDMAccUsername: ")
-            .append(mPolicyUpdateUsername == null ? none : mPolicyUpdateUsername)
-            .append(", PolDMAccPassword: ")
-            .append(mPolicyUpdatePassword == null ? none : mPolicyUpdatePassword)
-            .append(", Imsi: ").append(mImsi == null ? none : mImsi)
-            .append(", Mcc: ").append(mMcc == null ? none : mMcc)
-            .append(", Mnc: ").append(mMnc == null ? none : mMnc)
-            .append(", CaRootCert: ").append(mCaRootCert == null ? none : mCaRootCert)
-            .append(", Realm: ").append(mRealm == null ? none : mRealm)
-            .append(", Priority: ").append(mCrednetialPriority)
-            .append(", Fqdn: ").append(mHomeSpFqdn == null ? none : mHomeSpFqdn)
-            .append(", Otherhomepartners: ")
-            .append(mOtherHomePartnerList == null ? none : mOtherHomePartnerList)
-            .append(", ExpirationDate: ")
-            .append(mExpirationDate == null ? none : mExpirationDate)
-            .append(", MaxBssLoad: ").append(mMaxBssLoad == null ? none : mMaxBssLoad)
-            .append(", SPExclusionList: ").append(mSpExclusionList);
-
-            if (mPreferredRoamingPartnerList != null) {
-                sb.append("PreferredRoamingPartnerList:");
-                for (WifiPasspointDmTree.PreferredRoamingPartnerList prpListItem : mPreferredRoamingPartnerList) {
-                    sb.append("[fqdnmatch:").append(prpListItem.FQDN_Match).
-                            append(", priority:").append(prpListItem.Priority).
-                            append(", country:").append(prpListItem.Country).append("]");
-                }
-            }
-
-            if (mHomeOIList != null) {
-                sb.append("HomeOIList:");
-                for (WifiPasspointDmTree.HomeOIList HomeOIListItem : mHomeOIList) {
-                    sb.append("[HomeOI:").append(HomeOIListItem.HomeOI).
-                            append(", HomeOIRequired:").append(HomeOIListItem.HomeOIRequired).
-                            append("]");
-                }
-            }
-
-            if (mMinBackhaulThresholdNetwork != null) {
-                sb.append("BackHaulThreshold:");
-                for (WifiPasspointDmTree.MinBackhaulThresholdNetwork BhtListItem : mMinBackhaulThresholdNetwork) {
-                    sb.append("[networkType:").append(BhtListItem.NetworkType).
-                            append(", dlBandwidth:").append(BhtListItem.DLBandwidth).
-                            append(", ulBandwidth:").append(BhtListItem.ULBandwidth).
-                            append("]");
-                }
-            }
-
-            if (mRequiredProtoPortTuple != null) {
-                sb.append("WifiMORequiredProtoPortTupleList:");
-                for (WifiPasspointDmTree.RequiredProtoPortTuple RpptListItem : mRequiredProtoPortTuple) {
-                    sb.append("[IPProtocol:").append(RpptListItem.IPProtocol).
-                            append(", PortNumber:").append(RpptListItem.PortNumber).
-                            append("]");
-                }
-            }
-        }
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mWifiSpFqdn);
-        dest.writeString(mCredentialName);
-        dest.writeString(mType);
-        dest.writeInt(mCrednetialPriority);
-        dest.writeString(mHomeSpFqdn);
-        dest.writeString(mRealm);
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public void readFromParcel(Parcel in) {
-        mWifiSpFqdn = in.readString();
-        mCredentialName = in.readString();
-        mType = in.readString();
-        mCrednetialPriority = in.readInt();
-        mHomeSpFqdn = in.readString();
-        mRealm = in.readString();
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final Creator<WifiPasspointCredential> CREATOR =
-            new Creator<WifiPasspointCredential>() {
-                public WifiPasspointCredential createFromParcel(Parcel in) {
-                    WifiPasspointCredential pc = new WifiPasspointCredential();
-                    pc.mWifiSpFqdn = in.readString();
-                    pc.mCredentialName = in.readString();
-                    pc.mType = in.readString();
-                    pc.mCrednetialPriority = in.readInt();
-                    pc.mHomeSpFqdn = in.readString();
-                    pc.mRealm = in.readString();
-                    return pc;
-                }
-
-                public WifiPasspointCredential[] newArray(int size) {
-                    return new WifiPasspointCredential[size];
-                }
-            };
-
-    /** @hide */
-    public int compareTo(WifiPasspointCredential another) {
-
-        //The smaller the higher
-        if (mCrednetialPriority < another.mCrednetialPriority) {
-            return -1;
-        } else if (mCrednetialPriority == another.mCrednetialPriority) {
-            return this.mType.compareTo(another.mType);
-        } else {
-            return 1;
-        }
-    }
-
-    @Override
-    /** @hide */
-    public int hashCode() {
-        int hash = 208;
-        if (mType != null) {
-            hash += mType.hashCode();
-        }
-        if (mRealm != null) {
-            hash += mRealm.hashCode();
-        }
-        if (mHomeSpFqdn != null) {
-            hash += mHomeSpFqdn.hashCode();
-        }
-        if (mUsername != null) {
-            hash += mUsername.hashCode();
-        }
-        if (mPasswd != null) {
-            hash += mPasswd.hashCode();
-        }
-
-        return hash;
-    }
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
deleted file mode 100644
index 6a88b2e..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointDmTree;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
deleted file mode 100644
index 427c84c..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
+++ /dev/null
@@ -1,1375 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcelable;
-import android.os.Parcel;
-import java.util.HashMap;
-
-/**
- * Required Mobile Device Management Tree Structure
- *
- *                   +----------+
- *                   | ./(Root) |
- *                   +----+-----+
- *                        |
- *  +---------+           |         +---------+  +---------+
- *  | DevInfo |-----------+---------|  Wi-Fi  |--|SP FQDN* |
- *  +---------+           |         +---------+  +---------+
- *  +---------+           |                           |
- *  |DevDetail|-----------+                      +-----------------------+
- *  +---------+                                  |PerproviderSubscription|--<X>+
- *                                               +-----------------------+
- *
- * This class contains all nodes start from Wi-Fi
- * @hide
- **/
-public class WifiPasspointDmTree implements Parcelable {
-    private final static String TAG = "WifiTree";
-    public int PpsMoId;//plugfest used only
-    public HashMap<String, SpFqdn> spFqdn = new HashMap<String, SpFqdn>();//Maps.newHashMap();
-
-    public SpFqdn createSpFqdn(String name) {
-        SpFqdn obj = new SpFqdn(name);
-        spFqdn.put(name, obj);
-        return obj;
-    }
-
-    public static class SpFqdn implements Parcelable {
-        public String nodeName;
-        public PerProviderSubscription perProviderSubscription = new PerProviderSubscription();
-
-        public SpFqdn(String name) {
-            nodeName = name;
-        }
-
-        public SpFqdn() {
-        }
-
-        public SpFqdn(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeParcelable(perProviderSubscription, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                perProviderSubscription = in.readParcelable(PerProviderSubscription.class
-                        .getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<SpFqdn> CREATOR = new Parcelable.Creator<SpFqdn>() {
-            public SpFqdn createFromParcel(Parcel in) {
-                return new SpFqdn(in);
-            }
-
-            public SpFqdn[] newArray(int size) {
-                return new SpFqdn[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription
-     **/
-    public static class PerProviderSubscription implements Parcelable {
-        /**
-         * PerProviderSubscription/UpdateIdentifier
-         **/
-        public String UpdateIdentifier;
-        public HashMap<String, CredentialInfo> credentialInfo = new HashMap<String, CredentialInfo>();
-
-        public CredentialInfo createCredentialInfo(String name) {
-            CredentialInfo obj = new CredentialInfo(name);
-            credentialInfo.put(name, obj);
-            return obj;
-        }
-
-        public PerProviderSubscription() {
-        }
-
-        public PerProviderSubscription(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(UpdateIdentifier);
-            out.writeMap(credentialInfo);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                UpdateIdentifier = in.readString();
-                in.readMap(credentialInfo, CredentialInfo.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<PerProviderSubscription> CREATOR = new Parcelable.Creator<PerProviderSubscription>() {
-            public PerProviderSubscription createFromParcel(Parcel in) {
-                return new PerProviderSubscription(in);
-            }
-
-            public PerProviderSubscription[] newArray(int size) {
-                return new PerProviderSubscription[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>
-     * This interior node contains the Home SP information, subscription policy, management and credential information.
-     **/
-    public static class CredentialInfo implements Parcelable {
-        public String nodeName;
-        public Policy policy = new Policy();
-        public String credentialPriority;
-        public HashMap<String, AAAServerTrustRoot> aAAServerTrustRoot = new HashMap<String, AAAServerTrustRoot>();
-        public SubscriptionUpdate subscriptionUpdate = new SubscriptionUpdate();
-        public HomeSP homeSP = new HomeSP();
-        public SubscriptionParameters subscriptionParameters = new SubscriptionParameters();
-        public Credential credential = new Credential();
-        public Extension extension = new Extension();
-
-        public CredentialInfo(String nn) {
-            nodeName = nn;
-        }
-
-        public AAAServerTrustRoot createAAAServerTrustRoot(String name, String url, String fp) {
-            AAAServerTrustRoot obj = new AAAServerTrustRoot(name, url, fp);
-            aAAServerTrustRoot.put(name, obj);
-            return obj;
-        }
-
-        public CredentialInfo() {
-        }
-
-        public CredentialInfo(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeParcelable(policy, flags);
-            out.writeString(credentialPriority);
-            out.writeMap(aAAServerTrustRoot);
-            out.writeParcelable(subscriptionUpdate, flags);
-            out.writeParcelable(homeSP, flags);
-            out.writeParcelable(subscriptionParameters, flags);
-            out.writeParcelable(credential, flags);
-            //out.writeParcelable(extension, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                policy = in.readParcelable(Policy.class.getClassLoader());
-                credentialPriority = in.readString();
-                in.readMap(aAAServerTrustRoot, AAAServerTrustRoot.class.getClassLoader());
-                subscriptionUpdate = in.readParcelable(SubscriptionUpdate.class.getClassLoader());
-                homeSP = in.readParcelable(HomeSP.class.getClassLoader());
-                subscriptionParameters = in.readParcelable(SubscriptionParameters.class
-                        .getClassLoader());
-                credential = in.readParcelable(Credential.class.getClassLoader());
-                //extension = in.readParcelable(Extension.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<CredentialInfo> CREATOR = new Parcelable.Creator<CredentialInfo>() {
-            public CredentialInfo createFromParcel(Parcel in) {
-                return new CredentialInfo(in);
-            }
-
-            public CredentialInfo[] newArray(int size) {
-                return new CredentialInfo[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy
-     **/
-    public static class Policy implements Parcelable {
-        public HashMap<String, PreferredRoamingPartnerList> preferredRoamingPartnerList = new HashMap<String, PreferredRoamingPartnerList>();
-        public HashMap<String, MinBackhaulThresholdNetwork> minBackhaulThreshold = new HashMap<String, MinBackhaulThresholdNetwork>();
-        public PolicyUpdate policyUpdate = new PolicyUpdate();
-        public HashMap<String, SPExclusionList> sPExclusionList = new HashMap<String, SPExclusionList>();
-        public HashMap<String, RequiredProtoPortTuple> requiredProtoPortTuple = new HashMap<String, RequiredProtoPortTuple>();
-        public String maximumBSSLoadValue;
-
-        public PreferredRoamingPartnerList createPreferredRoamingPartnerList(String name,
-                String fqdn, String priority, String country) {
-            PreferredRoamingPartnerList obj = new PreferredRoamingPartnerList(name, fqdn, priority,
-                    country);
-            preferredRoamingPartnerList.put(name, obj);
-            return obj;
-        }
-
-        public MinBackhaulThresholdNetwork createMinBackhaulThreshold(String name, String type,
-                String dl, String ul) {
-            MinBackhaulThresholdNetwork obj = new MinBackhaulThresholdNetwork(name, type, dl, ul);
-            minBackhaulThreshold.put(name, obj);
-            return obj;
-        }
-
-        public SPExclusionList createSPExclusionList(String name, String ssid) {
-            SPExclusionList obj = new SPExclusionList(name, ssid);
-            sPExclusionList.put(name, obj);
-            return obj;
-        }
-
-        public RequiredProtoPortTuple createRequiredProtoPortTuple(String name, String proto,
-                String port) {
-            RequiredProtoPortTuple obj = new RequiredProtoPortTuple(name, proto, port);
-            requiredProtoPortTuple.put(name, obj);
-            return obj;
-        }
-
-        public Policy() {
-        }
-
-        public Policy(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeMap(preferredRoamingPartnerList);
-            out.writeMap(minBackhaulThreshold);
-            out.writeParcelable(policyUpdate, flags);
-            out.writeMap(sPExclusionList);
-            out.writeMap(requiredProtoPortTuple);
-            out.writeString(maximumBSSLoadValue);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                in.readMap(preferredRoamingPartnerList,
-                        PreferredRoamingPartnerList.class.getClassLoader());
-                in.readMap(minBackhaulThreshold, MinBackhaulThresholdNetwork.class.getClassLoader());
-                policyUpdate = in.readParcelable(PolicyUpdate.class.getClassLoader());
-                in.readMap(sPExclusionList, SPExclusionList.class.getClassLoader());
-                in.readMap(requiredProtoPortTuple, RequiredProtoPortTuple.class.getClassLoader());
-                maximumBSSLoadValue = in.readString();
-
-            }
-        }
-
-        public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() {
-            public Policy createFromParcel(Parcel in) {
-                return new Policy(in);
-            }
-
-            public Policy[] newArray(int size) {
-                return new Policy[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>
-     **/
-    public static class PreferredRoamingPartnerList implements Parcelable {
-        public String nodeName;
-        public String FQDN_Match; //maximum 255 + ",includeSubdomains", equals 273
-        public String Priority;
-        public String Country; // maximum 600 octets
-
-        public PreferredRoamingPartnerList(String nn, String f, String p, String c) {
-            nodeName = nn;
-            FQDN_Match = f;
-            Priority = p;
-            Country = c;
-        }
-
-        public PreferredRoamingPartnerList() {
-        }
-
-        public PreferredRoamingPartnerList(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(FQDN_Match);
-            out.writeString(Priority);
-            out.writeString(Country);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                FQDN_Match = in.readString();
-                Priority = in.readString();
-                Country = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<PreferredRoamingPartnerList> CREATOR = new Parcelable.Creator<PreferredRoamingPartnerList>() {
-            public PreferredRoamingPartnerList createFromParcel(Parcel in) {
-                return new PreferredRoamingPartnerList(in);
-            }
-
-            public PreferredRoamingPartnerList[] newArray(int size) {
-                return new PreferredRoamingPartnerList[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/MinBackhaulThreshold
-     **/
-    public static class MinBackhaulThresholdNetwork implements Parcelable {
-        public String nodeName;
-        public String NetworkType;
-        public String DLBandwidth;
-        public String ULBandwidth;
-
-        public MinBackhaulThresholdNetwork(String nn, String nt, String d, String u) {
-            nodeName = nn;
-            NetworkType = nt;
-            DLBandwidth = d;
-            ULBandwidth = u;
-        }
-
-        public MinBackhaulThresholdNetwork() {
-        }
-
-        public MinBackhaulThresholdNetwork(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(NetworkType);
-            out.writeString(DLBandwidth);
-            out.writeString(ULBandwidth);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                NetworkType = in.readString();
-                DLBandwidth = in.readString();
-                ULBandwidth = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<MinBackhaulThresholdNetwork> CREATOR = new Parcelable.Creator<MinBackhaulThresholdNetwork>() {
-            public MinBackhaulThresholdNetwork createFromParcel(Parcel in) {
-                return new MinBackhaulThresholdNetwork(in);
-            }
-
-            public MinBackhaulThresholdNetwork[] newArray(int size) {
-                return new MinBackhaulThresholdNetwork[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/PolicyUpdate
-     **/
-    public static class PolicyUpdate implements Parcelable {
-        public String UpdateInterval;
-        public String UpdateMethod;
-        public String Restriction;
-        public String URI;
-        public UsernamePassword usernamePassword = new UsernamePassword();
-        public String Other;
-        public TrustRoot trustRoot = new TrustRoot();
-
-        public PolicyUpdate() {
-        }
-
-        public PolicyUpdate(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(UpdateInterval);
-            out.writeString(UpdateMethod);
-            out.writeString(Restriction);
-            out.writeString(URI);
-            out.writeParcelable(usernamePassword, flags);
-            out.writeString(Other);
-            out.writeParcelable(trustRoot, flags);
-
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                UpdateInterval = in.readString();
-                UpdateMethod = in.readString();
-                Restriction = in.readString();
-                URI = in.readString();
-                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
-                Other = in.readString();
-                trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<PolicyUpdate> CREATOR = new Parcelable.Creator<PolicyUpdate>() {
-            public PolicyUpdate createFromParcel(Parcel in) {
-                return new PolicyUpdate(in);
-            }
-
-            public PolicyUpdate[] newArray(int size) {
-                return new PolicyUpdate[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/SPExclusionList
-     **/
-    public static class SPExclusionList implements Parcelable {
-        public String nodeName;
-        public String SSID;
-
-        public SPExclusionList(String nn, String s) {
-            nodeName = nn;
-            SSID = s;
-        }
-
-        public SPExclusionList() {
-        }
-
-        public SPExclusionList(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(SSID);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                SSID = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<SPExclusionList> CREATOR = new Parcelable.Creator<SPExclusionList>() {
-            public SPExclusionList createFromParcel(Parcel in) {
-                return new SPExclusionList(in);
-            }
-
-            public SPExclusionList[] newArray(int size) {
-                return new SPExclusionList[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/RequiredProtoPortTuple
-     **/
-    public static class RequiredProtoPortTuple implements Parcelable {
-        public String nodeName;
-        public String IPProtocol;
-        public String PortNumber;
-
-        public RequiredProtoPortTuple() {
-        }
-
-        public RequiredProtoPortTuple(String nn, String protocol, String port) {
-            nodeName = nn;
-            IPProtocol = protocol;
-            PortNumber = port;
-        }
-
-        public RequiredProtoPortTuple(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(IPProtocol);
-            out.writeString(PortNumber);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                IPProtocol = in.readString();
-                PortNumber = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<RequiredProtoPortTuple> CREATOR = new Parcelable.Creator<RequiredProtoPortTuple>() {
-            public RequiredProtoPortTuple createFromParcel(Parcel in) {
-                return new RequiredProtoPortTuple(in);
-            }
-
-            public RequiredProtoPortTuple[] newArray(int size) {
-                return new RequiredProtoPortTuple[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/AAAServerTrustRoot
-     **/
-    public static class AAAServerTrustRoot implements Parcelable {
-        public String nodeName;
-        public String CertURL;
-        public String CertSHA256Fingerprint;
-
-        public AAAServerTrustRoot(String nn, String url, String fp) {
-            nodeName = nn;
-            CertURL = url;
-            CertSHA256Fingerprint = fp;
-        }
-
-        public AAAServerTrustRoot() {
-        }
-
-        public AAAServerTrustRoot(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(CertURL);
-            out.writeString(CertSHA256Fingerprint);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                CertURL = in.readString();
-                CertSHA256Fingerprint = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<AAAServerTrustRoot> CREATOR = new Parcelable.Creator<AAAServerTrustRoot>() {
-            public AAAServerTrustRoot createFromParcel(Parcel in) {
-                return new AAAServerTrustRoot(in);
-            }
-
-            public AAAServerTrustRoot[] newArray(int size) {
-                return new AAAServerTrustRoot[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/SubscriptionUpdate
-     **/
-    public static class SubscriptionUpdate implements Parcelable {
-        public String UpdateInterval;
-        public String UpdateMethod;
-        public String Restriction;
-        public String URI;
-        public UsernamePassword usernamePassword = new UsernamePassword();
-        public String Other;
-        public TrustRoot trustRoot = new TrustRoot();
-
-        public SubscriptionUpdate() {
-        }
-
-        public SubscriptionUpdate(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(UpdateInterval);
-            out.writeString(UpdateMethod);
-            out.writeString(Restriction);
-            out.writeString(URI);
-            out.writeParcelable(usernamePassword, flags);
-            out.writeString(Other);
-            out.writeParcelable(trustRoot, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                UpdateInterval = in.readString();
-                UpdateMethod = in.readString();
-                Restriction = in.readString();
-                URI = in.readString();
-                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
-                Other = in.readString();
-                trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<SubscriptionUpdate> CREATOR = new Parcelable.Creator<SubscriptionUpdate>() {
-            public SubscriptionUpdate createFromParcel(Parcel in) {
-                return new SubscriptionUpdate(in);
-            }
-
-            public SubscriptionUpdate[] newArray(int size) {
-                return new SubscriptionUpdate[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/PolicyUpdate/TrustRoot
-     * PerProviderSubscription/<X+>/SubscriptionUpdate/TrustRoot
-     * PerProviderSubscription/<X+>/AAAServerTrustRoot/<X+>
-     **/
-    public static class TrustRoot implements Parcelable {
-        public String CertURL;
-        public String CertSHA256Fingerprint;
-
-        public TrustRoot() {
-        }
-
-        public TrustRoot(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(CertURL);
-            out.writeString(CertSHA256Fingerprint);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                CertURL = in.readString();
-                CertSHA256Fingerprint = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<TrustRoot> CREATOR = new Parcelable.Creator<TrustRoot>() {
-            public TrustRoot createFromParcel(Parcel in) {
-                return new TrustRoot(in);
-            }
-
-            public TrustRoot[] newArray(int size) {
-                return new TrustRoot[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Policy/PolicyUpdate/UsernamePassword
-     * PerProviderSubscription/<X+>/SubscriptionUpdate/UsernamePassword
-     * PerProviderSubscription/<X+>/Credential/UsernamePassword
-     **/
-    public static class UsernamePassword implements Parcelable {
-        public String Username;
-        public String Password;
-        //following are Credential node used only
-        public boolean MachineManaged;
-        public String SoftTokenApp;
-        public String AbleToShare;
-        public EAPMethod eAPMethod = new EAPMethod();
-
-        public UsernamePassword() {
-        }
-
-        public UsernamePassword(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(Username);
-            out.writeString(Password);
-            out.writeInt(MachineManaged ? 1 : 0);
-            out.writeString(SoftTokenApp);
-            out.writeString(AbleToShare);
-            out.writeParcelable(eAPMethod, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                Username = in.readString();
-                Password = in.readString();
-                MachineManaged = (in.readInt() == 1) ? true : false;
-                SoftTokenApp = in.readString();
-                AbleToShare = in.readString();
-                eAPMethod = in.readParcelable(EAPMethod.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<UsernamePassword> CREATOR = new Parcelable.Creator<UsernamePassword>() {
-            public UsernamePassword createFromParcel(Parcel in) {
-                return new UsernamePassword(in);
-            }
-
-            public UsernamePassword[] newArray(int size) {
-                return new UsernamePassword[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Credential/UsernamePassword/EAPMethod
-     **/
-    public static class EAPMethod implements Parcelable {
-        public String EAPType;
-        public String VendorId;
-        public String VendorType;
-        public String InnerEAPType;
-        public String InnerVendorId;
-        public String InnerVendorType;
-        public String InnerMethod;
-
-        public EAPMethod() {
-        }
-
-        public EAPMethod(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(EAPType);
-            out.writeString(VendorId);
-            out.writeString(VendorType);
-            out.writeString(InnerEAPType);
-            out.writeString(InnerVendorId);
-            out.writeString(InnerVendorType);
-            out.writeString(InnerMethod);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                EAPType = in.readString();
-                VendorId = in.readString();
-                VendorType = in.readString();
-                InnerEAPType = in.readString();
-                InnerVendorId = in.readString();
-                InnerVendorType = in.readString();
-                InnerMethod = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<EAPMethod> CREATOR = new Parcelable.Creator<EAPMethod>() {
-            public EAPMethod createFromParcel(Parcel in) {
-                return new EAPMethod(in);
-            }
-
-            public EAPMethod[] newArray(int size) {
-                return new EAPMethod[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/HomeSP
-     **/
-    public static class HomeSP implements Parcelable {
-        public HashMap<String, NetworkID> networkID = new HashMap<String, NetworkID>();
-        public String FriendlyName;
-        public String IconURL;
-        public String FQDN;
-        public HashMap<String, HomeOIList> homeOIList = new HashMap<String, HomeOIList>();
-        public HashMap<String, OtherHomePartners> otherHomePartners = new HashMap<String, OtherHomePartners>();
-        public String RoamingConsortiumOI;
-
-        public NetworkID createNetworkID(String name, String ssid, String hessid) {
-            NetworkID obj = new NetworkID(name, ssid, hessid);
-            networkID.put(name, obj);
-            return obj;
-        }
-
-        public HomeOIList createHomeOIList(String name, String homeoi, boolean required) {
-            HomeOIList obj = new HomeOIList(name, homeoi, required);
-            homeOIList.put(name, obj);
-            return obj;
-        }
-
-        public OtherHomePartners createOtherHomePartners(String name, String fqdn) {
-            OtherHomePartners obj = new OtherHomePartners(name, fqdn);
-            otherHomePartners.put(name, obj);
-            return obj;
-        }
-
-        public HomeSP() {
-        }
-
-        public HomeSP(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeMap(networkID);
-            out.writeString(FriendlyName);
-            out.writeString(IconURL);
-            out.writeString(FQDN);
-            out.writeMap(homeOIList);
-            out.writeMap(otherHomePartners);
-            out.writeString(RoamingConsortiumOI);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                in.readMap(networkID, NetworkID.class.getClassLoader());
-                FriendlyName = in.readString();
-                IconURL = in.readString();
-                FQDN = in.readString();
-                in.readMap(homeOIList, HomeOIList.class.getClassLoader());
-                in.readMap(otherHomePartners, OtherHomePartners.class.getClassLoader());
-                RoamingConsortiumOI = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<HomeSP> CREATOR = new Parcelable.Creator<HomeSP>() {
-            public HomeSP createFromParcel(Parcel in) {
-                return new HomeSP(in);
-            }
-
-            public HomeSP[] newArray(int size) {
-                return new HomeSP[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/HomeSP/NetworkID
-     **/
-    public static class NetworkID implements Parcelable {
-        public String nodeName;
-        public String SSID;
-        public String HESSID;
-
-        public NetworkID(String nn, String s, String h) {
-            nodeName = nn;
-            SSID = s;
-            HESSID = h;
-        }
-
-        public NetworkID() {
-        }
-
-        public NetworkID(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(SSID);
-            out.writeString(HESSID);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                SSID = in.readString();
-                HESSID = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<NetworkID> CREATOR = new Parcelable.Creator<NetworkID>() {
-            public NetworkID createFromParcel(Parcel in) {
-                return new NetworkID(in);
-            }
-
-            public NetworkID[] newArray(int size) {
-                return new NetworkID[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/HomeSP/HomeOIList
-     **/
-    public static class HomeOIList implements Parcelable {
-        public String nodeName;
-        public String HomeOI;
-        public boolean HomeOIRequired;
-
-        public HomeOIList(String nn, String h, boolean r) {
-            nodeName = nn;
-            HomeOI = h;
-            HomeOIRequired = r;
-        }
-
-        public HomeOIList() {
-        }
-
-        public HomeOIList(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(HomeOI);
-            out.writeInt(HomeOIRequired ? 1 : 0);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                HomeOI = in.readString();
-                HomeOIRequired = (in.readInt() == 1) ? true : false;
-            }
-        }
-
-        public static final Parcelable.Creator<HomeOIList> CREATOR = new Parcelable.Creator<HomeOIList>() {
-            public HomeOIList createFromParcel(Parcel in) {
-                return new HomeOIList(in);
-            }
-
-            public HomeOIList[] newArray(int size) {
-                return new HomeOIList[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/HomeSP/OtherHomePartners
-     **/
-    public static class OtherHomePartners implements Parcelable {
-        public String nodeName;
-        public String FQDN;
-
-        public OtherHomePartners(String nn, String f) {
-            nodeName = nn;
-            FQDN = f;
-        }
-
-        public OtherHomePartners() {
-        }
-
-        public OtherHomePartners(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(nodeName);
-            out.writeString(FQDN);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                nodeName = in.readString();
-                FQDN = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<OtherHomePartners> CREATOR = new Parcelable.Creator<OtherHomePartners>() {
-            public OtherHomePartners createFromParcel(Parcel in) {
-                return new OtherHomePartners(in);
-            }
-
-            public OtherHomePartners[] newArray(int size) {
-                return new OtherHomePartners[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/SubscriptionParameters
-     **/
-    public static class SubscriptionParameters implements Parcelable {
-        public String CreationDate;
-        public String ExpirationDate;
-        public String TypeOfSubscription;
-        public UsageLimits usageLimits = new UsageLimits();
-
-        public SubscriptionParameters() {
-        }
-
-        public SubscriptionParameters(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(CreationDate);
-            out.writeString(ExpirationDate);
-            out.writeString(TypeOfSubscription);
-            out.writeParcelable(usageLimits, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                CreationDate = in.readString();
-                ExpirationDate = in.readString();
-                TypeOfSubscription = in.readString();
-                usageLimits = in.readParcelable(UsageLimits.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<SubscriptionParameters> CREATOR = new Parcelable.Creator<SubscriptionParameters>() {
-            public SubscriptionParameters createFromParcel(Parcel in) {
-                return new SubscriptionParameters(in);
-            }
-
-            public SubscriptionParameters[] newArray(int size) {
-                return new SubscriptionParameters[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/SubscriptionParameters/UsageLimits
-     **/
-    public static class UsageLimits implements Parcelable {
-        public String DataLimit;
-        public String StartDate;
-        public String TimeLimit;
-        public String UsageTimePeriod;
-
-        public UsageLimits() {
-        }
-
-        public UsageLimits(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(DataLimit);
-            out.writeString(StartDate);
-            out.writeString(TimeLimit);
-            out.writeString(UsageTimePeriod);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                DataLimit = in.readString();
-                StartDate = in.readString();
-                TimeLimit = in.readString();
-                UsageTimePeriod = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<UsageLimits> CREATOR = new Parcelable.Creator<UsageLimits>() {
-            public UsageLimits createFromParcel(Parcel in) {
-                return new UsageLimits(in);
-            }
-
-            public UsageLimits[] newArray(int size) {
-                return new UsageLimits[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Credential
-     **/
-    public static class Credential implements Parcelable {
-        public String CreationDate;
-        public String ExpirationDate;
-        public UsernamePassword usernamePassword = new UsernamePassword();
-        public DigitalCertificate digitalCertificate = new DigitalCertificate();
-        public String Realm;
-        public boolean CheckAAAServerCertStatus;
-        public SIM sim = new SIM();
-
-        public Credential() {
-        }
-
-        public Credential(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(CreationDate);
-            out.writeString(ExpirationDate);
-            out.writeParcelable(usernamePassword, flags);
-            out.writeParcelable(digitalCertificate, flags);
-            out.writeString(Realm);
-            out.writeInt(CheckAAAServerCertStatus ? 1 : 0);
-            out.writeParcelable(sim, flags);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                CreationDate = in.readString();
-                ExpirationDate = in.readString();
-                usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
-                digitalCertificate = in.readParcelable(DigitalCertificate.class.getClassLoader());
-                Realm = in.readString();
-                CheckAAAServerCertStatus = (in.readInt() == 1) ? true : false;
-                sim = in.readParcelable(SIM.class.getClassLoader());
-            }
-        }
-
-        public static final Parcelable.Creator<Credential> CREATOR = new Parcelable.Creator<Credential>() {
-            public Credential createFromParcel(Parcel in) {
-                return new Credential(in);
-            }
-
-            public Credential[] newArray(int size) {
-                return new Credential[size];
-            }
-        };
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Credential/DigitalCertificate
-     **/
-    public static class DigitalCertificate implements Parcelable {
-        public String CertificateType;
-        public String CertSHA256Fingerprint;
-
-        public DigitalCertificate() {
-        }
-
-        public DigitalCertificate(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(CertificateType);
-            out.writeString(CertSHA256Fingerprint);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                CertificateType = in.readString();
-                CertSHA256Fingerprint = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<DigitalCertificate> CREATOR = new Parcelable.Creator<DigitalCertificate>() {
-            public DigitalCertificate createFromParcel(Parcel in) {
-                return new DigitalCertificate(in);
-            }
-
-            public DigitalCertificate[] newArray(int size) {
-                return new DigitalCertificate[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Credential/SIM
-     **/
-    public static class SIM implements Parcelable {
-        public String IMSI;
-        public String EAPType;
-
-        public SIM() {
-        }
-
-        public SIM(Parcel in) {
-            readFromParcel(in);
-        }
-
-        public int describeContents() {
-            return 0;
-        }
-
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(IMSI);
-            out.writeString(EAPType);
-        }
-
-        public void readFromParcel(Parcel in) {
-            if (in == null) {
-                //log here
-            } else {
-                IMSI = in.readString();
-                EAPType = in.readString();
-            }
-        }
-
-        public static final Parcelable.Creator<SIM> CREATOR = new Parcelable.Creator<SIM>() {
-            public SIM createFromParcel(Parcel in) {
-                return new SIM(in);
-            }
-
-            public SIM[] newArray(int size) {
-                return new SIM[size];
-            }
-        };
-
-    }
-
-    /**
-     * PerProviderSubscription/<X+>/Extension
-     **/
-    public static class Extension {
-        public String empty;
-    }
-
-    public WifiPasspointDmTree() {
-    }
-
-    public WifiPasspointDmTree(Parcel in) {
-        readFromParcel(in);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeMap(spFqdn);
-    }
-
-    public void readFromParcel(Parcel in) {
-        if (in == null) {
-            //log here
-        } else {
-            in.readMap(spFqdn, SpFqdn.class.getClassLoader());
-        }
-    }
-
-    public static final Parcelable.Creator<WifiPasspointDmTree> CREATOR = new Parcelable.Creator<WifiPasspointDmTree>() {
-        public WifiPasspointDmTree createFromParcel(Parcel in) {
-            return new WifiPasspointDmTree(in);
-        }
-
-        public WifiPasspointDmTree[] newArray(int size) {
-            return new WifiPasspointDmTree[size];
-        }
-    };
-
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
deleted file mode 100644
index 27f23bc..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointInfo;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
deleted file mode 100644
index 33db3f5..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/** @hide */
-public class WifiPasspointInfo implements Parcelable {
-
-    /** TODO doc */
-    public static final int ANQP_CAPABILITY = 1 << 0;
-
-    /** TODO doc */
-    public static final int VENUE_NAME = 1 << 1;
-
-    /** TODO doc */
-    public static final int NETWORK_AUTH_TYPE = 1 << 2;
-
-    /** TODO doc */
-    public static final int ROAMING_CONSORTIUM = 1 << 3;
-
-    /** TODO doc */
-    public static final int IP_ADDR_TYPE_AVAILABILITY = 1 << 4;
-
-    /** TODO doc */
-    public static final int NAI_REALM = 1 << 5;
-
-    /** TODO doc */
-    public static final int CELLULAR_NETWORK = 1 << 6;
-
-    /** TODO doc */
-    public static final int DOMAIN_NAME = 1 << 7;
-
-    /** TODO doc */
-    public static final int HOTSPOT_CAPABILITY = 1 << 8;
-
-    /** TODO doc */
-    public static final int OPERATOR_FRIENDLY_NAME = 1 << 9;
-
-    /** TODO doc */
-    public static final int WAN_METRICS = 1 << 10;
-
-    /** TODO doc */
-    public static final int CONNECTION_CAPABILITY = 1 << 11;
-
-    /** TODO doc */
-    public static final int OSU_PROVIDER = 1 << 12;
-
-    /** TODO doc */
-    public static final int PRESET_CRED_MATCH =
-            ANQP_CAPABILITY |
-                    HOTSPOT_CAPABILITY |
-                    NAI_REALM |
-                    CELLULAR_NETWORK |
-                    DOMAIN_NAME;
-
-    /** TODO doc */
-    public static final int PRESET_ALL =
-            ANQP_CAPABILITY |
-                    VENUE_NAME |
-                    NETWORK_AUTH_TYPE |
-                    ROAMING_CONSORTIUM |
-                    IP_ADDR_TYPE_AVAILABILITY |
-                    NAI_REALM |
-                    CELLULAR_NETWORK |
-                    DOMAIN_NAME |
-                    HOTSPOT_CAPABILITY |
-                    OPERATOR_FRIENDLY_NAME |
-                    WAN_METRICS |
-                    CONNECTION_CAPABILITY |
-                    OSU_PROVIDER;
-
-
-    public static class WanMetrics {
-        public static final int STATUS_RESERVED = 0;
-        public static final int STATUS_UP = 1;
-        public static final int STATUS_DOWN = 2;
-        public static final int STATUS_TEST = 3;
-
-        public int wanInfo;
-        public long downlinkSpeed;
-        public long uplinkSpeed;
-        public int downlinkLoad;
-        public int uplinkLoad;
-        public int lmd;
-
-        public int getLinkStatus() {
-            return wanInfo & 0x3;
-        }
-
-        public boolean getSymmetricLink() {
-            return (wanInfo & (1 << 2)) != 0;
-        }
-
-        public boolean getAtCapacity() {
-            return (wanInfo & (1 << 3)) != 0;
-        }
-
-        @Override
-        public String toString() {
-            return wanInfo + "," + downlinkSpeed + "," + uplinkSpeed + "," +
-                    downlinkLoad + "," + uplinkLoad + "," + lmd;
-        }
-    }
-
-    public static class IpProtoPort {
-        public static final int STATUS_CLOSED = 0;
-        public static final int STATUS_OPEN = 1;
-        public static final int STATUS_UNKNOWN = 2;
-
-        public int proto;
-        public int port;
-        public int status;
-
-        @Override
-        public String toString() {
-            return proto + "," + port + "," + status;
-        }
-    }
-
-    public static class NetworkAuthType {
-        public static final int TYPE_TERMS_AND_CONDITION = 0;
-        public static final int TYPE_ONLINE_ENROLLMENT = 1;
-        public static final int TYPE_HTTP_REDIRECTION = 2;
-        public static final int TYPE_DNS_REDIRECTION = 3;
-
-        public int type;
-        public String redirectUrl;
-
-        @Override
-        public String toString() {
-            return type + "," + redirectUrl;
-        }
-    }
-
-    public static class IpAddressType {
-        public static final int IPV6_NOT_AVAILABLE = 0;
-        public static final int IPV6_AVAILABLE = 1;
-        public static final int IPV6_UNKNOWN = 2;
-
-        public static final int IPV4_NOT_AVAILABLE = 0;
-        public static final int IPV4_PUBLIC = 1;
-        public static final int IPV4_PORT_RESTRICTED = 2;
-        public static final int IPV4_SINGLE_NAT = 3;
-        public static final int IPV4_DOUBLE_NAT = 4;
-        public static final int IPV4_PORT_RESTRICTED_SINGLE_NAT = 5;
-        public static final int IPV4_PORT_RESTRICTED_DOUBLE_NAT = 6;
-        public static final int IPV4_PORT_UNKNOWN = 7;
-
-        private static final int NULL_VALUE = -1;
-
-        public int availability;
-
-        public int getIpv6Availability() {
-            return availability & 0x3;
-        }
-
-        public int getIpv4Availability() {
-            return (availability & 0xFF) >> 2;
-        }
-
-        @Override
-        public String toString() {
-            return getIpv6Availability() + "," + getIpv4Availability();
-        }
-    }
-
-    public static class NaiRealm {
-        public static final int ENCODING_RFC4282 = 0;
-        public static final int ENCODING_UTF8 = 1;
-
-        public int encoding;
-        public String realm;
-
-        @Override
-        public String toString() {
-            return encoding + "," + realm;
-        }
-    }
-
-    public static class CellularNetwork {
-        public String mcc;
-        public String mnc;
-
-        @Override
-        public String toString() {
-            return mcc + "," + mnc;
-        }
-    }
-
-    /** BSSID */
-    public String bssid;
-
-    /** venue name */
-    public String venueName;
-
-    /** list of network authentication types */
-    public List<NetworkAuthType> networkAuthTypeList;
-
-    /** list of roaming consortium OIs */
-    public List<String> roamingConsortiumList;
-
-    /** IP address availability */
-    public IpAddressType ipAddrTypeAvailability;
-
-    /** list of NAI realm */
-    public List<NaiRealm> naiRealmList;
-
-    /** list of 3GPP cellular network */
-    public List<CellularNetwork> cellularNetworkList;
-
-    /** list of fully qualified domain name (FQDN) */
-    public List<String> domainNameList;
-
-    /** HS 2.0 operator friendly name */
-    public String operatorFriendlyName;
-
-    /** HS 2.0 wan metrics */
-    public WanMetrics wanMetrics;
-
-    /** list of HS 2.0 IP proto port */
-    public List<IpProtoPort> connectionCapabilityList;
-
-    /** list of HS 2.0 OSU providers */
-    public List<WifiPasspointOsuProvider> osuProviderList;
-
-    /**
-     * Convert mask to ANQP subtypes, for supplicant command use.
-     *
-     * @param mask The ANQP subtypes mask.
-     * @return String of ANQP subtypes, good for supplicant command use
-     * @hide
-     */
-    public static String toAnqpSubtypes(int mask) {
-        StringBuilder sb = new StringBuilder();
-        if ((mask & ANQP_CAPABILITY) != 0)
-            sb.append("257,");
-        if ((mask & VENUE_NAME) != 0)
-            sb.append("258,");
-        if ((mask & NETWORK_AUTH_TYPE) != 0)
-            sb.append("260,");
-        if ((mask & ROAMING_CONSORTIUM) != 0)
-            sb.append("261,");
-        if ((mask & IP_ADDR_TYPE_AVAILABILITY) != 0)
-            sb.append("262,");
-        if ((mask & NAI_REALM) != 0)
-            sb.append("263,");
-        if ((mask & CELLULAR_NETWORK) != 0)
-            sb.append("264,");
-        if ((mask & DOMAIN_NAME) != 0)
-            sb.append("268,");
-        if ((mask & HOTSPOT_CAPABILITY) != 0)
-            sb.append("hs20:2,");
-        if ((mask & OPERATOR_FRIENDLY_NAME) != 0)
-            sb.append("hs20:3,");
-        if ((mask & WAN_METRICS) != 0)
-            sb.append("hs20:4,");
-        if ((mask & CONNECTION_CAPABILITY) != 0)
-            sb.append("hs20:5,");
-        if ((mask & OSU_PROVIDER) != 0)
-            sb.append("hs20:8,");
-        if (sb.length() > 0)
-            sb.deleteCharAt(sb.length() - 1);
-        return sb.toString();
-    }
-
-    @Override
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-
-        sb.append("BSSID: ").append("(").append(bssid).append(")");
-
-        if (venueName != null)
-            sb.append(" venueName: ").append("(")
-              .append(venueName.replace("\n", "\\n")).append(")");
-
-        if (networkAuthTypeList != null) {
-            sb.append(" networkAuthType: ");
-            for (NetworkAuthType auth : networkAuthTypeList)
-                sb.append("(").append(auth.toString()).append(")");
-        }
-
-        if (roamingConsortiumList != null) {
-            sb.append(" roamingConsortium: ");
-            for (String oi : roamingConsortiumList)
-                sb.append("(").append(oi).append(")");
-        }
-
-        if (ipAddrTypeAvailability != null) {
-            sb.append(" ipAddrTypeAvaibility: ").append("(")
-              .append(ipAddrTypeAvailability.toString()).append(")");
-        }
-
-        if (naiRealmList != null) {
-            sb.append(" naiRealm: ");
-            for (NaiRealm realm : naiRealmList)
-                sb.append("(").append(realm.toString()).append(")");
-        }
-
-        if (cellularNetworkList != null) {
-            sb.append(" cellularNetwork: ");
-            for (CellularNetwork plmn : cellularNetworkList)
-                sb.append("(").append(plmn.toString()).append(")");
-        }
-
-        if (domainNameList != null) {
-            sb.append(" domainName: ");
-            for (String fqdn : domainNameList)
-                sb.append("(").append(fqdn).append(")");
-        }
-
-        if (operatorFriendlyName != null)
-            sb.append(" operatorFriendlyName: ").append("(")
-              .append(operatorFriendlyName).append(")");
-
-        if (wanMetrics != null)
-            sb.append(" wanMetrics: ").append("(")
-              .append(wanMetrics.toString()).append(")");
-
-        if (connectionCapabilityList != null) {
-            sb.append(" connectionCapability: ");
-            for (IpProtoPort ip : connectionCapabilityList)
-                sb.append("(").append(ip.toString()).append(")");
-        }
-
-        if (osuProviderList != null) {
-            sb.append(" osuProviderList: ");
-            for (WifiPasspointOsuProvider osu : osuProviderList)
-                sb.append("(").append(osu.toString()).append(")");
-        }
-
-        return sb.toString();
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(bssid);
-        out.writeString(venueName);
-
-        if (networkAuthTypeList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(networkAuthTypeList.size());
-            for (NetworkAuthType auth : networkAuthTypeList) {
-                out.writeInt(auth.type);
-                out.writeString(auth.redirectUrl);
-            }
-        }
-
-        if (roamingConsortiumList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(roamingConsortiumList.size());
-            for (String oi : roamingConsortiumList)
-                out.writeString(oi);
-        }
-
-        if (ipAddrTypeAvailability == null) {
-            out.writeInt(IpAddressType.NULL_VALUE);
-        } else {
-            out.writeInt(ipAddrTypeAvailability.availability);
-        }
-
-        if (naiRealmList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(naiRealmList.size());
-            for (NaiRealm realm : naiRealmList) {
-                out.writeInt(realm.encoding);
-                out.writeString(realm.realm);
-            }
-        }
-
-        if (cellularNetworkList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(cellularNetworkList.size());
-            for (CellularNetwork plmn : cellularNetworkList) {
-                out.writeString(plmn.mcc);
-                out.writeString(plmn.mnc);
-            }
-        }
-
-
-        if (domainNameList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(domainNameList.size());
-            for (String fqdn : domainNameList)
-                out.writeString(fqdn);
-        }
-
-        out.writeString(operatorFriendlyName);
-
-        if (wanMetrics == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(1);
-            out.writeInt(wanMetrics.wanInfo);
-            out.writeLong(wanMetrics.downlinkSpeed);
-            out.writeLong(wanMetrics.uplinkSpeed);
-            out.writeInt(wanMetrics.downlinkLoad);
-            out.writeInt(wanMetrics.uplinkLoad);
-            out.writeInt(wanMetrics.lmd);
-        }
-
-        if (connectionCapabilityList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(connectionCapabilityList.size());
-            for (IpProtoPort ip : connectionCapabilityList) {
-                out.writeInt(ip.proto);
-                out.writeInt(ip.port);
-                out.writeInt(ip.status);
-            }
-        }
-
-        if (osuProviderList == null) {
-            out.writeInt(0);
-        } else {
-            out.writeInt(osuProviderList.size());
-            for (WifiPasspointOsuProvider osu : osuProviderList)
-                osu.writeToParcel(out, flags);
-        }
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final Parcelable.Creator<WifiPasspointInfo> CREATOR =
-            new Parcelable.Creator<WifiPasspointInfo>() {
-                @Override
-                public WifiPasspointInfo createFromParcel(Parcel in) {
-                    WifiPasspointInfo p = new WifiPasspointInfo();
-                    int n;
-
-                    p.bssid = in.readString();
-                    p.venueName = in.readString();
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.networkAuthTypeList = new ArrayList<NetworkAuthType>();
-                        for (int i = 0; i < n; i++) {
-                            NetworkAuthType auth = new NetworkAuthType();
-                            auth.type = in.readInt();
-                            auth.redirectUrl = in.readString();
-                            p.networkAuthTypeList.add(auth);
-                        }
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.roamingConsortiumList = new ArrayList<String>();
-                        for (int i = 0; i < n; i++)
-                            p.roamingConsortiumList.add(in.readString());
-                    }
-
-                    n = in.readInt();
-                    if (n != IpAddressType.NULL_VALUE) {
-                        p.ipAddrTypeAvailability = new IpAddressType();
-                        p.ipAddrTypeAvailability.availability = n;
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.naiRealmList = new ArrayList<NaiRealm>();
-                        for (int i = 0; i < n; i++) {
-                            NaiRealm realm = new NaiRealm();
-                            realm.encoding = in.readInt();
-                            realm.realm = in.readString();
-                            p.naiRealmList.add(realm);
-                        }
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.cellularNetworkList = new ArrayList<CellularNetwork>();
-                        for (int i = 0; i < n; i++) {
-                            CellularNetwork plmn = new CellularNetwork();
-                            plmn.mcc = in.readString();
-                            plmn.mnc = in.readString();
-                            p.cellularNetworkList.add(plmn);
-                        }
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.domainNameList = new ArrayList<String>();
-                        for (int i = 0; i < n; i++)
-                            p.domainNameList.add(in.readString());
-                    }
-
-                    p.operatorFriendlyName = in.readString();
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.wanMetrics = new WanMetrics();
-                        p.wanMetrics.wanInfo = in.readInt();
-                        p.wanMetrics.downlinkSpeed = in.readLong();
-                        p.wanMetrics.uplinkSpeed = in.readLong();
-                        p.wanMetrics.downlinkLoad = in.readInt();
-                        p.wanMetrics.uplinkLoad = in.readInt();
-                        p.wanMetrics.lmd = in.readInt();
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.connectionCapabilityList = new ArrayList<IpProtoPort>();
-                        for (int i = 0; i < n; i++) {
-                            IpProtoPort ip = new IpProtoPort();
-                            ip.proto = in.readInt();
-                            ip.port = in.readInt();
-                            ip.status = in.readInt();
-                            p.connectionCapabilityList.add(ip);
-                        }
-                    }
-
-                    n = in.readInt();
-                    if (n > 0) {
-                        p.osuProviderList = new ArrayList<WifiPasspointOsuProvider>();
-                        for (int i = 0; i < n; i++) {
-                            WifiPasspointOsuProvider osu = WifiPasspointOsuProvider.CREATOR
-                                    .createFromParcel(in);
-                            p.osuProviderList.add(osu);
-                        }
-                    }
-
-                    return p;
-                }
-
-                @Override
-                public WifiPasspointInfo[] newArray(int size) {
-                    return new WifiPasspointInfo[size];
-                }
-            };
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
deleted file mode 100644
index 0245a3d..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
+++ /dev/null
@@ -1,567 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.content.Context;
-import android.net.wifi.ScanResult;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.Messenger;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-
-import com.android.internal.util.AsyncChannel;
-import com.android.internal.util.Protocol;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Provides APIs for managing Wifi Passpoint credentials.
- * @hide
- */
-public class WifiPasspointManager {
-
-    private static final String TAG = "PasspointManager";
-
-    private static final boolean DBG = true;
-
-    /* Passpoint states values */
-
-    /** Passpoint is in an unknown state. This should only occur in boot time */
-    public static final int PASSPOINT_STATE_UNKNOWN = 0;
-
-    /** Passpoint is disabled. This occurs when wifi is disabled */
-    public static final int PASSPOINT_STATE_DISABLED = 1;
-
-    /** Passpoint is enabled and in discovery state */
-    public static final int PASSPOINT_STATE_DISCOVERY = 2;
-
-    /** Passpoint is enabled and in access state */
-    public static final int PASSPOINT_STATE_ACCESS = 3;
-
-    /** Passpoint is enabled and in provisioning state */
-    public static final int PASSPOINT_STATE_PROVISION = 4;
-
-    /* Passpoint callback error codes */
-
-    /** Indicates that the operation failed due to an internal error */
-    public static final int REASON_ERROR = 0;
-
-    /** Indicates that the operation failed because wifi is disabled */
-    public static final int REASON_WIFI_DISABLED = 1;
-
-    /** Indicates that the operation failed because the framework is busy */
-    public static final int REASON_BUSY = 2;
-
-    /** Indicates that the operation failed because parameter is invalid */
-    public static final int REASON_INVALID_PARAMETER = 3;
-
-    /** Indicates that the operation failed because the server is not trusted */
-    public static final int REASON_NOT_TRUSTED = 4;
-
-    /**
-     * protocol supported for Passpoint
-     */
-    public static final String PROTOCOL_DM = "OMA-DM-ClientInitiated";
-
-    /**
-     * protocol supported for Passpoint
-     */
-    public static final String PROTOCOL_SOAP = "SPP-ClientInitiated";
-
-    /* Passpoint broadcasts */
-
-    /**
-     * Broadcast intent action indicating that the state of Passpoint
-     * connectivity has changed
-     */
-    public static final String PASSPOINT_STATE_CHANGED_ACTION =
-            "android.net.wifi.passpoint.STATE_CHANGE";
-
-    /**
-     * Broadcast intent action indicating that the saved Passpoint credential
-     * list has changed
-     */
-    public static final String PASSPOINT_CRED_CHANGED_ACTION =
-            "android.net.wifi.passpoint.CRED_CHANGE";
-
-    /**
-     * Broadcast intent action indicating that Passpoint online sign up is
-     * avaiable.
-     */
-    public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
-            "android.net.wifi.passpoint.OSU_AVAILABLE";
-
-    /**
-     * Broadcast intent action indicating that user remediation is required
-     */
-    public static final String PASSPOINT_USER_REM_REQ_ACTION =
-            "android.net.wifi.passpoint.USER_REM_REQ";
-
-    /**
-     * Interface for callback invocation when framework channel is lost
-     */
-    public interface ChannelListener {
-        /**
-         * The channel to the framework has been disconnected. Application could
-         * try re-initializing using {@link #initialize}
-         */
-        public void onChannelDisconnected();
-    }
-
-    /**
-     * Interface for callback invocation on an application action
-     */
-    public interface ActionListener {
-        /** The operation succeeded */
-        public void onSuccess();
-
-        /**
-         * The operation failed
-         *
-         * @param reason The reason for failure could be one of
-         *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
-         */
-        public void onFailure(int reason);
-    }
-
-    /**
-     * Interface for callback invocation when doing OSU or user remediation
-     */
-    public interface OsuRemListener {
-        /** The operation succeeded */
-        public void onSuccess();
-
-        /**
-         * The operation failed
-         *
-         * @param reason The reason for failure could be one of
-         *            {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY}
-         */
-        public void onFailure(int reason);
-
-        /**
-         * Browser launch is requried for user interaction. When this callback
-         * is called, app should launch browser / webview to the given URI.
-         *
-         * @param uri URI for browser launch
-         */
-        public void onBrowserLaunch(String uri);
-
-        /**
-         * When this is called, app should dismiss the previously lanched browser.
-         */
-        public void onBrowserDismiss();
-    }
-
-    /**
-     * A channel that connects the application to the wifi passpoint framework.
-     * Most passpoint operations require a Channel as an argument.
-     * An instance of Channel is obtained by doing a call on {@link #initialize}
-     */
-    public static class Channel {
-        private final static int INVALID_LISTENER_KEY = 0;
-
-        private ChannelListener mChannelListener;
-
-        private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>();
-        private HashMap<Integer, Integer> mListenerMapCount = new HashMap<Integer, Integer>();
-        private Object mListenerMapLock = new Object();
-        private int mListenerKey = 0;
-
-        private List<ScanResult> mAnqpRequest = new LinkedList<ScanResult>();
-        private Object mAnqpRequestLock = new Object();
-
-        private AsyncChannel mAsyncChannel;
-        private PasspointHandler mHandler;
-        Context mContext;
-
-        Channel(Context context, Looper looper, ChannelListener l) {
-            mAsyncChannel = new AsyncChannel();
-            mHandler = new PasspointHandler(looper);
-            mChannelListener = l;
-            mContext = context;
-        }
-
-        private int putListener(Object listener) {
-            return putListener(listener, 1);
-        }
-
-        private int putListener(Object listener, int count) {
-            if (listener == null || count <= 0)
-                return INVALID_LISTENER_KEY;
-            int key;
-            synchronized (mListenerMapLock) {
-                do {
-                    key = mListenerKey++;
-                } while (key == INVALID_LISTENER_KEY);
-                mListenerMap.put(key, listener);
-                mListenerMapCount.put(key, count);
-            }
-            return key;
-        }
-
-        private Object peekListener(int key) {
-            Log.d(TAG, "peekListener() key=" + key);
-            if (key == INVALID_LISTENER_KEY)
-                return null;
-            synchronized (mListenerMapLock) {
-                return mListenerMap.get(key);
-            }
-        }
-
-
-        private Object getListener(int key, boolean forceRemove) {
-            Log.d(TAG, "getListener() key=" + key + " force=" + forceRemove);
-            if (key == INVALID_LISTENER_KEY)
-                return null;
-            synchronized (mListenerMapLock) {
-                if (!forceRemove) {
-                    int count = mListenerMapCount.get(key);
-                    Log.d(TAG, "count=" + count);
-                    mListenerMapCount.put(key, --count);
-                    if (count > 0)
-                        return null;
-                }
-                Log.d(TAG, "remove key");
-                mListenerMapCount.remove(key);
-                return mListenerMap.remove(key);
-            }
-        }
-
-        private void anqpRequestStart(ScanResult sr) {
-            Log.d(TAG, "anqpRequestStart sr.bssid=" + sr.BSSID);
-            synchronized (mAnqpRequestLock) {
-                mAnqpRequest.add(sr);
-            }
-        }
-
-        private void anqpRequestFinish(WifiPasspointInfo result) {
-            Log.d(TAG, "anqpRequestFinish pi.bssid=" + result.bssid);
-            synchronized (mAnqpRequestLock) {
-                for (ScanResult sr : mAnqpRequest)
-                    if (sr.BSSID.equals(result.bssid)) {
-                        Log.d(TAG, "find hit " + result.bssid);
-                        /* sr.passpoint = result; */
-                        mAnqpRequest.remove(sr);
-                        Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size());
-                        break;
-                    }
-            }
-        }
-
-        private void anqpRequestFinish(ScanResult sr) {
-            Log.d(TAG, "anqpRequestFinish sr.bssid=" + sr.BSSID);
-            synchronized (mAnqpRequestLock) {
-                for (ScanResult sr1 : mAnqpRequest)
-                    if (sr1.BSSID.equals(sr.BSSID)) {
-                        mAnqpRequest.remove(sr1);
-                        break;
-                    }
-            }
-        }
-
-        class PasspointHandler extends Handler {
-            PasspointHandler(Looper looper) {
-                super(looper);
-            }
-
-            @Override
-            public void handleMessage(Message message) {
-                Object listener = null;
-
-                switch (message.what) {
-                    case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
-                        if (mChannelListener != null) {
-                            mChannelListener.onChannelDisconnected();
-                            mChannelListener = null;
-                        }
-                        break;
-
-                    case REQUEST_ANQP_INFO_SUCCEEDED:
-                        WifiPasspointInfo result = (WifiPasspointInfo) message.obj;
-                        anqpRequestFinish(result);
-                        listener = getListener(message.arg2, false);
-                        if (listener != null) {
-                            ((ActionListener) listener).onSuccess();
-                        }
-                        break;
-
-                    case REQUEST_ANQP_INFO_FAILED:
-                        anqpRequestFinish((ScanResult) message.obj);
-                        listener = getListener(message.arg2, false);
-                        if (listener == null)
-                            getListener(message.arg2, true);
-                        if (listener != null) {
-                            ((ActionListener) listener).onFailure(message.arg1);
-                        }
-                        break;
-
-                    case START_OSU_SUCCEEDED:
-                        listener = getListener(message.arg2, true);
-                        if (listener != null) {
-                            ((OsuRemListener) listener).onSuccess();
-                        }
-                        break;
-
-                    case START_OSU_FAILED:
-                        listener = getListener(message.arg2, true);
-                        if (listener != null) {
-                            ((OsuRemListener) listener).onFailure(message.arg1);
-                        }
-                        break;
-
-                    case START_OSU_BROWSER:
-                        listener = peekListener(message.arg2);
-                        if (listener != null) {
-                            ParcelableString str = (ParcelableString) message.obj;
-                            if (str == null || str.string == null)
-                                ((OsuRemListener) listener).onBrowserDismiss();
-                            else
-                                ((OsuRemListener) listener).onBrowserLaunch(str.string);
-                        }
-                        break;
-
-                    default:
-                        Log.d(TAG, "Ignored " + message);
-                        break;
-                }
-            }
-        }
-
-    }
-
-    public static class ParcelableString implements Parcelable {
-        public String string;
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeString(string);
-        }
-
-        public static final Parcelable.Creator<ParcelableString> CREATOR =
-                new Parcelable.Creator<ParcelableString>() {
-                    @Override
-                    public ParcelableString createFromParcel(Parcel in) {
-                        ParcelableString ret = new ParcelableString();
-                        ret.string = in.readString();
-                        return ret;
-                    }
-                    @Override
-                    public ParcelableString[] newArray(int size) {
-                        return new ParcelableString[size];
-                    }
-        };
-    }
-
-    private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
-
-    public static final int REQUEST_ANQP_INFO                   = BASE + 1;
-    public static final int REQUEST_ANQP_INFO_FAILED            = BASE + 2;
-    public static final int REQUEST_ANQP_INFO_SUCCEEDED         = BASE + 3;
-    public static final int REQUEST_OSU_ICON                    = BASE + 4;
-    public static final int REQUEST_OSU_ICON_FAILED             = BASE + 5;
-    public static final int REQUEST_OSU_ICON_SUCCEEDED          = BASE + 6;
-    public static final int START_OSU                           = BASE + 7;
-    public static final int START_OSU_BROWSER                   = BASE + 8;
-    public static final int START_OSU_FAILED                    = BASE + 9;
-    public static final int START_OSU_SUCCEEDED                 = BASE + 10;
-
-    private Context mContext;
-    IWifiPasspointManager mService;
-
-    /**
-     * TODO: doc
-     * @param context
-     * @param service
-     */
-    public WifiPasspointManager(Context context, IWifiPasspointManager service) {
-        mContext = context;
-        mService = service;
-    }
-
-    /**
-     * Registers the application with the framework. This function must be the
-     * first to be called before any async passpoint operations are performed.
-     *
-     * @param srcContext is the context of the source
-     * @param srcLooper is the Looper on which the callbacks are receivied
-     * @param listener for callback at loss of framework communication. Can be
-     *            null.
-     * @return Channel instance that is necessary for performing any further
-     *         passpoint operations
-     *
-     */
-    public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) {
-        Messenger messenger = getMessenger();
-        if (messenger == null)
-            return null;
-
-        Channel c = new Channel(srcContext, srcLooper, listener);
-        if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger)
-                == AsyncChannel.STATUS_SUCCESSFUL) {
-            return c;
-        } else {
-            return null;
-        }
-    }
-
-    /**
-     * STOPSHIP: temp solution, should use supplicant manager instead, check
-     * with b/13931972
-     */
-    public Messenger getMessenger() {
-        try {
-            return mService.getMessenger();
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    public int getPasspointState() {
-        try {
-            return mService.getPasspointState();
-        } catch (RemoteException e) {
-            return PASSPOINT_STATE_UNKNOWN;
-        }
-    }
-
-    public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask,
-            ActionListener listener) {
-        Log.d(TAG, "requestAnqpInfo start");
-        Log.d(TAG, "requested.size=" + requested.size());
-        checkChannel(c);
-        List<ScanResult> list = new ArrayList<ScanResult>();
-        for (ScanResult sr : requested)
-            if (sr.capabilities.contains("[HS20]")) {
-                list.add(sr);
-                c.anqpRequestStart(sr);
-                Log.d(TAG, "adding " + sr.BSSID);
-            }
-        int count = list.size();
-        Log.d(TAG, "after filter, count=" + count);
-        if (count == 0) {
-            if (DBG)
-                Log.d(TAG, "ANQP info request contains no HS20 APs, skipped");
-            listener.onSuccess();
-            return;
-        }
-        int key = c.putListener(listener, count);
-        for (ScanResult sr : list)
-            c.mAsyncChannel.sendMessage(REQUEST_ANQP_INFO, mask, key, sr);
-        Log.d(TAG, "requestAnqpInfo end");
-    }
-
-    public void requestOsuIcons(Channel c, List<WifiPasspointOsuProvider> requested,
-            int resolution, ActionListener listener) {
-    }
-
-    public List<WifiPasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
-        try {
-            return mService.requestCredentialMatch(requested);
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Get a list of saved Passpoint credentials. Only those credentials owned
-     * by the caller will be returned.
-     *
-     * @return The list of credentials
-     */
-    public List<WifiPasspointCredential> getCredentials() {
-        try {
-            return mService.getCredentials();
-        } catch (RemoteException e) {
-            return null;
-        }
-    }
-
-    /**
-     * Add a new Passpoint credential.
-     *
-     * @param cred The credential to be added
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     */
-    public boolean addCredential(WifiPasspointCredential cred) {
-        try {
-            return mService.addCredential(cred);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Update an existing Passpoint credential. Only system or the owner of this
-     * credential has the permission to do this.
-     *
-     * @param cred The credential to be updated
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     */
-    public boolean updateCredential(WifiPasspointCredential cred) {
-        try {
-            return mService.updateCredential(cred);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    /**
-     * Remove an existing Passpoint credential. Only system or the owner of this
-     * credential has the permission to do this.
-     *
-     * @param cred The credential to be removed
-     * @return {@code true} if the operation succeeds, {@code false} otherwise
-     */
-    public boolean removeCredential(WifiPasspointCredential cred) {
-        try {
-            return mService.removeCredential(cred);
-        } catch (RemoteException e) {
-            return false;
-        }
-    }
-
-    public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {
-        Log.d(TAG, "startOsu start");
-        checkChannel(c);
-        int key = c.putListener(listener);
-        c.mAsyncChannel.sendMessage(START_OSU, 0, key, osu);
-        Log.d(TAG, "startOsu end");
-    }
-
-    public void startRemediation(Channel c, OsuRemListener listener) {
-    }
-
-    public void connect(WifiPasspointPolicy policy) {
-    }
-
-    private static void checkChannel(Channel c) {
-        if (c == null) throw new IllegalArgumentException("Channel needs to be initialized");
-    }
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
deleted file mode 100644
index 088136f..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointOsuProvider;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
deleted file mode 100644
index b54b70c..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/** @hide */
-public class WifiPasspointOsuProvider implements Parcelable {
-
-    /** TODO: doc
-     * @hide
-     */
-    public static final int OSU_METHOD_UNKNOWN = -1;
-
-    /** TODO: doc
-     * @hide
-     */
-    public static final int OSU_METHOD_OMADM = 0;
-
-    /** TODO: doc
-     * @hide
-     */
-    public static final int OSU_METHOD_SOAP = 1;
-
-    /** TODO: doc */
-    public String ssid;
-
-    /** TODO: doc */
-    public String friendlyName;
-
-    /** TODO: doc
-     * @hide
-     */
-    public String serverUri;
-
-    /** TODO: doc
-     * @hide
-     */
-    public int osuMethod = OSU_METHOD_UNKNOWN;
-
-    /** TODO: doc */
-    public int iconWidth;
-
-    /** TODO: doc */
-    public int iconHeight;
-
-    /** TODO: doc */
-    public String iconType;
-
-    /** TODO: doc */
-    public String iconFileName;
-
-    /** TODO: doc */
-    public Object icon; // TODO: should change to image format
-
-    /** TODO: doc */
-    public String osuNai;
-
-    /** TODO: doc */
-    public String osuService;
-
-    /** default constructor @hide */
-    public WifiPasspointOsuProvider() {
-        // TODO
-    }
-
-    /** copy constructor @hide */
-    public WifiPasspointOsuProvider(WifiPasspointOsuProvider source) {
-        // TODO
-    }
-
-    @Override
-    public String toString() {
-        StringBuffer sb = new StringBuffer();
-        sb.append("SSID: ").append("<").append(ssid).append(">");
-        if (friendlyName != null)
-            sb.append(" friendlyName: ").append("<").append(friendlyName).append(">");
-        if (serverUri != null)
-            sb.append(" serverUri: ").append("<").append(serverUri).append(">");
-        sb.append(" osuMethod: ").append("<").append(osuMethod).append(">");
-        if (iconFileName != null) {
-            sb.append(" icon: <").append(iconWidth).append("x")
-                    .append(iconHeight).append(" ")
-                    .append(iconType).append(" ")
-                    .append(iconFileName).append(">");
-        }
-        if (osuNai != null)
-            sb.append(" osuNai: ").append("<").append(osuNai).append(">");
-        if (osuService != null)
-            sb.append(" osuService: ").append("<").append(osuService).append(">");
-        return sb.toString();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(ssid);
-        out.writeString(friendlyName);
-        out.writeString(serverUri);
-        out.writeInt(osuMethod);
-        out.writeInt(iconWidth);
-        out.writeInt(iconHeight);
-        out.writeString(iconType);
-        out.writeString(iconFileName);
-        out.writeString(osuNai);
-        out.writeString(osuService);
-        // TODO: icon image?
-    }
-
-    public static final Parcelable.Creator<WifiPasspointOsuProvider> CREATOR =
-            new Parcelable.Creator<WifiPasspointOsuProvider>() {
-                @Override
-                public WifiPasspointOsuProvider createFromParcel(Parcel in) {
-                    WifiPasspointOsuProvider osu = new WifiPasspointOsuProvider();
-                    osu.ssid = in.readString();
-                    osu.friendlyName = in.readString();
-                    osu.serverUri = in.readString();
-                    osu.osuMethod = in.readInt();
-                    osu.iconWidth = in.readInt();
-                    osu.iconHeight = in.readInt();
-                    osu.iconType = in.readString();
-                    osu.iconFileName = in.readString();
-                    osu.osuNai = in.readString();
-                    osu.osuService = in.readString();
-                    return osu;
-                }
-
-                @Override
-                public WifiPasspointOsuProvider[] newArray(int size) {
-                    return new WifiPasspointOsuProvider[size];
-                }
-            };
-}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
deleted file mode 100644
index 1d61da0..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-parcelable WifiPasspointPolicy;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
deleted file mode 100644
index c08877e..0000000
--- a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.net.wifi.passpoint;
-
-import android.net.wifi.WifiConfiguration;
-import android.os.Parcelable;
-import android.os.Parcel;
-import android.security.Credentials;
-import android.util.Log;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-
-
-/** @hide */
-public class WifiPasspointPolicy implements Parcelable {
-
-    private final static String TAG = "PasspointPolicy";
-
-    /** @hide */
-    public static final int HOME_SP = 0;
-
-    /** @hide */
-    public static final int ROAMING_PARTNER = 1;
-
-    /** @hide */
-    public static final int UNRESTRICTED = 2;
-
-    private String mName;
-    private int mCredentialPriority;
-    private int mRoamingPriority;
-    private String mBssid;
-    private String mSsid;
-    private WifiPasspointCredential mCredential;
-    private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted"
-    private boolean mIsHomeSp;
-
-    private final String INT_PRIVATE_KEY = "private_key";
-    private final String INT_PHASE2 = "phase2";
-    private final String INT_PASSWORD = "password";
-    private final String INT_IDENTITY = "identity";
-    private final String INT_EAP = "eap";
-    private final String INT_CLIENT_CERT = "client_cert";
-    private final String INT_CA_CERT = "ca_cert";
-    private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity";
-    private final String INT_SIM_SLOT = "sim_slot";
-    private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField";
-    private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
-    private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2";
-    private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP";
-
-    /** @hide */
-    public WifiPasspointPolicy(String name, String ssid,
-            String bssid, WifiPasspointCredential pc,
-            int restriction, boolean ishomesp) {
-        mName = name;
-        if (pc != null) {
-            mCredentialPriority = pc.getPriority();
-        }
-        //PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>/Priority
-        mRoamingPriority = 128; //default priority value of 128
-        mSsid = ssid;
-        mCredential = pc;
-        mBssid = bssid;
-        mRestriction = restriction;
-        mIsHomeSp = ishomesp;
-    }
-
-    public String getSsid() {
-        return mSsid;
-    }
-
-    /** @hide */
-    public void setBssid(String bssid) {
-        mBssid = bssid;
-    }
-
-    public String getBssid() {
-        return mBssid;
-    }
-
-    /** @hide */
-    public void setRestriction(int r) {
-        mRestriction = r;
-    }
-
-    /** @hide */
-    public int getRestriction() {
-        return mRestriction;
-    }
-
-    /** @hide */
-    public void setHomeSp(boolean b) {
-        mIsHomeSp = b;
-    }
-
-    /** @hide */
-    public boolean isHomeSp() {
-        return mIsHomeSp;
-    }
-
-    /** @hide */
-    public void setCredential(WifiPasspointCredential newCredential) {
-        mCredential = newCredential;
-    }
-
-    public WifiPasspointCredential getCredential() {
-        // TODO: return a copy
-        return mCredential;
-    }
-
-    /** @hide */
-    public void setCredentialPriority(int priority) {
-        mCredentialPriority = priority;
-    }
-
-    /** @hide */
-    public void setRoamingPriority(int priority) {
-        mRoamingPriority = priority;
-    }
-
-    public int getCredentialPriority() {
-        return mCredentialPriority;
-    }
-
-    public int getRoamingPriority() {
-        return mRoamingPriority;
-    }
-
-    public WifiConfiguration createWifiConfiguration() {
-        WifiConfiguration wfg = new WifiConfiguration();
-        if (mBssid != null) {
-            Log.d(TAG, "create bssid:" + mBssid);
-            wfg.BSSID = mBssid;
-        }
-
-        if (mSsid != null) {
-            Log.d(TAG, "create ssid:" + mSsid);
-            wfg.SSID = mSsid;
-        }
-        //TODO: 1. add pmf configuration
-        //      2. add ocsp configuration
-        //      3. add eap-sim configuration
-        /*Key management*/
-        wfg.status = WifiConfiguration.Status.ENABLED;
-        wfg.allowedKeyManagement.clear();
-        wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
-        wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
-
-        /*Group Ciphers*/
-        wfg.allowedGroupCiphers.clear();
-        wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
-        wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
-
-        /*Protocols*/
-        wfg.allowedProtocols.clear();
-        wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
-        wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
-
-        Class[] enterpriseFieldArray  = WifiConfiguration.class.getClasses();
-        Class<?> enterpriseFieldClass = null;
-
-
-        for(Class<?> myClass : enterpriseFieldArray) {
-            if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) {
-                enterpriseFieldClass = myClass;
-                break;
-            }
-        }
-        Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() );
-
-
-        Field anonymousId = null, caCert = null, clientCert = null,
-              eap = null, identity = null, password = null,
-              phase2 = null, privateKey =  null;
-
-        Field[] fields = WifiConfiguration.class.getFields();
-
-
-        for (Field tempField : fields) {
-            if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) {
-                anonymousId = tempField;
-                Log.d(TAG, "field " + anonymousId.getName() );
-            } else if (tempField.getName().trim().equals(INT_CA_CERT)) {
-                caCert = tempField;
-            } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) {
-                clientCert = tempField;
-                Log.d(TAG, "field " + clientCert.getName() );
-            } else if (tempField.getName().trim().equals(INT_EAP)) {
-                eap = tempField;
-                Log.d(TAG, "field " + eap.getName() );
-            } else if (tempField.getName().trim().equals(INT_IDENTITY)) {
-                identity = tempField;
-                Log.d(TAG, "field " + identity.getName() );
-            } else if (tempField.getName().trim().equals(INT_PASSWORD)) {
-                password = tempField;
-                Log.d(TAG, "field " + password.getName() );
-            } else if (tempField.getName().trim().equals(INT_PHASE2)) {
-                phase2 = tempField;
-                Log.d(TAG, "field " + phase2.getName() );
-
-            } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) {
-                privateKey = tempField;
-            }
-        }
-
-
-        Method setValue = null;
-
-        for(Method m: enterpriseFieldClass.getMethods()) {
-            if(m.getName().trim().equals("setValue")) {
-                Log.d(TAG, "method " + m.getName() );
-                setValue = m;
-                break;
-            }
-        }
-
-        try {
-            // EAP
-            String eapmethod = mCredential.getType();
-            Log.d(TAG, "eapmethod:" + eapmethod);
-            setValue.invoke(eap.get(wfg), eapmethod);
-
-            // Username, password, EAP Phase 2
-            if ("TTLS".equals(eapmethod)) {
-                setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2);
-                setValue.invoke(identity.get(wfg), mCredential.getUserName());
-                setValue.invoke(password.get(wfg), mCredential.getPassword());
-                setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm());
-            }
-
-            // EAP CA Certificate
-            String cacertificate = null;
-            String rootCA = mCredential.getCaRootCertPath();
-            if (rootCA == null){
-                cacertificate = null;
-            } else {
-                cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA;
-            }
-            Log.d(TAG, "cacertificate:" + cacertificate);
-            setValue.invoke(caCert.get(wfg), cacertificate);
-
-            //User certificate
-            if ("TLS".equals(eapmethod)) {
-                String usercertificate = null;
-                String privatekey = null;
-                String clientCertPath = mCredential.getClientCertPath();
-                if (clientCertPath != null){
-                    privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath;
-                    usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath;
-                }
-                Log.d(TAG, "privatekey:" + privatekey);
-                Log.d(TAG, "usercertificate:" + usercertificate);
-                if (privatekey != null && usercertificate != null) {
-                    setValue.invoke(privateKey.get(wfg), privatekey);
-                    setValue.invoke(clientCert.get(wfg), usercertificate);
-                }
-            }
-        } catch (Exception e) {
-            Log.d(TAG, "createWifiConfiguration err:" + e);
-        }
-
-        return wfg;
-    }
-
-    /** {@inheritDoc} @hide */
-    public int compareTo(WifiPasspointPolicy another) {
-        Log.d(TAG, "this:" + this);
-        Log.d(TAG, "another:" + another);
-
-        if (another == null) {
-            return -1;
-        } else if (this.mIsHomeSp == true && another.isHomeSp() == false) {
-            //home sp priority is higher then roaming
-            Log.d(TAG, "compare HomeSP  first, this is HomeSP, another isn't");
-            return -1;
-        } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) {
-            Log.d(TAG, "both HomeSP");
-            //if both home sp, compare credential priority
-            if (this.mCredentialPriority < another.getCredentialPriority()) {
-                Log.d(TAG, "this priority is higher");
-                return -1;
-            } else if (this.mCredentialPriority == another.getCredentialPriority()) {
-                Log.d(TAG, "both priorities equal");
-                //if priority still the same, compare name(ssid)
-                if (this.mName.compareTo(another.mName) != 0) {
-                    Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
-                    return this.mName.compareTo(another.mName);
-                }
-                /**
-                 *if name still the same, compare credential
-                 *the device may has two more credentials(TLS,SIM..etc)
-                 *it can associate to one AP(same ssid). so we should compare by credential
-                 */
-                if (this.mCredential != null && another.mCredential != null) {
-                    if (this.mCredential.compareTo(another.mCredential) != 0) {
-                        Log.d(TAG,
-                                "compare mCredential return:" + this.mName.compareTo(another.mName));
-                        return this.mCredential.compareTo(another.mCredential);
-                    }
-                }
-            } else {
-                return 1;
-            }
-        } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) {
-            Log.d(TAG, "both RoamingSp");
-            //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority)
-            if (this.mRoamingPriority < another.getRoamingPriority()) {
-                Log.d(TAG, "this priority is higher");
-                return -1;
-            } else if (this.mRoamingPriority == another.getRoamingPriority()) {//priority equals, compare name
-                Log.d(TAG, "both priorities equal");
-                //if priority still the same, compare name(ssid)
-                if (this.mName.compareTo(another.mName) != 0) {
-                    Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
-                    return this.mName.compareTo(another.mName);
-                }
-                //if name still the same, compare credential
-                if (this.mCredential != null && another.mCredential != null) {
-                    if (this.mCredential.compareTo(another.mCredential) != 0) {
-                        Log.d(TAG,
-                                "compare mCredential return:"
-                                        + this.mCredential.compareTo(another.mCredential));
-                        return this.mCredential.compareTo(another.mCredential);
-                    }
-                }
-            } else {
-                return 1;
-            }
-        }
-
-        Log.d(TAG, "both policies equal");
-        return 0;
-    }
-
-    @Override
-    /** @hide */
-    public String toString() {
-        return "PasspointPolicy: name=" + mName + " CredentialPriority=" + mCredentialPriority +
-                " mRoamingPriority" + mRoamingPriority +
-                " ssid=" + mSsid + " restriction=" + mRestriction +
-                " ishomesp=" + mIsHomeSp + " Credential=" + mCredential;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        // TODO
-    }
-
-    /** Implement the Parcelable interface {@hide} */
-    public static final Creator<WifiPasspointPolicy> CREATOR =
-            new Creator<WifiPasspointPolicy>() {
-                @Override
-                public WifiPasspointPolicy createFromParcel(Parcel in) {
-                    return null;
-                }
-
-                @Override
-                public WifiPasspointPolicy[] newArray(int size) {
-                    return new WifiPasspointPolicy[size];
-                }
-            };
-}