From e246244e82878bd4d149a875d53cf956e6e50a78 Mon Sep 17 00:00:00 2001 From: Haoyu Bai Date: Thu, 28 Jun 2012 15:26:19 -0700 Subject: [PATCH 001/296] Setup idletimer for network interface. Cherry-picked from commit 8ce570b0f39a5c83a29eabcd641c3152b1d1eade in master. DO NOT MERGE Change-Id: I6101c7ae041b4cc1237ce7a9983753dbdfa301d3 --- .../android/server/ConnectivityService.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6049b0510c..375ba68d42 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1625,6 +1625,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { int prevNetType = info.getType(); mNetTrackers[prevNetType].setTeardownRequested(false); + + // Remove idletimer previously setup in {@code handleConnect} + removeDataActivityTracking(prevNetType); + /* * If the disconnected network is not the active one, then don't report * this as a loss of connectivity. What probably happened is that we're @@ -1905,6 +1909,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleConnect(NetworkInfo info) { final int type = info.getType(); + setupDataActivityTracking(type); + // snapshot isFailover, because sendConnectedBroadcast() resets it boolean isFailover = info.isFailover(); final NetworkStateTracker thisNet = mNetTrackers[type]; @@ -1976,6 +1982,58 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * Setup data activity tracking for the given network interface. + * + * Every {@code setupDataActivityTracking} should be paired with a + * {@link removeDataActivityTracking} for cleanup. + */ + private void setupDataActivityTracking(int type) { + final NetworkStateTracker thisNet = mNetTrackers[type]; + final String iface = thisNet.getLinkProperties().getInterfaceName(); + + final int timeout; + + if (ConnectivityManager.isNetworkTypeMobile(type)) { + timeout = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DATA_ACTIVITY_TIMEOUT_MOBILE, + 0); + // Canonicalize mobile network type + type = ConnectivityManager.TYPE_MOBILE; + } else if (ConnectivityManager.TYPE_WIFI == type) { + timeout = Settings.Secure.getInt(mContext.getContentResolver(), + Settings.Secure.DATA_ACTIVITY_TIMEOUT_WIFI, + 0); + } else { + // do not track any other networks + timeout = 0; + } + + if (timeout > 0 && iface != null) { + try { + mNetd.addIdleTimer(iface, timeout, Integer.toString(type)); + } catch (RemoteException e) { + } + } + } + + /** + * Remove data activity tracking when network disconnects. + */ + private void removeDataActivityTracking(int type) { + final NetworkStateTracker net = mNetTrackers[type]; + final String iface = net.getLinkProperties().getInterfaceName(); + + if (iface != null && (ConnectivityManager.isNetworkTypeMobile(type) || + ConnectivityManager.TYPE_WIFI == type)) { + try { + // the call fails silently if no idletimer setup for this interface + mNetd.removeIdleTimer(iface); + } catch (RemoteException e) { + } + } + } + /** * After a change in the connectivity state of a network. We're mainly * concerned with making sure that the list of DNS servers is set up From adb8bf98d93ce390004fd3da53d815c142679e20 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 20 Aug 2012 11:15:39 -0700 Subject: [PATCH 002/296] Update TCP buffer size when switching network type Import of non-merging change 41612 from AOSP When PDP connects in GSM network, the TCP buffer window size is set to max 8760. If the phone swicthes to UMTS, the TCP buffer size is not updated to UMTS, i.e. GPRS buffer size is still used with limited data transfer spead as a result. This fix makes sure the TCP buffer size is updated when switching network type. Change-Id: Ic44a557677ffe629e83ce1f522a9f058bee6e7b2 --- services/java/com/android/server/ConnectivityService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 375ba68d42..cb6ce4b3b2 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2592,6 +2592,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // @see bug/4455071 handleConnectivityChange(info.getType(), false); break; + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + info = (NetworkInfo) msg.obj; + type = info.getType(); + updateNetworkSettings(mNetTrackers[type]); + break; } } } From 366e0b75b7486a245a8c9e4e284820a4fceb6821 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 4 Aug 2012 15:24:58 -0700 Subject: [PATCH 003/296] Begin moving VPN to NetworkStateTracker pattern. Created base tracker that handles common bookkeeping, and move VPN to become a tracker. VPN status is now reflected in NetworkInfo, and is mapped to LegacyVpnInfo. Legacy VPN now "babysits" any init services it starts, watching for when they stop unexpectedly. Bug: 5756357 Change-Id: Iba7ec79da69469f6bd9a970cc39cf6b885b4c9c4 --- .../android/server/ConnectivityService.java | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb6ce4b3b2..d0db0d2e06 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -115,13 +115,15 @@ import java.util.List; * @hide */ public class ConnectivityService extends IConnectivityManager.Stub { + private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; private static final boolean VDBG = false; - private static final String TAG = "ConnectivityService"; private static final boolean LOGD_RULES = false; + // TODO: create better separation between radio types and network types + // how long to wait before switching back to a radio's default network private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000; // system property that can override the above value @@ -136,6 +138,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean mTetheringConfigValid = false; private Vpn mVpn; + private VpnCallback mVpnCallback = new VpnCallback(); /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ private Object mRulesLock = new Object(); @@ -328,7 +331,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { this(context, netd, statsService, policyManager, null); } - public ConnectivityService(Context context, INetworkManagementService netd, + public ConnectivityService(Context context, INetworkManagementService netManager, INetworkStatsService statsService, INetworkPolicyManager policyManager, NetworkFactory netFactory) { if (DBG) log("ConnectivityService starting up"); @@ -366,7 +369,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mContext = checkNotNull(context, "missing Context"); - mNetd = checkNotNull(netd, "missing INetworkManagementService"); + mNetd = checkNotNull(netManager, "missing INetworkManagementService"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); try { @@ -506,11 +509,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { mTethering.getTetherableBluetoothRegexs().length != 0) && mTethering.getUpstreamIfaceTypes().length != 0); - mVpn = new Vpn(mContext, new VpnCallback()); + mVpn = new Vpn(mContext, mVpnCallback, mNetd); + mVpn.startMonitoring(mContext, mTrackerHandler); try { mNetd.registerObserver(mTethering); - mNetd.registerObserver(mVpn); mNetd.registerObserver(mDataActivityObserver); } catch (RemoteException e) { loge("Error registering observer :" + e); @@ -2238,9 +2241,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ public void updateNetworkSettings(NetworkStateTracker nt) { String key = nt.getTcpBufferSizesPropName(); - String bufferSizes = SystemProperties.get(key); + String bufferSizes = key == null ? null : SystemProperties.get(key); - if (bufferSizes.length() == 0) { + if (TextUtils.isEmpty(bufferSizes)) { if (VDBG) log(key + " not found in system properties. Using defaults"); // Setting to default values so we won't be stuck to previous values @@ -3153,10 +3156,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { * be done whenever a better abstraction is developed. */ public class VpnCallback { - private VpnCallback() { } + public void onStateChanged(NetworkInfo info) { + // TODO: if connected, release delayed broadcast + // TODO: if disconnected, consider kicking off reconnect + } + public void override(List dnsServers, List searchDomains) { if (dnsServers == null) { restore(); From 64d8b3be3a88a9b72e8c933abedc1d6281445b13 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 24 Aug 2012 11:17:25 -0700 Subject: [PATCH 004/296] Migrate legacy VPN arguments to system_server. Generate the racoon and mtpd daemon arguments in system_server, instead of accepting them from Settings. Bug: 5756357 Change-Id: I42c1a644f6add477fe4222342640d7db15982cb8 --- .../android/net/IConnectivityManager.aidl | 3 ++- .../android/server/ConnectivityService.java | 22 ++++++++++++++----- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 92aeff2747..dea25dd9ca 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -26,6 +26,7 @@ import android.os.ParcelFileDescriptor; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; +import com.android.internal.net.VpnProfile; /** * Interface that answers queries about, and allows changing, the @@ -118,7 +119,7 @@ interface IConnectivityManager ParcelFileDescriptor establishVpn(in VpnConfig config); - void startLegacyVpn(in VpnConfig config, in String[] racoon, in String[] mtpd); + void startLegacyVpn(in VpnProfile profile); LegacyVpnInfo getLegacyVpnInfo(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index d0db0d2e06..3c2ab163ac 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -31,6 +31,8 @@ import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.bluetooth.BluetoothTetheringDataTracker; import android.content.ContentResolver; import android.content.Context; @@ -78,6 +80,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; +import android.security.KeyStore; import android.text.TextUtils; import android.util.EventLog; import android.util.Slog; @@ -85,8 +88,10 @@ import android.util.SparseIntArray; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; +import com.android.internal.net.VpnProfile; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.util.Preconditions; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; @@ -137,6 +142,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private Tethering mTethering; private boolean mTetheringConfigValid = false; + private final KeyStore mKeyStore; + private Vpn mVpn; private VpnCallback mVpnCallback = new VpnCallback(); @@ -371,6 +378,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mContext = checkNotNull(context, "missing Context"); mNetd = checkNotNull(netManager, "missing INetworkManagementService"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); + mKeyStore = KeyStore.getInstance(); try { mPolicyManager.registerListener(mPolicyListener); @@ -3124,14 +3132,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { } /** - * Start legacy VPN and return an intent to VpnDialogs. This method is - * used by VpnSettings and not available in ConnectivityManager. - * Permissions are checked in Vpn class. - * @hide + * Start legacy VPN, controlling native daemons as needed. Creates a + * secondary thread to perform connection work, returning quickly. */ @Override - public void startLegacyVpn(VpnConfig config, String[] racoon, String[] mtpd) { - mVpn.startLegacyVpn(config, racoon, mtpd); + public void startLegacyVpn(VpnProfile profile) { + final LinkProperties egress = getActiveLinkProperties(); + if (egress == null) { + throw new IllegalStateException("Missing active network connection"); + } + mVpn.startLegacyVpn(profile, mKeyStore, egress); } /** From ebcc7978c14e136375e3b499d38b6f8a41201af0 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sat, 25 Aug 2012 00:05:46 -0700 Subject: [PATCH 005/296] Always-on VPN. Adds support for always-on VPN profiles, also called "lockdown." When enabled, LockdownVpnTracker manages the netd firewall to prevent unencrypted traffic from leaving the device. It creates narrow rules to only allow traffic to the selected VPN server. When an egress network becomes available, LockdownVpnTracker will try bringing up the VPN connection, and will reconnect if disconnected. ConnectivityService augments any NetworkInfo based on the lockdown VPN status to help apps wait until the VPN is connected. This feature requires that VPN profiles use an IP address for both VPN server and DNS. It also blocks non-default APN access when enabled. Waits for USER_PRESENT after boot to check KeyStore status. Bug: 5756357 Change-Id: If615f206b1634000d78a8350a17e88bfcac8e0d0 --- .../java/android/net/ConnectivityManager.java | 9 ++ .../android/net/IConnectivityManager.aidl | 2 + .../android/server/ConnectivityService.java | 131 +++++++++++++++++- 3 files changed, 135 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index d30ef04628..60bf4d6869 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -912,4 +912,13 @@ public class ConnectivityManager { return false; } } + + /** {@hide} */ + public boolean updateLockdownVpn() { + try { + return mService.updateLockdownVpn(); + } catch (RemoteException e) { + return false; + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index dea25dd9ca..3614045f42 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -122,4 +122,6 @@ interface IConnectivityManager void startLegacyVpn(in VpnProfile profile); LegacyVpnInfo getLegacyVpnInfo(); + + boolean updateLockdownVpn(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3c2ab163ac..776a1a48e1 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -16,6 +16,7 @@ package com.android.server; +import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; @@ -31,13 +32,13 @@ import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; -import android.app.NotificationManager; -import android.app.PendingIntent; import android.bluetooth.BluetoothTetheringDataTracker; +import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; +import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; @@ -80,6 +81,7 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Settings; +import android.security.Credentials; import android.security.KeyStore; import android.text.TextUtils; import android.util.EventLog; @@ -91,11 +93,11 @@ import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; -import com.android.internal.util.Preconditions; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; +import com.android.server.net.LockdownVpnTracker; import com.google.android.collect.Lists; import com.google.android.collect.Sets; @@ -142,11 +144,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { private Tethering mTethering; private boolean mTetheringConfigValid = false; - private final KeyStore mKeyStore; + private KeyStore mKeyStore; private Vpn mVpn; private VpnCallback mVpnCallback = new VpnCallback(); + private boolean mLockdownEnabled; + private LockdownVpnTracker mLockdownTracker; + /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ private Object mRulesLock = new Object(); /** Currently active network rules by UID. */ @@ -276,6 +281,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_SET_POLICY_DATA_ENABLE = 13; + private static final int EVENT_VPN_STATE_CHANGED = 14; + /** Handler used for internal events. */ private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -786,6 +793,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { info = new NetworkInfo(info); info.setDetailedState(DetailedState.BLOCKED, null, null); } + if (mLockdownTracker != null) { + info = mLockdownTracker.augmentNetworkInfo(info); + } return info; } @@ -803,6 +813,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { return getNetworkInfo(mActiveDefaultNetwork, uid); } + public NetworkInfo getActiveNetworkInfoUnfiltered() { + enforceAccessPermission(); + if (isNetworkTypeValid(mActiveDefaultNetwork)) { + final NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork]; + if (tracker != null) { + return tracker.getNetworkInfo(); + } + } + return null; + } + @Override public NetworkInfo getActiveNetworkInfoForUid(int uid) { enforceConnectivityInternalPermission(); @@ -1062,6 +1083,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { // TODO - move this into individual networktrackers int usedNetworkType = convertFeatureToNetworkType(networkType, feature); + if (mLockdownEnabled) { + // Since carrier APNs usually aren't available from VPN + // endpoint, mark them as unavailable. + return PhoneConstants.APN_TYPE_NOT_AVAILABLE; + } + if (mProtectedNetworks.contains(usedNetworkType)) { enforceConnectivityInternalPermission(); } @@ -1769,7 +1796,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void sendConnectedBroadcast(NetworkInfo info) { + public void sendConnectedBroadcast(NetworkInfo info) { sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } @@ -1784,6 +1811,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private Intent makeGeneralIntent(NetworkInfo info, String bcastType) { + if (mLockdownTracker != null) { + info = mLockdownTracker.augmentNetworkInfo(info); + } + Intent intent = new Intent(bcastType); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); @@ -1915,8 +1946,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // load the global proxy at startup mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY)); + + // Try bringing up tracker, but if KeyStore isn't ready yet, wait + // for user to unlock device. + if (!updateLockdownVpn()) { + final IntentFilter filter = new IntentFilter(Intent.ACTION_USER_PRESENT); + mContext.registerReceiver(mUserPresentReceiver, filter); + } } + private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + // Try creating lockdown tracker, since user present usually means + // unlocked keystore. + if (updateLockdownVpn()) { + mContext.unregisterReceiver(this); + } + } + }; + private void handleConnect(NetworkInfo info) { final int type = info.getType(); @@ -2595,6 +2644,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (state == NetworkInfo.State.CONNECTED) { handleConnect(info); } + if (mLockdownTracker != null) { + mLockdownTracker.onNetworkInfoChanged(info); + } break; case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: info = (NetworkInfo) msg.obj; @@ -2692,6 +2744,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { final int networkType = msg.arg1; final boolean enabled = msg.arg2 == ENABLED; handleSetPolicyDataEnable(networkType, enabled); + break; + } + case EVENT_VPN_STATE_CHANGED: { + if (mLockdownTracker != null) { + mLockdownTracker.onVpnStateChanged((NetworkInfo) msg.obj); + } + break; } } } @@ -3090,6 +3149,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ @Override public boolean protectVpn(ParcelFileDescriptor socket) { + throwIfLockdownEnabled(); try { int type = mActiveDefaultNetwork; if (ConnectivityManager.isNetworkTypeValid(type)) { @@ -3116,6 +3176,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ @Override public boolean prepareVpn(String oldPackage, String newPackage) { + throwIfLockdownEnabled(); return mVpn.prepare(oldPackage, newPackage); } @@ -3128,6 +3189,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ @Override public ParcelFileDescriptor establishVpn(VpnConfig config) { + throwIfLockdownEnabled(); return mVpn.establish(config); } @@ -3137,6 +3199,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ @Override public void startLegacyVpn(VpnProfile profile) { + throwIfLockdownEnabled(); final LinkProperties egress = getActiveLinkProperties(); if (egress == null) { throw new IllegalStateException("Missing active network connection"); @@ -3152,6 +3215,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ @Override public LegacyVpnInfo getLegacyVpnInfo() { + throwIfLockdownEnabled(); return mVpn.getLegacyVpnInfo(); } @@ -3170,8 +3234,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public void onStateChanged(NetworkInfo info) { - // TODO: if connected, release delayed broadcast - // TODO: if disconnected, consider kicking off reconnect + mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget(); } public void override(List dnsServers, List searchDomains) { @@ -3240,4 +3303,58 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } + + @Override + public boolean updateLockdownVpn() { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + + // Tear down existing lockdown if profile was removed + mLockdownEnabled = LockdownVpnTracker.isEnabled(); + if (mLockdownEnabled) { + if (mKeyStore.state() != KeyStore.State.UNLOCKED) { + Slog.w(TAG, "KeyStore locked; unable to create LockdownTracker"); + return false; + } + + final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN)); + final VpnProfile profile = VpnProfile.decode( + profileName, mKeyStore.get(Credentials.VPN + profileName)); + setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpn, profile)); + } else { + setLockdownTracker(null); + } + + return true; + } + + /** + * Internally set new {@link LockdownVpnTracker}, shutting down any existing + * {@link LockdownVpnTracker}. Can be {@code null} to disable lockdown. + */ + private void setLockdownTracker(LockdownVpnTracker tracker) { + // Shutdown any existing tracker + final LockdownVpnTracker existing = mLockdownTracker; + mLockdownTracker = null; + if (existing != null) { + existing.shutdown(); + } + + try { + if (tracker != null) { + mNetd.setFirewallEnabled(true); + mLockdownTracker = tracker; + mLockdownTracker.init(); + } else { + mNetd.setFirewallEnabled(false); + } + } catch (RemoteException e) { + // ignored; NMS lives inside system_server + } + } + + private void throwIfLockdownEnabled() { + if (mLockdownEnabled) { + throw new IllegalStateException("Unavailable in lockdown mode"); + } + } } From 0ad0d13d5a78efaf4e824193f892513cf4aab6b2 Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Thu, 16 Aug 2012 12:49:23 -0700 Subject: [PATCH 006/296] Captive portal handling We now notify the user of a captive portal before switching to the network as default. This allows background applications to continue to work until the user confirms he wants to sign in to the captive portal. Also, moved out captive portal handling out of wifi as a seperate component. Change-Id: I7c7507481967e33a1afad0b4961688bd192f0d31 --- .../java/android/net/ConnectivityManager.java | 11 +++ .../android/net/IConnectivityManager.aidl | 2 + core/java/android/net/NetworkInfo.java | 5 +- .../android/server/ConnectivityService.java | 86 ++++++++++++++----- 4 files changed, 81 insertions(+), 23 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 60bf4d6869..a57047363e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -921,4 +921,15 @@ public class ConnectivityManager { return false; } } + + /** + * {@hide} + */ + public void captivePortalCheckComplete(NetworkInfo info) { + try { + mService.captivePortalCheckComplete(info); + } catch (RemoteException e) { + } + } + } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3614045f42..056fa030e9 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -124,4 +124,6 @@ interface IConnectivityManager LegacyVpnInfo getLegacyVpnInfo(); boolean updateLockdownVpn(); + + void captivePortalCheckComplete(in NetworkInfo info); } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 0bc6b58aef..0b23cb72a7 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -79,7 +79,9 @@ public class NetworkInfo implements Parcelable { /** Access to this network is blocked. */ BLOCKED, /** Link has poor connectivity. */ - VERIFYING_POOR_LINK + VERIFYING_POOR_LINK, + /** Checking if network is a captive portal */ + CAPTIVE_PORTAL_CHECK, } /** @@ -97,6 +99,7 @@ public class NetworkInfo implements Parcelable { stateMap.put(DetailedState.AUTHENTICATING, State.CONNECTING); stateMap.put(DetailedState.OBTAINING_IPADDR, State.CONNECTING); stateMap.put(DetailedState.VERIFYING_POOR_LINK, State.CONNECTING); + stateMap.put(DetailedState.CAPTIVE_PORTAL_CHECK, State.CONNECTING); stateMap.put(DetailedState.CONNECTED, State.CONNECTED); stateMap.put(DetailedState.SUSPENDED, State.SUSPENDED); stateMap.put(DetailedState.DISCONNECTING, State.DISCONNECTING); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 776a1a48e1..8a1ac109f3 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -42,6 +42,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.database.ContentObserver; +import android.net.CaptivePortalTracker; import android.net.ConnectivityManager; import android.net.DummyDataStateTracker; import android.net.EthernetDataTracker; @@ -166,6 +167,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private NetworkStateTracker mNetTrackers[]; + /* Handles captive portal check on a network */ + private CaptivePortalTracker mCaptivePortalTracker; + /** * The link properties that define the current links */ @@ -1363,8 +1367,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } NetworkStateTracker tracker = mNetTrackers[networkType]; + DetailedState netState = tracker.getNetworkInfo().getDetailedState(); - if (tracker == null || !tracker.getNetworkInfo().isConnected() || + if (tracker == null || (netState != DetailedState.CONNECTED && + netState != DetailedState.CAPTIVE_PORTAL_CHECK) || tracker.isTeardownRequested()) { if (VDBG) { log("requestRouteToHostAddress on down network " + @@ -1966,32 +1972,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { } }; - private void handleConnect(NetworkInfo info) { - final int type = info.getType(); + private boolean isNewNetTypePreferredOverCurrentNetType(int type) { + if ((type != mNetworkPreference && + mNetConfigs[mActiveDefaultNetwork].priority > + mNetConfigs[type].priority) || + mNetworkPreference == mActiveDefaultNetwork) return false; + return true; + } - setupDataActivityTracking(type); + private void handleConnect(NetworkInfo info) { + final int newNetType = info.getType(); + + setupDataActivityTracking(newNetType); // snapshot isFailover, because sendConnectedBroadcast() resets it boolean isFailover = info.isFailover(); - final NetworkStateTracker thisNet = mNetTrackers[type]; + final NetworkStateTracker thisNet = mNetTrackers[newNetType]; final String thisIface = thisNet.getLinkProperties().getInterfaceName(); // if this is a default net and other default is running // kill the one not preferred - if (mNetConfigs[type].isDefault()) { - if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { - if ((type != mNetworkPreference && - mNetConfigs[mActiveDefaultNetwork].priority > - mNetConfigs[type].priority) || - mNetworkPreference == mActiveDefaultNetwork) { - // don't accept this one - if (VDBG) { - log("Not broadcasting CONNECT_ACTION " + - "to torn down network " + info.getTypeName()); - } - teardown(thisNet); - return; - } else { + if (mNetConfigs[newNetType].isDefault()) { + if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) { + if (isNewNetTypePreferredOverCurrentNetType(newNetType)) { // tear down the other NetworkStateTracker otherNet = mNetTrackers[mActiveDefaultNetwork]; @@ -2004,6 +2007,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { teardown(thisNet); return; } + } else { + // don't accept this one + if (VDBG) { + log("Not broadcasting CONNECT_ACTION " + + "to torn down network " + info.getTypeName()); + } + teardown(thisNet); + return; } } synchronized (ConnectivityService.this) { @@ -2017,7 +2028,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { 1000); } } - mActiveDefaultNetwork = type; + mActiveDefaultNetwork = newNetType; // this will cause us to come up initially as unconnected and switching // to connected after our normal pause unless somebody reports us as reall // disconnected @@ -2029,19 +2040,47 @@ public class ConnectivityService extends IConnectivityManager.Stub { } thisNet.setTeardownRequested(false); updateNetworkSettings(thisNet); - handleConnectivityChange(type, false); + handleConnectivityChange(newNetType, false); sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); // notify battery stats service about this network if (thisIface != null) { try { - BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, type); + BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, newNetType); } catch (RemoteException e) { // ignored; service lives in system_server } } } + private void handleCaptivePortalTrackerCheck(NetworkInfo info) { + if (DBG) log("Captive portal check " + info); + int type = info.getType(); + final NetworkStateTracker thisNet = mNetTrackers[type]; + if (mNetConfigs[type].isDefault()) { + if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { + if (isNewNetTypePreferredOverCurrentNetType(type)) { + if (DBG) log("Captive check on " + info.getTypeName()); + mCaptivePortalTracker = CaptivePortalTracker.detect(mContext, info, + ConnectivityService.this); + return; + } else { + if (DBG) log("Tear down low priority net " + info.getTypeName()); + teardown(thisNet); + return; + } + } + } + + thisNet.captivePortalCheckComplete(); + } + + /** @hide */ + public void captivePortalCheckComplete(NetworkInfo info) { + mNetTrackers[info.getType()].captivePortalCheckComplete(); + mCaptivePortalTracker = null; + } + /** * Setup data activity tracking for the given network interface. * @@ -2630,6 +2669,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { handleConnectionFailure(info); + } else if (info.getDetailedState() == + DetailedState.CAPTIVE_PORTAL_CHECK) { + handleCaptivePortalTrackerCheck(info); } else if (state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) { From 2298689dc112d2904cda22e16820ab07eca0cc10 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 29 Aug 2012 18:32:08 -0700 Subject: [PATCH 007/296] Improve multi-user broadcasts. You can now use ALL and CURRENT when sending broadcasts, to specify where the broadcast goes. Sticky broadcasts are now correctly separated per user, and registered receivers are filtered based on the requested target user. New Context APIs for more kinds of sending broadcasts as users. Updating a bunch of system code that sends broadcasts to explicitly specify which user the broadcast goes to. Made a single version of the code for interpreting the requested target user ID that all entries to activity manager (start activity, send broadcast, start service) use. Change-Id: Ie29f02dd5242ef8c8fa56c54593a315cd2574e1c --- .../java/com/android/server/ConnectivityService.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 8a1ac109f3..04991bbca7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -81,6 +81,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.UserHandle; import android.provider.Settings; import android.security.Credentials; import android.security.KeyStore; @@ -1851,7 +1852,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE); intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType); intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active); - mContext.sendOrderedBroadcast(intent, RECEIVE_DATA_ACTIVITY_CHANGE); + mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, + RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null); } /** @@ -1925,7 +1927,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("sendStickyBroadcast: action=" + intent.getAction()); } - mContext.sendStickyBroadcast(intent); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } } @@ -1946,7 +1948,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { synchronized(this) { mSystemReady = true; if (mInitialBroadcast != null) { - mContext.sendStickyBroadcast(mInitialBroadcast); + mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL); mInitialBroadcast = null; } } @@ -2465,7 +2467,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * Connectivity events can happen before boot has completed ... */ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcast(intent); + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); } // Caller must grab mDnsLock. @@ -3110,7 +3112,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy); - mContext.sendStickyBroadcast(intent); + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } private static class SettingsObserver extends ContentObserver { From e588ca1c19ed85a32b6c50e8c1ea2a202d86f4d0 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 4 Sep 2012 18:48:37 -0700 Subject: [PATCH 008/296] Fix another issue #7097984 java.lang.SecurityException: Permission Denial: broadcast asks to run as user -1 but is calling from user 0; this requires Dupped bug of a different problem. Change-Id: I15f4ab08b81f5f5746ba1cd183dee4f0b1281df5 --- .../android/server/ConnectivityService.java | 30 +++++++++++++++---- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 04991bbca7..cbbfda18c3 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1852,8 +1852,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE); intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType); intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active); - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, - RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, + RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null); + } finally { + Binder.restoreCallingIdentity(ident); + } } /** @@ -1927,7 +1932,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("sendStickyBroadcast: action=" + intent.getAction()); } - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + } finally { + Binder.restoreCallingIdentity(ident); + } } } @@ -2467,7 +2477,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { * Connectivity events can happen before boot has completed ... */ intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + } finally { + Binder.restoreCallingIdentity(ident); + } } // Caller must grab mDnsLock. @@ -3112,7 +3127,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy); - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); + } finally { + Binder.restoreCallingIdentity(ident); + } } private static class SettingsObserver extends ContentObserver { From 69fc5f8bd10ad3415a59a268b7e6f7b751f4aa9f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 6 Sep 2012 17:54:29 -0700 Subject: [PATCH 009/296] Restrict lockdown and firewall to AID_SYSTEM. Bug: 7076289 Change-Id: Iafa3054335e8b1c3c8c3b8db2a4191d4ed4c8c41 --- .../java/com/android/server/ConnectivityService.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cbbfda18c3..3a338a9847 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -77,6 +77,7 @@ import android.os.Looper; import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -3370,7 +3371,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public boolean updateLockdownVpn() { - mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + enforceSystemUid(); // Tear down existing lockdown if profile was removed mLockdownEnabled = LockdownVpnTracker.isEnabled(); @@ -3421,4 +3422,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalStateException("Unavailable in lockdown mode"); } } + + private static void enforceSystemUid() { + final int uid = Binder.getCallingUid(); + if (uid != Process.SYSTEM_UID) { + throw new SecurityException("Only available to AID_SYSTEM"); + } + } } From cf6ffaff69156d677a070c43e27d22f879660397 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 14 Sep 2012 13:47:51 -0700 Subject: [PATCH 010/296] Actually move to Global settings. Also add better ConnectivityService logging. Bug: 7157464 Change-Id: Ia235a7e62ed809240913c4782920c1410c7d597d --- .../android/server/ConnectivityService.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3a338a9847..5c7a3edf37 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -96,6 +96,7 @@ import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.util.IndentingPrintWriter; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; @@ -2593,7 +2594,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } @Override - protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { + final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " "); if (mContext.checkCallingOrSelfPermission( android.Manifest.permission.DUMP) != PackageManager.PERMISSION_GRANTED) { @@ -2602,20 +2604,28 @@ public class ConnectivityService extends IConnectivityManager.Stub { Binder.getCallingUid()); return; } + + // TODO: add locking to get atomic snapshot pw.println(); - for (NetworkStateTracker nst : mNetTrackers) { + for (int i = 0; i < mNetTrackers.length; i++) { + final NetworkStateTracker nst = mNetTrackers[i]; if (nst != null) { + pw.println("NetworkStateTracker for " + getNetworkTypeName(i) + ":"); + pw.increaseIndent(); if (nst.getNetworkInfo().isConnected()) { pw.println("Active network: " + nst.getNetworkInfo(). getTypeName()); } pw.println(nst.getNetworkInfo()); + pw.println(nst.getLinkProperties()); pw.println(nst); pw.println(); + pw.decreaseIndent(); } } pw.println("Network Requester Pids:"); + pw.increaseIndent(); for (int net : mPriorityList) { String pidString = net + ": "; for (Object pid : mNetRequestersPids[net]) { @@ -2624,12 +2634,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { pw.println(pidString); } pw.println(); + pw.decreaseIndent(); pw.println("FeatureUsers:"); + pw.increaseIndent(); for (Object requester : mFeatureUsers) { pw.println(requester.toString()); } pw.println(); + pw.decreaseIndent(); synchronized (this) { pw.println("NetworkTranstionWakeLock is currently " + @@ -2643,9 +2656,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mInetLog != null) { pw.println(); pw.println("Inet condition reports:"); + pw.increaseIndent(); for(int i = 0; i < mInetLog.size(); i++) { pw.println(mInetLog.get(i)); } + pw.decreaseIndent(); } } From d53c789d442a71110dae25b4651f2057ab194730 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 19 Sep 2012 14:10:39 -0700 Subject: [PATCH 011/296] Migrate network stats from removed users. When a user is removed, migrate all network stats belonging to that user into special UID_REMOVED bucket. Also removes those stats from kernel to avoid double-counting if another user is created. Bug: 7194784 Change-Id: I03f1d660fe3754566326b7749cae8068fc224ea9 --- core/tests/coretests/src/android/net/NetworkStatsTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java index 098464f9f0..633196433d 100644 --- a/core/tests/coretests/src/android/net/NetworkStatsTest.java +++ b/core/tests/coretests/src/android/net/NetworkStatsTest.java @@ -287,7 +287,7 @@ public class NetworkStatsTest extends TestCase { .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L) .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L); - final NetworkStats after = before.withoutUid(100); + final NetworkStats after = before.withoutUids(new int[] { 100 }); assertEquals(6, before.size()); assertEquals(2, after.size()); assertValues(after, 0, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L); From 32bed2cc471e75fac9cb1b9abf199f5433fa5dad Mon Sep 17 00:00:00 2001 From: Irfan Sheriff Date: Thu, 20 Sep 2012 09:32:41 -0700 Subject: [PATCH 012/296] Captive check for both mobile and wifi Bug: 7113195 Bug: 7102238 Bug: 7087564 Change-Id: Iac08db9de3935338ad498aa3983d2ca82057dda1 --- .../java/com/android/server/ConnectivityService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 5c7a3edf37..9676eb9e8a 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -32,6 +32,7 @@ import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import android.app.Activity; import android.bluetooth.BluetoothTetheringDataTracker; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -548,6 +549,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); mSettingsObserver.observe(mContext); + mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); loadGlobalProxy(); } @@ -1694,7 +1696,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info)); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); if (info.isFailover()) { intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); @@ -1825,7 +1827,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } Intent intent = new Intent(bcastType); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info)); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); if (info.isFailover()) { intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); @@ -1882,7 +1884,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText); Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info)); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); if (getActiveNetworkInfo() == null) { intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); @@ -2075,8 +2077,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { if (isNewNetTypePreferredOverCurrentNetType(type)) { if (DBG) log("Captive check on " + info.getTypeName()); - mCaptivePortalTracker = CaptivePortalTracker.detect(mContext, info, - ConnectivityService.this); + mCaptivePortalTracker.detectCaptivePortal(new NetworkInfo(info)); return; } else { if (DBG) log("Tear down low priority net " + info.getTypeName()); @@ -2092,7 +2093,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** @hide */ public void captivePortalCheckComplete(NetworkInfo info) { mNetTrackers[info.getType()].captivePortalCheckComplete(); - mCaptivePortalTracker = null; } /** From c67cf56735bc92a2fbc66b93c1c7cefa54752223 Mon Sep 17 00:00:00 2001 From: Jeff Brown Date: Tue, 25 Sep 2012 15:03:20 -0700 Subject: [PATCH 013/296] Update references to migrated global settings. Fixed one setting that was migrated but not marked deprecated. Removed a hidden setting that is no longer used by the new power manager service. Bug: 7231172 Change-Id: I332f020f876a18d519a1a20598a172f1c98036f7 --- .../android/server/ConnectivityService.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9676eb9e8a..ceb17c7bb6 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -701,7 +701,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetConfigs[preference].isDefault()) { if (mNetworkPreference != preference) { final ContentResolver cr = mContext.getContentResolver(); - Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference); + Settings.Global.putInt(cr, Settings.Global.NETWORK_PREFERENCE, preference); synchronized(this) { mNetworkPreference = preference; } @@ -724,8 +724,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private int getPersistedNetworkPreference() { final ContentResolver cr = mContext.getContentResolver(); - final int networkPrefSetting = Settings.Secure - .getInt(cr, Settings.Secure.NETWORK_PREFERENCE, -1); + final int networkPrefSetting = Settings.Global + .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1); if (networkPrefSetting != -1) { return networkPrefSetting; } @@ -2108,14 +2108,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { final int timeout; if (ConnectivityManager.isNetworkTypeMobile(type)) { - timeout = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.DATA_ACTIVITY_TIMEOUT_MOBILE, + timeout = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, 0); // Canonicalize mobile network type type = ConnectivityManager.TYPE_MOBILE; } else if (ConnectivityManager.TYPE_WIFI == type) { - timeout = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.DATA_ACTIVITY_TIMEOUT_WIFI, + timeout = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, 0); } else { // do not track any other networks @@ -2930,8 +2930,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { public boolean isTetheringSupported() { enforceTetherAccessPermission(); int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); - boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0); + boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.TETHER_SUPPORTED, defaultVal) != 0); return tetherEnabledInSettings && mTetheringConfigValid; } From 6c97dcf3c7e18d2266edf386bde1d541523b8b5f Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Wed, 26 Sep 2012 11:33:50 -0700 Subject: [PATCH 014/296] Migrate DATA_ACTIVITY_TIMEOUT_MOBILE/WIFI from Settings.Secure to Settings.Global Bug: 7189605 Change-Id: Id54b8d490d7849bf071c3fbfd8f7358ed873a4e8 --- services/java/com/android/server/ConnectivityService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9676eb9e8a..c8d6459a35 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2108,14 +2108,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { final int timeout; if (ConnectivityManager.isNetworkTypeMobile(type)) { - timeout = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.DATA_ACTIVITY_TIMEOUT_MOBILE, + timeout = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, 0); // Canonicalize mobile network type type = ConnectivityManager.TYPE_MOBILE; } else if (ConnectivityManager.TYPE_WIFI == type) { - timeout = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.DATA_ACTIVITY_TIMEOUT_WIFI, + timeout = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, 0); } else { // do not track any other networks From 8b36157b583d75126b880f4c8ba9a58b0588837e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 26 Sep 2012 15:54:06 -0700 Subject: [PATCH 015/296] First step towards cleaning up Global settings. Remove all @Deprecated @hide settings, and clean up any stragglers. Bug: 7232125 Change-Id: Ibf67093c728d4a28565129b923edb1701d3b2789 --- services/java/com/android/server/ConnectivityService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ceb17c7bb6..891cac71cb 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1509,8 +1509,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // which is where we store the value and maybe make this // asynchronous. enforceAccessPermission(); - boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.MOBILE_DATA, 1) == 1; + boolean retVal = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.MOBILE_DATA, 1) == 1; if (VDBG) log("getMobileDataEnabled returning " + retVal); return retVal; } From 8c87045d090fc2a7f3808688c18472da0d704ff6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 26 Sep 2012 22:03:49 -0700 Subject: [PATCH 016/296] Migrate more Secure settings to Global. Migrate networking, storage, battery, DropBox, and PackageManager related Secure settings to Global table. Bug: 7232014, 7231331, 7231198 Change-Id: I772c2a9586a2f708c9db95622477f235064b8f4d --- .../java/android/net/ConnectivityManager.java | 8 ++++ .../android/server/ConnectivityService.java | 40 +++++++++---------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index a57047363e..6ff1a339fb 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -330,6 +330,14 @@ public class ConnectivityManager { public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; + /** + * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in + * milliseconds. + * + * @hide + */ + public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000; + private final IConnectivityManager mService; public static boolean isNetworkTypeValid(int networkType) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 891cac71cb..033aa1e426 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -378,8 +378,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // read our default dns server ip - String dns = Settings.Secure.getString(context.getContentResolver(), - Settings.Secure.DEFAULT_DNS_SERVER); + String dns = Settings.Global.getString(context.getContentResolver(), + Settings.Global.DEFAULT_DNS_SERVER); if (dns == null || dns.length() == 0) { dns = context.getResources().getString( com.android.internal.R.string.config_default_dns_server); @@ -715,9 +715,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** Check system properties for the default value then use secure settings value, if any. */ int defaultDelay = SystemProperties.getInt( - "conn." + Settings.Secure.CONNECTIVITY_CHANGE_DELAY, - Settings.Secure.CONNECTIVITY_CHANGE_DELAY_DEFAULT); - return Settings.Secure.getInt(cr, Settings.Secure.CONNECTIVITY_CHANGE_DELAY, + "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY, + ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT); + return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY, defaultDelay); } @@ -2997,11 +2997,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (VDBG) log("handleInetConditionChange: starting a change hold"); // setup a new hold to debounce this if (mDefaultInetCondition > 50) { - delay = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); + delay = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); } else { - delay = Settings.Secure.getInt(mContext.getContentResolver(), - Settings.Secure.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); + delay = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.INET_CONDITION_DEBOUNCE_DOWN_DELAY, 3000); } mInetConditionChangeInFlight = true; mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END, @@ -3070,9 +3070,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mGlobalProxy = null; } ContentResolver res = mContext.getContentResolver(); - Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host); - Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port); - Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, + Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host); + Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port); + Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList); } @@ -3084,10 +3084,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void loadGlobalProxy() { ContentResolver res = mContext.getContentResolver(); - String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST); - int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0); - String exclList = Settings.Secure.getString(res, - Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); + String host = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST); + int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0); + String exclList = Settings.Global.getString(res, + Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); if (!TextUtils.isEmpty(host)) { ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList); synchronized (mGlobalProxyLock) { @@ -3118,8 +3118,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void handleDeprecatedGlobalHttpProxy() { - String proxy = Settings.Secure.getString(mContext.getContentResolver(), - Settings.Secure.HTTP_PROXY); + String proxy = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.HTTP_PROXY); if (!TextUtils.isEmpty(proxy)) { String data[] = proxy.split(":"); String proxyHost = data[0]; @@ -3162,8 +3162,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { void observe(Context context) { ContentResolver resolver = context.getContentResolver(); - resolver.registerContentObserver(Settings.Secure.getUriFor( - Settings.Secure.HTTP_PROXY), false, this); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.HTTP_PROXY), false, this); } @Override From dc456a66da46ed33232873764c6c98be007f644b Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Thu, 8 Nov 2012 11:12:09 -0800 Subject: [PATCH 017/296] Remove extraneous logs. Change-Id: I4c47d36748de91bd6fddc419afbf59552bf63e9a --- services/java/com/android/server/ConnectivityService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 033aa1e426..ad1dfb2799 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -629,7 +629,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { wimaxStateTrackerClassName = context.getResources().getString( com.android.internal.R.string.config_wimaxStateTrackerClassname); - log("wimaxJarLocation: " + wimaxJarLocation); + if (DBG) log("wimaxJarLocation: " + wimaxJarLocation); wimaxClassLoader = new DexClassLoader(wimaxJarLocation, new ContextWrapper(context).getCacheDir().getAbsolutePath(), wimaxLibLocation, ClassLoader.getSystemClassLoader()); @@ -648,7 +648,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } try { - log("Starting Wimax Service... "); + if (DBG) log("Starting Wimax Service... "); Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor (new Class[] {Context.class, Handler.class}); From 462e5705c871b134a686cdcb5bf52188e508b6c8 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 31 Oct 2012 14:32:53 -0700 Subject: [PATCH 018/296] Remove DhcpInfoInternal First step in accepting a set of patches. bug:6799630 Change-Id: I6c894c60aeb3022960c2aaa45451bb1dde2b493b --- core/java/android/net/DhcpInfo.java | 5 +- core/java/android/net/LinkProperties.java | 13 +-- core/java/android/net/NetworkUtils.java | 13 +-- core/java/android/net/RouteInfo.java | 4 + core/jni/android_net_NetUtils.cpp | 117 +++++++++++++--------- 5 files changed, 85 insertions(+), 67 deletions(-) diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index e2660e40f5..2b359ebc11 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,16 +22,17 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. + * @deprecated - use LinkProperties - To be removed 11/2013 + * STOPSHIP - make sure we expose LinkProperties through ConnectivityManager */ public class DhcpInfo implements Parcelable { public int ipAddress; public int gateway; public int netmask; - public int dns1; public int dns2; - public int serverAddress; + public int leaseDuration; public DhcpInfo() { diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 75646fdf90..60bf640b38 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -51,7 +51,7 @@ import java.util.Collections; */ public class LinkProperties implements Parcelable { - String mIfaceName; + private String mIfaceName; private Collection mLinkAddresses = new ArrayList(); private Collection mDnses = new ArrayList(); private Collection mRoutes = new ArrayList(); @@ -181,7 +181,7 @@ public class LinkProperties implements Parcelable { } /** - * Compares this {@code LinkProperties} interface name against the target + * Compares this {@code LinkProperties} interface addresses against the target * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. @@ -365,7 +365,6 @@ public class LinkProperties implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(getInterfaceName()); @@ -394,19 +393,15 @@ public class LinkProperties implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public static final Creator CREATOR = new Creator() { public LinkProperties createFromParcel(Parcel in) { LinkProperties netProp = new LinkProperties(); + String iface = in.readString(); if (iface != null) { - try { - netProp.setInterfaceName(iface); - } catch (Exception e) { - return null; - } + netProp.setInterfaceName(iface); } int addressCount = in.readInt(); for (int i=0; iReleaseStringUTFChars(ifname, nameStr); if (result == 0) { - env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr)); + env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear); + // set mIfaceName + // dhcpResults->setInterfaceName(ifname) + env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setInterfaceName, ifname); + + // set the linkAddress + // dhcpResults->addLinkAddress(inetAddress, prefixLength) + result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addLinkAddress, + env->NewStringUTF(ipaddr), prefixLength); + } + + if (result == 0) { // set the gateway - jclass cls = env->FindClass("java/net/InetAddress"); - jmethodID method = env->GetStaticMethodID(cls, "getByName", - "(Ljava/lang/String;)Ljava/net/InetAddress;"); - jvalue args[1]; - args[0].l = env->NewStringUTF(gateway); - jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args); + // dhcpResults->addGateway(gateway) + result = env->CallBooleanMethod(dhcpResults, + dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway)); + } - if (!env->ExceptionOccurred()) { - cls = env->FindClass("android/net/RouteInfo"); - method = env->GetMethodID(cls, "", "(Ljava/net/InetAddress;)V"); - args[0].l = inetAddressObject; - jobject routeInfoObject = env->NewObjectA(cls, method, args); + if (result == 0) { + // dhcpResults->addDns(new InetAddress(dns1)) + result = env->CallBooleanMethod(dhcpResults, + dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1)); + } - cls = env->FindClass("android/net/DhcpInfoInternal"); - method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V"); - args[0].l = routeInfoObject; - env->CallVoidMethodA(info, method, args); - } else { - // if we have an exception (host not found perhaps), just don't add the route - env->ExceptionClear(); - } + if (result == 0) { + result = env->CallBooleanMethod(dhcpResults, + dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2)); + } - env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength); - env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1)); - env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2)); - env->SetObjectField(info, dhcpInfoInternalFieldIds.serverAddress, + if (result == 0) { + // dhcpResults->setServerAddress(new InetAddress(server)) + result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress, env->NewStringUTF(server)); - env->SetIntField(info, dhcpInfoInternalFieldIds.leaseDuration, lease); - env->SetObjectField(info, dhcpInfoInternalFieldIds.vendorInfo, env->NewStringUTF(vendorInfo)); + } + + 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_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info) { return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false); @@ -217,8 +230,8 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface }, { "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface }, { "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections }, - { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp }, - { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew }, + { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_runDhcp }, + { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_runDhcpRenew }, { "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 }, @@ -226,16 +239,24 @@ static JNINativeMethod gNetworkUtilMethods[] = { int register_android_net_NetworkUtils(JNIEnv* env) { - jclass dhcpInfoInternalClass = env->FindClass("android/net/DhcpInfoInternal"); - LOG_FATAL_IF(dhcpInfoInternalClass == NULL, "Unable to find class android/net/DhcpInfoInternal"); - dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalClass, "", "()V"); - dhcpInfoInternalFieldIds.ipaddress = env->GetFieldID(dhcpInfoInternalClass, "ipAddress", "Ljava/lang/String;"); - dhcpInfoInternalFieldIds.prefixLength = env->GetFieldID(dhcpInfoInternalClass, "prefixLength", "I"); - dhcpInfoInternalFieldIds.dns1 = env->GetFieldID(dhcpInfoInternalClass, "dns1", "Ljava/lang/String;"); - dhcpInfoInternalFieldIds.dns2 = env->GetFieldID(dhcpInfoInternalClass, "dns2", "Ljava/lang/String;"); - dhcpInfoInternalFieldIds.serverAddress = env->GetFieldID(dhcpInfoInternalClass, "serverAddress", "Ljava/lang/String;"); - dhcpInfoInternalFieldIds.leaseDuration = env->GetFieldID(dhcpInfoInternalClass, "leaseDuration", "I"); - dhcpInfoInternalFieldIds.vendorInfo = env->GetFieldID(dhcpInfoInternalClass, "vendorInfo", "Ljava/lang/String;"); + jclass dhcpResultsClass = env->FindClass("android/net/DhcpResults"); + LOG_FATAL_IF(dhcpResultsClass == NULL, "Unable to find class android/net/DhcpResults"); + dhcpResultsFieldIds.clear = + env->GetMethodID(dhcpResultsClass, "clear", "()V"); + dhcpResultsFieldIds.setInterfaceName = + env->GetMethodID(dhcpResultsClass, "setInterfaceName", "(Ljava/lang/String;)V"); + dhcpResultsFieldIds.addLinkAddress = + env->GetMethodID(dhcpResultsClass, "addLinkAddress", "(Ljava/lang/String;I)Z"); + dhcpResultsFieldIds.addGateway = + env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z"); + dhcpResultsFieldIds.addDns = + env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z"); + dhcpResultsFieldIds.setServerAddress = + env->GetMethodID(dhcpResultsClass, "setServerAddress", "(Ljava/lang/String;)Z"); + dhcpResultsFieldIds.setLeaseDuration = + env->GetMethodID(dhcpResultsClass, "setLeaseDuration", "(I)V"); + dhcpResultsFieldIds.setVendorInfo = + env->GetMethodID(dhcpResultsClass, "setVendorInfo", "(Ljava/lang/String;)V"); return AndroidRuntime::registerNativeMethods(env, NETUTILS_PKG_NAME, gNetworkUtilMethods, NELEM(gNetworkUtilMethods)); From 876ddc95641f80a37073656589d05ae56e77b650 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Fri, 9 Nov 2012 15:57:02 -0800 Subject: [PATCH 019/296] Increase readability of connectivity event log. Bug: 6322766 Change-Id: I556759f5fc1466cdd4db6b4574084a8068dc9909 --- .../com/android/server/ConnectivityService.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ad1dfb2799..a7c4d73013 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2686,18 +2686,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } - // Connectivity state changed: - // [31-14] Reserved for future use - // [13-10] Network subtype (for mobile network, as defined - // by TelephonyManager) - // [9-4] Detailed state ordinal (as defined by - // NetworkInfo.DetailedState) - // [3-0] Network type (as defined by ConnectivityManager) - int eventLogParam = (info.getType() & 0xf) | - ((info.getDetailedState().ordinal() & 0x3f) << 4) | - (info.getSubtype() << 10); - EventLog.writeEvent(EventLogTags.CONNECTIVITY_STATE_CHANGED, - eventLogParam); + EventLogTags.writeConnectivityStateChanged( + info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { From cd2778578b779c016ff99e9c864289eb1d695c73 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 9 Nov 2012 10:52:27 -0800 Subject: [PATCH 020/296] Support for dns domain. bug:6799630 Change-Id: I10070eddb65b7b60f0bc2b3e1e320e1aa4ec6e98 --- core/java/android/net/LinkProperties.java | 28 +++++++++++++++++-- core/jni/android_net_NetUtils.cpp | 18 ++++++++---- .../android/server/ConnectivityService.java | 14 +++++----- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 60bf640b38..b9362dabf2 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -54,6 +54,7 @@ public class LinkProperties implements Parcelable { private String mIfaceName; private Collection mLinkAddresses = new ArrayList(); private Collection mDnses = new ArrayList(); + private String mDomains; private Collection mRoutes = new ArrayList(); private ProxyProperties mHttpProxy; @@ -82,9 +83,10 @@ public class LinkProperties implements Parcelable { mIfaceName = source.getInterfaceName(); for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l); for (InetAddress i : source.getDnses()) mDnses.add(i); + mDomains = source.getDomains(); for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? - null : new ProxyProperties(source.getHttpProxy()); + null : new ProxyProperties(source.getHttpProxy()); } } @@ -120,6 +122,14 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(mDnses); } + public String getDomains() { + return mDomains; + } + + public void setDomains(String domains) { + mDomains = domains; + } + public void addRoute(RouteInfo route) { if (route != null) mRoutes.add(route); } @@ -138,6 +148,7 @@ public class LinkProperties implements Parcelable { mIfaceName = null; mLinkAddresses.clear(); mDnses.clear(); + mDomains = null; mRoutes.clear(); mHttpProxy = null; } @@ -162,12 +173,14 @@ public class LinkProperties implements Parcelable { for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; dns += "] "; - String routes = "Routes: ["; + String domainName = "Domains: " + mDomains; + + String routes = " Routes: ["; for (RouteInfo route : mRoutes) routes += route.toString() + ","; routes += "] "; String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); - return ifaceName + linkAddresses + routes + dns + proxy; + return ifaceName + linkAddresses + routes + dns + domainName + proxy; } /** @@ -201,6 +214,12 @@ public class LinkProperties implements Parcelable { */ public boolean isIdenticalDnses(LinkProperties target) { Collection targetDnses = target.getDnses(); + String targetDomains = target.getDomains(); + if (mDomains == null) { + if (targetDomains != null) return false; + } else { + if (mDomains.equals(targetDomains) == false) return false; + } return (mDnses.size() == targetDnses.size()) ? mDnses.containsAll(targetDnses) : false; } @@ -359,6 +378,7 @@ public class LinkProperties implements Parcelable { return ((null == mIfaceName) ? 0 : mIfaceName.hashCode() + mLinkAddresses.size() * 31 + mDnses.size() * 37 + + ((null == mDomains) ? 0 : mDomains.hashCode()) + mRoutes.size() * 41 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())); } @@ -377,6 +397,7 @@ public class LinkProperties implements Parcelable { for(InetAddress d : mDnses) { dest.writeByteArray(d.getAddress()); } + dest.writeString(mDomains); dest.writeInt(mRoutes.size()); for(RouteInfo route : mRoutes) { @@ -413,6 +434,7 @@ public class LinkProperties implements Parcelable { netProp.addDns(InetAddress.getByAddress(in.createByteArray())); } catch (UnknownHostException e) { } } + netProp.setDomains(in.readString()); addressCount = in.readInt(); for (int i=0; iGetStringUTFChars(ifname, NULL); if (nameStr == NULL) return (jboolean)false; if (renew) { result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease, vendorInfo); + dns1, dns2, server, &lease, vendorInfo, domains); } else { result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease, vendorInfo); + dns1, dns2, server, &lease, vendorInfo, domains); } - env->ReleaseStringUTFChars(ifname, nameStr); if (result == 0) { env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear); @@ -160,6 +163,9 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr } if (result == 0) { + env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains, + env->NewStringUTF(domains)); + result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2)); } @@ -251,6 +257,8 @@ int register_android_net_NetworkUtils(JNIEnv* env) env->GetMethodID(dhcpResultsClass, "addGateway", "(Ljava/lang/String;)Z"); dhcpResultsFieldIds.addDns = env->GetMethodID(dhcpResultsClass, "addDns", "(Ljava/lang/String;)Z"); + dhcpResultsFieldIds.setDomains = + env->GetMethodID(dhcpResultsClass, "setDomains", "(Ljava/lang/String;)V"); dhcpResultsFieldIds.setServerAddress = env->GetMethodID(dhcpResultsClass, "setServerAddress", "(Ljava/lang/String;)Z"); dhcpResultsFieldIds.setLeaseDuration = diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ad1dfb2799..c59c3d97af 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2524,19 +2524,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { SystemProperties.set(key, ""); } mNumDnsEntries = last; + if (SystemProperties.get("net.dns.search").equals(domains) == false) { + SystemProperties.set("net.dns.search", domains); + changed = true; + } if (changed) { try { - mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses)); + mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); mNetd.setDefaultInterfaceForDns(iface); } catch (Exception e) { if (DBG) loge("exception setting default dns interface: " + e); } } - if (!domains.equals(SystemProperties.get("net.dns.search"))) { - SystemProperties.set("net.dns.search", domains); - changed = true; - } return changed; } @@ -2552,13 +2552,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { String network = nt.getNetworkInfo().getTypeName(); synchronized (mDnsLock) { if (!mDnsOverridden) { - changed = updateDns(network, p.getInterfaceName(), dnses, ""); + changed = updateDns(network, p.getInterfaceName(), dnses, p.getDomains()); } } } else { try { mNetd.setDnsServersForInterface(p.getInterfaceName(), - NetworkUtils.makeStrings(dnses)); + NetworkUtils.makeStrings(dnses), p.getDomains()); } catch (Exception e) { if (DBG) loge("exception setting dns servers: " + e); } From 028d203d0f5b90674470763a685608b1202605b3 Mon Sep 17 00:00:00 2001 From: Jianzheng Zhou Date: Fri, 16 Nov 2012 13:45:20 +0800 Subject: [PATCH 021/296] Refactor getPersistedNetworkPreference Optimize for updating mNetworkPreference according to device's networkAttributes setting from overlay config.xml when connectivityservice start. Change-Id: I90286332d4f453038f1ddac7dd9d1265d96b4859 Signed-off-by: Jianzheng Zhou --- .../java/android/net/ConnectivityManager.java | 12 ++++++++++ .../android/server/ConnectivityService.java | 22 ++++++++++++++----- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 6ff1a339fb..cda9f77c0e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -328,6 +328,18 @@ public class ConnectivityManager { /** {@hide} */ public static final int MAX_NETWORK_TYPE = TYPE_WIFI_P2P; + /** + * If you want to set the default network preference,you can directly + * change the networkAttributes array in framework's config.xml. + * + * @deprecated Since we support so many more networks now, the single + * network default network preference can't really express + * the heirarchy. Instead, the default is defined by the + * networkAttributes in config.xml. You can determine + * the current value by calling {@link getNetworkPreference()} + * from an App. + */ + @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; /** diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4c22ae8cb3..8c5ff04241 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -412,8 +412,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { ConnectivityManager.MAX_NETWORK_TYPE+1]; mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1]; - mNetworkPreference = getPersistedNetworkPreference(); - mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1]; mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; @@ -495,6 +493,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + // Update mNetworkPreference according to user mannually first then overlay config.xml + mNetworkPreference = getPersistedNetworkPreference(); + if (mNetworkPreference == -1) { + for (int n : mPriorityList) { + if (mNetConfigs[n].isDefault() && ConnectivityManager.isNetworkTypeValid(n)) { + mNetworkPreference = n; + break; + } + } + if (mNetworkPreference == -1) { + throw new IllegalStateException( + "You should set at least one default Network in config.xml!"); + } + } + mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; for (int i : mPriorityList) { mNetRequestersPids[i] = new ArrayList(); @@ -726,11 +739,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { final int networkPrefSetting = Settings.Global .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1); - if (networkPrefSetting != -1) { - return networkPrefSetting; - } - return ConnectivityManager.DEFAULT_NETWORK_PREFERENCE; + return networkPrefSetting; } /** From f909cb1535704ba7194c1bcb4911e5640379e9e2 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 7 Dec 2012 09:56:50 -0800 Subject: [PATCH 022/296] Fix javadoc break Change-Id: Ia69a5cbead61747537269e267dcd8da320d61ba3 --- core/java/android/net/ConnectivityManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index cda9f77c0e..a8a68d0e32 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -336,7 +336,7 @@ public class ConnectivityManager { * network default network preference can't really express * the heirarchy. Instead, the default is defined by the * networkAttributes in config.xml. You can determine - * the current value by calling {@link getNetworkPreference()} + * the current value by calling {@link #getNetworkPreference()} * from an App. */ @Deprecated From c6534b50300896fc7bc64c475eb0a56508aa3a3d Mon Sep 17 00:00:00 2001 From: Mikael Hedegren Date: Fri, 14 Dec 2012 15:52:52 +0100 Subject: [PATCH 023/296] Return error upon attempt to use non-existent APN startUsingNetworkFeature will ignore errors from reconnect - causing ConnectivityService to send faulty information back to requester. Change-Id: I4e0fcc1addd84da409cdc1eed1a95d25d925e020 --- services/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ad1dfb2799..ec682e8e33 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1183,8 +1183,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("startUsingNetworkFeature reconnecting to " + networkType + ": " + feature); } - network.reconnect(); - return PhoneConstants.APN_REQUEST_STARTED; + if (network.reconnect()) { + return PhoneConstants.APN_REQUEST_STARTED; + } else { + return PhoneConstants.APN_REQUEST_FAILED; + } } else { // need to remember this unsupported request so we respond appropriately on stop synchronized(this) { From f012738c731a8c539beba57a79e94bc622bbfcf6 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 3 Jan 2013 11:21:24 -0800 Subject: [PATCH 024/296] Expose roaming flag for testing. Change-Id: I29ef6fc59926a97f4e97c561387ac9bc0e4e4769 --- core/java/android/net/NetworkInfo.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 0b23cb72a7..689dae5301 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -19,6 +19,8 @@ package android.net; import android.os.Parcelable; import android.os.Parcel; +import com.android.internal.annotations.VisibleForTesting; + import java.util.EnumMap; /** @@ -312,7 +314,9 @@ public class NetworkInfo implements Parcelable { } } - void setRoaming(boolean isRoaming) { + /** {@hide} */ + @VisibleForTesting + public void setRoaming(boolean isRoaming) { synchronized (this) { mIsRoaming = isRoaming; } From 72e2243b31cbc90be156e375b4199f25ea2c7307 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 9 Jan 2013 16:28:19 -0800 Subject: [PATCH 025/296] Up our DNS server support from 2 > 4 bug:5958524 Change-Id: I81a9d9293049bcfc16c15ee856887aa7ed076638 --- core/jni/android_net_NetUtils.cpp | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 296add3922..f5f22b2d2a 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -28,23 +28,21 @@ int ifc_enable(const char *ifname); int ifc_disable(const char *ifname); int ifc_reset_connections(const char *ifname, int reset_mask); -int dhcp_do_request(const char *ifname, +int dhcp_do_request(const char * const ifname, const char *ipaddr, const char *gateway, uint32_t *prefixLength, - const char *dns1, - const char *dns2, + const char *dns[], const char *server, uint32_t *lease, const char *vendorInfo, const char *domains); -int dhcp_do_request_renew(const char *ifname, +int dhcp_do_request_renew(const char * const ifname, const char *ipaddr, const char *gateway, uint32_t *prefixLength, - const char *dns1, - const char *dns2, + const char *dns[], const char *server, uint32_t *lease, const char *vendorInfo, @@ -120,6 +118,9 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr 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]; @@ -130,10 +131,10 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr if (renew) { result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease, vendorInfo, domains); + dns, server, &lease, vendorInfo, domains); } else { result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, - dns1, dns2, server, &lease, vendorInfo, domains); + dns, server, &lease, vendorInfo, domains); } env->ReleaseStringUTFChars(ifname, nameStr); if (result == 0) { @@ -168,6 +169,15 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr 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) { From b101d0116714f68a8a95644dcaf120015a6d3b32 Mon Sep 17 00:00:00 2001 From: Mattias Falk Date: Tue, 23 Aug 2011 14:15:13 +0200 Subject: [PATCH 026/296] Second pass tying into dns cache per interface Set dns servers for secondary nets and attach the processes (pids) that are using the secondary nets to the secondary nets associated dns cache. Change-Id: Id865c2c3fdc0ec1c3e30c134e9ea4109f4f2fbeb bug:5465296 --- .../android/server/ConnectivityService.java | 157 +++++------------- 1 file changed, 43 insertions(+), 114 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4cfe5d5253..2ccde3b655 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -183,7 +183,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * A per Net list of the PID's that requested access to the net * used both as a refcount and for per-PID DNS selection */ - private List mNetRequestersPids[]; + private List mNetRequestersPids[]; // priority order of the nettrackers // (excluding dynamically set mNetworkPreference) @@ -200,7 +200,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private int mDefaultConnectionSequence = 0; private Object mDnsLock = new Object(); - private int mNumDnsEntries; private boolean mDnsOverridden = false; private boolean mTestMode; @@ -508,15 +507,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; + mNetRequestersPids = + (List [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; for (int i : mPriorityList) { - mNetRequestersPids[i] = new ArrayList(); + mNetRequestersPids[i] = new ArrayList(); } mFeatureUsers = new ArrayList(); - mNumDnsEntries = 0; - mTestMode = SystemProperties.get("cm.test.mode").equals("true") && SystemProperties.get("ro.build.type").equals("eng"); @@ -1317,6 +1315,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { Integer currentPid = new Integer(pid); mNetRequestersPids[usedNetworkType].remove(currentPid); reassessPidDns(pid, true); + flushVmDnsCache(); if (mNetRequestersPids[usedNetworkType].size() != 0) { if (VDBG) { log("stopUsingNetworkFeature: net " + networkType + ": " + feature + @@ -1698,9 +1697,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { * in accordance with network preference policies. */ if (!mNetConfigs[prevNetType].isDefault()) { - List pids = mNetRequestersPids[prevNetType]; - for (int i = 0; i pids = mNetRequestersPids[prevNetType]; + for (Integer pid : pids) { // will remove them because the net's no longer connected // need to do this now as only now do we know the pids and // can properly null things that are no longer referenced. @@ -2250,6 +2248,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } if (resetDns) { + flushVmDnsCache(); if (VDBG) log("resetting DNS cache for " + iface); try { mNetd.flushInterfaceDnsCache(iface); @@ -2416,9 +2415,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { * on the highest priority active net which this process requested. * If there aren't any, clear it out */ - private void reassessPidDns(int myPid, boolean doBump) + private void reassessPidDns(int pid, boolean doBump) { - if (VDBG) log("reassessPidDns for pid " + myPid); + if (VDBG) log("reassessPidDns for pid " + pid); + Integer myPid = new Integer(pid); for(int i : mPriorityList) { if (mNetConfigs[i].isDefault()) { continue; @@ -2428,61 +2428,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { !nt.isTeardownRequested()) { LinkProperties p = nt.getLinkProperties(); if (p == null) continue; - List pids = mNetRequestersPids[i]; - for (int j=0; j dnses = p.getDnses(); - writePidDns(dnses, myPid); - if (doBump) { - bumpDns(); - } - return; + if (mNetRequestersPids[i].contains(myPid)) { + try { + mNetd.setDnsIfaceForPid(p.getInterfaceName(), pid); + } catch (Exception e) { + Slog.e(TAG, "exception reasseses pid dns: " + e); } + return; } } } // nothing found - delete - for (int i = 1; ; i++) { - String prop = "net.dns" + i + "." + myPid; - if (SystemProperties.get(prop).length() == 0) { - if (doBump) { - bumpDns(); - } - return; - } - SystemProperties.set(prop, ""); + try { + mNetd.clearDnsIfaceForPid(pid); + } catch (Exception e) { + Slog.e(TAG, "exception clear interface from pid: " + e); } } - // return true if results in a change - private boolean writePidDns(Collection dnses, int pid) { - int j = 1; - boolean changed = false; - for (InetAddress dns : dnses) { - String dnsString = dns.getHostAddress(); - if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) { - changed = true; - SystemProperties.set("net.dns" + j + "." + pid, dns.getHostAddress()); - } - j++; - } - return changed; - } - - private void bumpDns() { - /* - * Bump the property that tells the name resolver library to reread - * the DNS server list from the properties. - */ - String propVal = SystemProperties.get("net.dnschange"); - int n = 0; - if (propVal.length() != 0) { - try { - n = Integer.parseInt(propVal); - } catch (NumberFormatException e) {} - } - SystemProperties.set("net.dnschange", "" + (n+1)); + private void flushVmDnsCache() { /* * Tell the VMs to toss their DNS caches */ @@ -2501,56 +2465,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Caller must grab mDnsLock. - private boolean updateDns(String network, String iface, + private void updateDns(String network, String iface, Collection dnses, String domains) { - boolean changed = false; int last = 0; if (dnses.size() == 0 && mDefaultDns != null) { - ++last; - String value = mDefaultDns.getHostAddress(); - if (!value.equals(SystemProperties.get("net.dns1"))) { - if (DBG) { - loge("no dns provided for " + network + " - using " + value); - } - changed = true; - SystemProperties.set("net.dns1", value); + dnses = new ArrayList(); + dnses.add(mDefaultDns); + if (DBG) { + loge("no dns provided for " + network + " - using " + mDefaultDns.getHostAddress()); } - } else { - for (InetAddress dns : dnses) { - ++last; - String key = "net.dns" + last; - String value = dns.getHostAddress(); - if (!changed && value.equals(SystemProperties.get(key))) { - continue; - } - if (VDBG) { - log("adding dns " + value + " for " + network); - } - changed = true; - SystemProperties.set(key, value); - } - } - for (int i = last + 1; i <= mNumDnsEntries; ++i) { - String key = "net.dns" + i; - if (VDBG) log("erasing " + key); - changed = true; - SystemProperties.set(key, ""); - } - mNumDnsEntries = last; - if (SystemProperties.get("net.dns.search").equals(domains) == false) { - SystemProperties.set("net.dns.search", domains); - changed = true; } - if (changed) { - try { - mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); - mNetd.setDefaultInterfaceForDns(iface); - } catch (Exception e) { - if (DBG) loge("exception setting default dns interface: " + e); - } + try { + mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); + mNetd.setDefaultInterfaceForDns(iface); + } catch (Exception e) { + if (DBG) loge("exception setting default dns interface: " + e); } - return changed; } private void handleDnsConfigurationChange(int netType) { @@ -2560,12 +2491,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { LinkProperties p = nt.getLinkProperties(); if (p == null) return; Collection dnses = p.getDnses(); - boolean changed = false; if (mNetConfigs[netType].isDefault()) { String network = nt.getNetworkInfo().getTypeName(); synchronized (mDnsLock) { if (!mDnsOverridden) { - changed = updateDns(network, p.getInterfaceName(), dnses, p.getDomains()); + updateDns(network, p.getInterfaceName(), dnses, p.getDomains()); } } } else { @@ -2576,13 +2506,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) loge("exception setting dns servers: " + e); } // set per-pid dns for attached secondary nets - List pids = mNetRequestersPids[netType]; - for (int y=0; y< pids.size(); y++) { - Integer pid = (Integer)pids.get(y); - changed = writePidDns(dnses, pid.intValue()); + List pids = mNetRequestersPids[netType]; + for (Integer pid : pids) { + try { + mNetd.setDnsIfaceForPid(p.getInterfaceName(), pid); + } catch (Exception e) { + Slog.e(TAG, "exception setting interface for pid: " + e); + } } } - if (changed) bumpDns(); + flushVmDnsCache(); } } @@ -2641,7 +2574,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { pw.increaseIndent(); for (int net : mPriorityList) { String pidString = net + ": "; - for (Object pid : mNetRequestersPids[net]) { + for (Integer pid : mNetRequestersPids[net]) { pidString = pidString + pid.toString() + ", "; } pw.println(pidString); @@ -3351,14 +3284,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { String domains = buffer.toString().trim(); // Apply DNS changes. - boolean changed = false; synchronized (mDnsLock) { - changed = updateDns("VPN", "VPN", addresses, domains); + updateDns("VPN", "VPN", addresses, domains); mDnsOverridden = true; } - if (changed) { - bumpDns(); - } // Temporarily disable the default proxy. synchronized (mDefaultProxyLock) { From 2587a53c31073d277590cb9a8ae5e3bb58006927 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 18 Jan 2013 09:31:13 -0800 Subject: [PATCH 027/296] Clean up published network condition reporting. Change-Id: I371c04bcb0547f1133e7ce12a6871aad3b3fdc6b --- .../android/server/ConnectivityService.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 2ccde3b655..5aba7ec649 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -194,7 +194,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private int mNetworkPreference; private int mActiveDefaultNetwork = -1; // 0 is full bad, 100 is full good - private int mDefaultInetCondition = 0; private int mDefaultInetConditionPublished = 0; private boolean mInetConditionChangeInFlight = false; private int mDefaultConnectionSequence = 0; @@ -1728,6 +1727,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { mDefaultInetConditionPublished = 0; // we're not connected anymore + if (DBG) { + log("handleDisconnect: net=" + mActiveDefaultNetwork + + ", published condition=" + mDefaultInetConditionPublished); + } intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } } @@ -1918,6 +1921,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { mDefaultInetConditionPublished = 0; + if (DBG) { + log("handleConnectionFailure: net=" + mActiveDefaultNetwork + + ", published condition=" + mDefaultInetConditionPublished); + } intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } } @@ -2062,6 +2069,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { mDefaultInetConditionPublished = 0; mDefaultConnectionSequence++; mInetConditionChangeInFlight = false; + if (DBG) { + log("handleConnect: net=" + newNetType + + ", published condition=" + mDefaultInetConditionPublished); + } // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); } @@ -2712,7 +2723,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { { int netType = msg.arg1; int sequence = msg.arg2; - handleInetConditionHoldEnd(netType, sequence); + int condition = (Integer)msg.obj; + handleInetConditionHoldEnd(netType, sequence, condition); break; } case EVENT_SET_NETWORK_PREFERENCE: @@ -2925,14 +2937,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (VDBG) { log("handleInetConditionChange: net=" + netType + ", condition=" + condition + - ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); + " mActiveDefaultNetwork=" + mActiveDefaultNetwork); } - mDefaultInetCondition = condition; int delay; if (mInetConditionChangeInFlight == false) { if (VDBG) log("handleInetConditionChange: starting a change hold"); // setup a new hold to debounce this - if (mDefaultInetCondition > 50) { + if (condition > 50) { delay = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); } else { @@ -2941,18 +2952,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mInetConditionChangeInFlight = true; mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END, - mActiveDefaultNetwork, mDefaultConnectionSequence), delay); + mActiveDefaultNetwork, mDefaultConnectionSequence, new Integer(condition)), delay); } else { // we've set the new condition, when this hold ends that will get picked up if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt"); } } - private void handleInetConditionHoldEnd(int netType, int sequence) { + private void handleInetConditionHoldEnd(int netType, int sequence, int condition) { if (DBG) { - log("handleInetConditionHoldEnd: net=" + netType + - ", condition=" + mDefaultInetCondition + - ", published condition=" + mDefaultInetConditionPublished); + log("handleInetConditionHoldEnd: net=" + netType + ", condition=" + condition); } mInetConditionChangeInFlight = false; @@ -2964,19 +2973,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring"); return; } - // TODO: Figure out why this optimization sometimes causes a - // change in mDefaultInetCondition to be missed and the - // UI to not be updated. - //if (mDefaultInetConditionPublished == mDefaultInetCondition) { - // if (DBG) log("no change in condition - aborting"); - // return; - //} + NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); if (networkInfo.isConnected() == false) { if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring"); return; } - mDefaultInetConditionPublished = mDefaultInetCondition; + mDefaultInetConditionPublished = condition; sendInetConditionBroadcast(networkInfo); return; } From d3aec30722086bee13cb646669a0e900d6d11a6d Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sat, 19 Jan 2013 00:34:07 +0000 Subject: [PATCH 028/296] Revert "Second pass tying into dns cache per interface" This reverts commit b101d0116714f68a8a95644dcaf120015a6d3b32 Change-Id: If52dffd5100a6b03275da0eabfa05e24c5ecada9 --- .../android/server/ConnectivityService.java | 159 +++++++++++++----- 1 file changed, 115 insertions(+), 44 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 2ccde3b655..4cfe5d5253 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -183,7 +183,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * A per Net list of the PID's that requested access to the net * used both as a refcount and for per-PID DNS selection */ - private List mNetRequestersPids[]; + private List mNetRequestersPids[]; // priority order of the nettrackers // (excluding dynamically set mNetworkPreference) @@ -200,6 +200,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private int mDefaultConnectionSequence = 0; private Object mDnsLock = new Object(); + private int mNumDnsEntries; private boolean mDnsOverridden = false; private boolean mTestMode; @@ -507,14 +508,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - mNetRequestersPids = - (List [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; + mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; for (int i : mPriorityList) { - mNetRequestersPids[i] = new ArrayList(); + mNetRequestersPids[i] = new ArrayList(); } mFeatureUsers = new ArrayList(); + mNumDnsEntries = 0; + mTestMode = SystemProperties.get("cm.test.mode").equals("true") && SystemProperties.get("ro.build.type").equals("eng"); @@ -1315,7 +1317,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { Integer currentPid = new Integer(pid); mNetRequestersPids[usedNetworkType].remove(currentPid); reassessPidDns(pid, true); - flushVmDnsCache(); if (mNetRequestersPids[usedNetworkType].size() != 0) { if (VDBG) { log("stopUsingNetworkFeature: net " + networkType + ": " + feature + @@ -1697,8 +1698,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { * in accordance with network preference policies. */ if (!mNetConfigs[prevNetType].isDefault()) { - List pids = mNetRequestersPids[prevNetType]; - for (Integer pid : pids) { + List pids = mNetRequestersPids[prevNetType]; + for (int i = 0; i dnses = p.getDnses(); + writePidDns(dnses, myPid); + if (doBump) { + bumpDns(); + } + return; } - return; } } } // nothing found - delete - try { - mNetd.clearDnsIfaceForPid(pid); - } catch (Exception e) { - Slog.e(TAG, "exception clear interface from pid: " + e); + for (int i = 1; ; i++) { + String prop = "net.dns" + i + "." + myPid; + if (SystemProperties.get(prop).length() == 0) { + if (doBump) { + bumpDns(); + } + return; + } + SystemProperties.set(prop, ""); } } - private void flushVmDnsCache() { + // return true if results in a change + private boolean writePidDns(Collection dnses, int pid) { + int j = 1; + boolean changed = false; + for (InetAddress dns : dnses) { + String dnsString = dns.getHostAddress(); + if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) { + changed = true; + SystemProperties.set("net.dns" + j + "." + pid, dns.getHostAddress()); + } + j++; + } + return changed; + } + + private void bumpDns() { + /* + * Bump the property that tells the name resolver library to reread + * the DNS server list from the properties. + */ + String propVal = SystemProperties.get("net.dnschange"); + int n = 0; + if (propVal.length() != 0) { + try { + n = Integer.parseInt(propVal); + } catch (NumberFormatException e) {} + } + SystemProperties.set("net.dnschange", "" + (n+1)); /* * Tell the VMs to toss their DNS caches */ @@ -2465,23 +2501,56 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Caller must grab mDnsLock. - private void updateDns(String network, String iface, + private boolean updateDns(String network, String iface, Collection dnses, String domains) { + boolean changed = false; int last = 0; if (dnses.size() == 0 && mDefaultDns != null) { - dnses = new ArrayList(); - dnses.add(mDefaultDns); - if (DBG) { - loge("no dns provided for " + network + " - using " + mDefaultDns.getHostAddress()); + ++last; + String value = mDefaultDns.getHostAddress(); + if (!value.equals(SystemProperties.get("net.dns1"))) { + if (DBG) { + loge("no dns provided for " + network + " - using " + value); + } + changed = true; + SystemProperties.set("net.dns1", value); + } + } else { + for (InetAddress dns : dnses) { + ++last; + String key = "net.dns" + last; + String value = dns.getHostAddress(); + if (!changed && value.equals(SystemProperties.get(key))) { + continue; + } + if (VDBG) { + log("adding dns " + value + " for " + network); + } + changed = true; + SystemProperties.set(key, value); } } - - try { - mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); - mNetd.setDefaultInterfaceForDns(iface); - } catch (Exception e) { - if (DBG) loge("exception setting default dns interface: " + e); + for (int i = last + 1; i <= mNumDnsEntries; ++i) { + String key = "net.dns" + i; + if (VDBG) log("erasing " + key); + changed = true; + SystemProperties.set(key, ""); } + mNumDnsEntries = last; + if (SystemProperties.get("net.dns.search").equals(domains) == false) { + SystemProperties.set("net.dns.search", domains); + changed = true; + } + + if (changed) { + try { + mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); + mNetd.setDefaultInterfaceForDns(iface); + } catch (Exception e) { + if (DBG) loge("exception setting default dns interface: " + e); + } + } + return changed; } private void handleDnsConfigurationChange(int netType) { @@ -2491,11 +2560,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { LinkProperties p = nt.getLinkProperties(); if (p == null) return; Collection dnses = p.getDnses(); + boolean changed = false; if (mNetConfigs[netType].isDefault()) { String network = nt.getNetworkInfo().getTypeName(); synchronized (mDnsLock) { if (!mDnsOverridden) { - updateDns(network, p.getInterfaceName(), dnses, p.getDomains()); + changed = updateDns(network, p.getInterfaceName(), dnses, p.getDomains()); } } } else { @@ -2506,16 +2576,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) loge("exception setting dns servers: " + e); } // set per-pid dns for attached secondary nets - List pids = mNetRequestersPids[netType]; - for (Integer pid : pids) { - try { - mNetd.setDnsIfaceForPid(p.getInterfaceName(), pid); - } catch (Exception e) { - Slog.e(TAG, "exception setting interface for pid: " + e); - } + List pids = mNetRequestersPids[netType]; + for (int y=0; y< pids.size(); y++) { + Integer pid = (Integer)pids.get(y); + changed = writePidDns(dnses, pid.intValue()); } } - flushVmDnsCache(); + if (changed) bumpDns(); } } @@ -2574,7 +2641,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { pw.increaseIndent(); for (int net : mPriorityList) { String pidString = net + ": "; - for (Integer pid : mNetRequestersPids[net]) { + for (Object pid : mNetRequestersPids[net]) { pidString = pidString + pid.toString() + ", "; } pw.println(pidString); @@ -3284,10 +3351,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { String domains = buffer.toString().trim(); // Apply DNS changes. + boolean changed = false; synchronized (mDnsLock) { - updateDns("VPN", "VPN", addresses, domains); + changed = updateDns("VPN", "VPN", addresses, domains); mDnsOverridden = true; } + if (changed) { + bumpDns(); + } // Temporarily disable the default proxy. synchronized (mDefaultProxyLock) { From 151eaa6bc12a95f5f90617a891c6db3754d6e23d Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 31 Jan 2013 00:30:13 +0000 Subject: [PATCH 029/296] Revert "Clean up published network condition reporting." In some cases causes grey ICON's. This reverts commit 2587a53c31073d277590cb9a8ae5e3bb58006927 Change-Id: I09f893d03651c3fb9fcb88ee9e5ac7ce6cb6e273 --- .../android/server/ConnectivityService.java | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 5aba7ec649..2ccde3b655 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -194,6 +194,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private int mNetworkPreference; private int mActiveDefaultNetwork = -1; // 0 is full bad, 100 is full good + private int mDefaultInetCondition = 0; private int mDefaultInetConditionPublished = 0; private boolean mInetConditionChangeInFlight = false; private int mDefaultConnectionSequence = 0; @@ -1727,10 +1728,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { mDefaultInetConditionPublished = 0; // we're not connected anymore - if (DBG) { - log("handleDisconnect: net=" + mActiveDefaultNetwork + - ", published condition=" + mDefaultInetConditionPublished); - } intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } } @@ -1921,10 +1918,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); } else { mDefaultInetConditionPublished = 0; - if (DBG) { - log("handleConnectionFailure: net=" + mActiveDefaultNetwork + - ", published condition=" + mDefaultInetConditionPublished); - } intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } } @@ -2069,10 +2062,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { mDefaultInetConditionPublished = 0; mDefaultConnectionSequence++; mInetConditionChangeInFlight = false; - if (DBG) { - log("handleConnect: net=" + newNetType + - ", published condition=" + mDefaultInetConditionPublished); - } // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); } @@ -2723,8 +2712,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { { int netType = msg.arg1; int sequence = msg.arg2; - int condition = (Integer)msg.obj; - handleInetConditionHoldEnd(netType, sequence, condition); + handleInetConditionHoldEnd(netType, sequence); break; } case EVENT_SET_NETWORK_PREFERENCE: @@ -2937,13 +2925,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (VDBG) { log("handleInetConditionChange: net=" + netType + ", condition=" + condition + - " mActiveDefaultNetwork=" + mActiveDefaultNetwork); + ",mActiveDefaultNetwork=" + mActiveDefaultNetwork); } + mDefaultInetCondition = condition; int delay; if (mInetConditionChangeInFlight == false) { if (VDBG) log("handleInetConditionChange: starting a change hold"); // setup a new hold to debounce this - if (condition > 50) { + if (mDefaultInetCondition > 50) { delay = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); } else { @@ -2952,16 +2941,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mInetConditionChangeInFlight = true; mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_INET_CONDITION_HOLD_END, - mActiveDefaultNetwork, mDefaultConnectionSequence, new Integer(condition)), delay); + mActiveDefaultNetwork, mDefaultConnectionSequence), delay); } else { // we've set the new condition, when this hold ends that will get picked up if (VDBG) log("handleInetConditionChange: currently in hold - not setting new end evt"); } } - private void handleInetConditionHoldEnd(int netType, int sequence, int condition) { + private void handleInetConditionHoldEnd(int netType, int sequence) { if (DBG) { - log("handleInetConditionHoldEnd: net=" + netType + ", condition=" + condition); + log("handleInetConditionHoldEnd: net=" + netType + + ", condition=" + mDefaultInetCondition + + ", published condition=" + mDefaultInetConditionPublished); } mInetConditionChangeInFlight = false; @@ -2973,13 +2964,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) log("handleInetConditionHoldEnd: event hold for obsolete network - ignoring"); return; } - + // TODO: Figure out why this optimization sometimes causes a + // change in mDefaultInetCondition to be missed and the + // UI to not be updated. + //if (mDefaultInetConditionPublished == mDefaultInetCondition) { + // if (DBG) log("no change in condition - aborting"); + // return; + //} NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); if (networkInfo.isConnected() == false) { if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring"); return; } - mDefaultInetConditionPublished = condition; + mDefaultInetConditionPublished = mDefaultInetCondition; sendInetConditionBroadcast(networkInfo); return; } From d697aa2e383852df7cafc61458a6c82ef788588b Mon Sep 17 00:00:00 2001 From: Mattias Falk Date: Tue, 23 Aug 2011 14:15:13 +0200 Subject: [PATCH 030/296] Second pass tying into dns cache per interface Set dns servers for secondary nets and attach the processes (pids) that are using the secondary nets to the secondary nets associated dns cache. bug:5465296 Change-Id: I1eaf92d5c6b81d287e9fb2763b3d972d9de34395 --- .../android/server/ConnectivityService.java | 157 +++++------------- 1 file changed, 43 insertions(+), 114 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 7cfa8c2667..8e21246c19 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -183,7 +183,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * A per Net list of the PID's that requested access to the net * used both as a refcount and for per-PID DNS selection */ - private List mNetRequestersPids[]; + private List mNetRequestersPids[]; // priority order of the nettrackers // (excluding dynamically set mNetworkPreference) @@ -199,7 +199,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private int mDefaultConnectionSequence = 0; private Object mDnsLock = new Object(); - private int mNumDnsEntries; private boolean mDnsOverridden = false; private boolean mTestMode; @@ -507,15 +506,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - mNetRequestersPids = new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; + mNetRequestersPids = + (List [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; for (int i : mPriorityList) { - mNetRequestersPids[i] = new ArrayList(); + mNetRequestersPids[i] = new ArrayList(); } mFeatureUsers = new ArrayList(); - mNumDnsEntries = 0; - mTestMode = SystemProperties.get("cm.test.mode").equals("true") && SystemProperties.get("ro.build.type").equals("eng"); @@ -1316,6 +1314,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { Integer currentPid = new Integer(pid); mNetRequestersPids[usedNetworkType].remove(currentPid); reassessPidDns(pid, true); + flushVmDnsCache(); if (mNetRequestersPids[usedNetworkType].size() != 0) { if (VDBG) { log("stopUsingNetworkFeature: net " + networkType + ": " + feature + @@ -1697,9 +1696,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { * in accordance with network preference policies. */ if (!mNetConfigs[prevNetType].isDefault()) { - List pids = mNetRequestersPids[prevNetType]; - for (int i = 0; i pids = mNetRequestersPids[prevNetType]; + for (Integer pid : pids) { // will remove them because the net's no longer connected // need to do this now as only now do we know the pids and // can properly null things that are no longer referenced. @@ -2261,6 +2259,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } if (resetDns) { + flushVmDnsCache(); if (VDBG) log("resetting DNS cache for " + iface); try { mNetd.flushInterfaceDnsCache(iface); @@ -2427,9 +2426,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { * on the highest priority active net which this process requested. * If there aren't any, clear it out */ - private void reassessPidDns(int myPid, boolean doBump) + private void reassessPidDns(int pid, boolean doBump) { - if (VDBG) log("reassessPidDns for pid " + myPid); + if (VDBG) log("reassessPidDns for pid " + pid); + Integer myPid = new Integer(pid); for(int i : mPriorityList) { if (mNetConfigs[i].isDefault()) { continue; @@ -2439,61 +2439,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { !nt.isTeardownRequested()) { LinkProperties p = nt.getLinkProperties(); if (p == null) continue; - List pids = mNetRequestersPids[i]; - for (int j=0; j dnses = p.getDnses(); - writePidDns(dnses, myPid); - if (doBump) { - bumpDns(); - } - return; + if (mNetRequestersPids[i].contains(myPid)) { + try { + mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid); + } catch (Exception e) { + Slog.e(TAG, "exception reasseses pid dns: " + e); } + return; } } } // nothing found - delete - for (int i = 1; ; i++) { - String prop = "net.dns" + i + "." + myPid; - if (SystemProperties.get(prop).length() == 0) { - if (doBump) { - bumpDns(); - } - return; - } - SystemProperties.set(prop, ""); + try { + mNetd.clearDnsInterfaceForPid(pid); + } catch (Exception e) { + Slog.e(TAG, "exception clear interface from pid: " + e); } } - // return true if results in a change - private boolean writePidDns(Collection dnses, int pid) { - int j = 1; - boolean changed = false; - for (InetAddress dns : dnses) { - String dnsString = dns.getHostAddress(); - if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) { - changed = true; - SystemProperties.set("net.dns" + j + "." + pid, dns.getHostAddress()); - } - j++; - } - return changed; - } - - private void bumpDns() { - /* - * Bump the property that tells the name resolver library to reread - * the DNS server list from the properties. - */ - String propVal = SystemProperties.get("net.dnschange"); - int n = 0; - if (propVal.length() != 0) { - try { - n = Integer.parseInt(propVal); - } catch (NumberFormatException e) {} - } - SystemProperties.set("net.dnschange", "" + (n+1)); + private void flushVmDnsCache() { /* * Tell the VMs to toss their DNS caches */ @@ -2512,56 +2476,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Caller must grab mDnsLock. - private boolean updateDns(String network, String iface, + private void updateDnsLocked(String network, String iface, Collection dnses, String domains) { - boolean changed = false; int last = 0; if (dnses.size() == 0 && mDefaultDns != null) { - ++last; - String value = mDefaultDns.getHostAddress(); - if (!value.equals(SystemProperties.get("net.dns1"))) { - if (DBG) { - loge("no dns provided for " + network + " - using " + value); - } - changed = true; - SystemProperties.set("net.dns1", value); + dnses = new ArrayList(); + dnses.add(mDefaultDns); + if (DBG) { + loge("no dns provided for " + network + " - using " + mDefaultDns.getHostAddress()); } - } else { - for (InetAddress dns : dnses) { - ++last; - String key = "net.dns" + last; - String value = dns.getHostAddress(); - if (!changed && value.equals(SystemProperties.get(key))) { - continue; - } - if (VDBG) { - log("adding dns " + value + " for " + network); - } - changed = true; - SystemProperties.set(key, value); - } - } - for (int i = last + 1; i <= mNumDnsEntries; ++i) { - String key = "net.dns" + i; - if (VDBG) log("erasing " + key); - changed = true; - SystemProperties.set(key, ""); - } - mNumDnsEntries = last; - if (SystemProperties.get("net.dns.search").equals(domains) == false) { - SystemProperties.set("net.dns.search", domains); - changed = true; } - if (changed) { - try { - mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); - mNetd.setDefaultInterfaceForDns(iface); - } catch (Exception e) { - if (DBG) loge("exception setting default dns interface: " + e); - } + try { + mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); + mNetd.setDefaultInterfaceForDns(iface); + } catch (Exception e) { + if (DBG) loge("exception setting default dns interface: " + e); } - return changed; } private void handleDnsConfigurationChange(int netType) { @@ -2571,12 +2502,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { LinkProperties p = nt.getLinkProperties(); if (p == null) return; Collection dnses = p.getDnses(); - boolean changed = false; if (mNetConfigs[netType].isDefault()) { String network = nt.getNetworkInfo().getTypeName(); synchronized (mDnsLock) { if (!mDnsOverridden) { - changed = updateDns(network, p.getInterfaceName(), dnses, p.getDomains()); + updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains()); } } } else { @@ -2587,13 +2517,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) loge("exception setting dns servers: " + e); } // set per-pid dns for attached secondary nets - List pids = mNetRequestersPids[netType]; - for (int y=0; y< pids.size(); y++) { - Integer pid = (Integer)pids.get(y); - changed = writePidDns(dnses, pid.intValue()); + List pids = mNetRequestersPids[netType]; + for (Integer pid : pids) { + try { + mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid); + } catch (Exception e) { + Slog.e(TAG, "exception setting interface for pid: " + e); + } } } - if (changed) bumpDns(); + flushVmDnsCache(); } } @@ -2652,7 +2585,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { pw.increaseIndent(); for (int net : mPriorityList) { String pidString = net + ": "; - for (Object pid : mNetRequestersPids[net]) { + for (Integer pid : mNetRequestersPids[net]) { pidString = pidString + pid.toString() + ", "; } pw.println(pidString); @@ -3354,14 +3287,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { String domains = buffer.toString().trim(); // Apply DNS changes. - boolean changed = false; synchronized (mDnsLock) { - changed = updateDns("VPN", "VPN", addresses, domains); + updateDnsLocked("VPN", "VPN", addresses, domains); mDnsOverridden = true; } - if (changed) { - bumpDns(); - } // Temporarily disable the default proxy. synchronized (mDefaultProxyLock) { From e41e3b3c09f606ec94bd24dd3b595d3c648bb717 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 11 Feb 2013 15:25:10 -0800 Subject: [PATCH 031/296] Reintroduce the net.dns system properties Removing these properties broke video playback as they used a custom dns resolver. We'll work together to resolve our resolver issues in the future, but this was the easy fix to get things working again. bug:8173236 Change-Id: I687dae59eda4fc449efc34eed11c3dc88a110ad0 --- .../java/com/android/server/ConnectivityService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index fb81391edd..6efe4c5842 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -200,6 +200,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private int mDefaultConnectionSequence = 0; private Object mDnsLock = new Object(); + private int mNumDnsEntries; private boolean mDnsOverridden = false; private boolean mTestMode; @@ -2479,6 +2480,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); mNetd.setDefaultInterfaceForDns(iface); + for (InetAddress dns : dnses) { + ++last; + String key = "net.dns" + last; + String value = dns.getHostAddress(); + SystemProperties.set(key, value); + } + for (int i = last + 1; i <= mNumDnsEntries; ++i) { + String key = "net.dns" + i; + SystemProperties.set(key, ""); + } + mNumDnsEntries = last; } catch (Exception e) { if (DBG) loge("exception setting default dns interface: " + e); } From 3874bd4930f07ba0515e6bcf4aa9da6e6b5d68eb Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 11 Feb 2013 15:25:10 -0800 Subject: [PATCH 032/296] Reintroduce the net.dns system properties Removing these properties broke video playback as they used a custom dns resolver. We'll work together to resolve our resolver issues in the future, but this was the easy fix to get things working again. bug:8173236 Change-Id: I687dae59eda4fc449efc34eed11c3dc88a110ad0 --- .../java/com/android/server/ConnectivityService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index fb81391edd..6efe4c5842 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -200,6 +200,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private int mDefaultConnectionSequence = 0; private Object mDnsLock = new Object(); + private int mNumDnsEntries; private boolean mDnsOverridden = false; private boolean mTestMode; @@ -2479,6 +2480,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); mNetd.setDefaultInterfaceForDns(iface); + for (InetAddress dns : dnses) { + ++last; + String key = "net.dns" + last; + String value = dns.getHostAddress(); + SystemProperties.set(key, value); + } + for (int i = last + 1; i <= mNumDnsEntries; ++i) { + String key = "net.dns" + i; + SystemProperties.set(key, ""); + } + mNumDnsEntries = last; } catch (Exception e) { if (DBG) loge("exception setting default dns interface: " + e); } From e767d81d8f9e33933d7af3c8e1c13391ec3151fa Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 12 Feb 2013 17:18:25 -0800 Subject: [PATCH 033/296] Fix a permissions probem in ConnectivityManager stopUsingNetworkFeature fails because of new permissions checks in netd. Change-Id: I04cb10d955c9dd9977c460c6c1db0d1910a863ce --- services/java/com/android/server/ConnectivityService.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6efe4c5842..e3a3ca2083 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1315,7 +1315,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (usedNetworkType != networkType) { Integer currentPid = new Integer(pid); mNetRequestersPids[usedNetworkType].remove(currentPid); - reassessPidDns(pid, true); + + final long token = Binder.clearCallingIdentity(); + try { + reassessPidDns(pid, true); + } finally { + Binder.restoreCallingIdentity(token); + } flushVmDnsCache(); if (mNetRequestersPids[usedNetworkType].size() != 0) { if (VDBG) { From 30fe264f5c7b9eda127cbb8a181103240e2b32d0 Mon Sep 17 00:00:00 2001 From: Russell Brenner Date: Tue, 12 Feb 2013 10:03:14 -0800 Subject: [PATCH 034/296] Adjust captive portal test for setup wizard During setup wizard, perform captive portal test without the typical delays. Change-Id: If596948e732966817aae6201440e87e19be0c2f8 --- core/java/android/net/ConnectivityManager.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index a8a68d0e32..000c56c3a4 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -227,6 +227,21 @@ public class ConnectivityManager { */ public static final String EXTRA_ERRORED_TETHER = "erroredArray"; + /** + * Broadcast Action: The captive portal tracker has finished its test. + * Sent only while running Setup Wizard, in lieu of showing a user + * notification. + * @hide + */ + public static final String ACTION_CAPTIVE_PORTAL_TEST_COMPLETED = + "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED"; + /** + * The lookup key for a boolean that indicates whether a captive portal was detected. + * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. + * @hide + */ + public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal"; + /** * The absence of APN.. * @hide From 0ded63c2ffdc282e22a78d6665fc0b74997d6d08 Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Thu, 14 Feb 2013 10:18:38 -0800 Subject: [PATCH 035/296] KeyStore: stop using state() Change-Id: I721974fd95f8d1ab06a3fd1bbb4c9b4d9d1d7752 --- services/java/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cccaf1cc48..e5cfdf6a9f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3384,7 +3384,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Tear down existing lockdown if profile was removed mLockdownEnabled = LockdownVpnTracker.isEnabled(); if (mLockdownEnabled) { - if (mKeyStore.state() != KeyStore.State.UNLOCKED) { + if (!mKeyStore.isUnlocked()) { Slog.w(TAG, "KeyStore locked; unable to create LockdownTracker"); return false; } From 760c62064b4598cfeb1a834392c54b64f3bea5c4 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 31 Jan 2013 17:22:26 -0800 Subject: [PATCH 036/296] Migrate to using Mockito directly. Change-Id: I1fcc5d1a780f5831bd6685f0735d4c0c6d245735 --- .../android/server/ConnectivityService.java | 15 ++++-------- .../server/ConnectivityServiceTest.java | 23 +++++++++---------- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index c31cde7094..6d817a17e7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -16,7 +16,6 @@ package com.android.server; -import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; @@ -32,7 +31,6 @@ import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; -import android.app.Activity; import android.bluetooth.BluetoothTetheringDataTracker; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -88,7 +86,6 @@ import android.provider.Settings; import android.security.Credentials; import android.security.KeyStore; import android.text.TextUtils; -import android.util.EventLog; import android.util.Slog; import android.util.SparseIntArray; @@ -3336,7 +3333,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public boolean updateLockdownVpn() { - enforceSystemUid(); + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + Slog.w(TAG, "Lockdown VPN only available to AID_SYSTEM"); + return false; + } // Tear down existing lockdown if profile was removed mLockdownEnabled = LockdownVpnTracker.isEnabled(); @@ -3387,11 +3387,4 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalStateException("Unavailable in lockdown mode"); } } - - private static void enforceSystemUid() { - final int uid = Binder.getCallingUid(); - if (uid != Process.SYSTEM_UID) { - throw new SecurityException("Only available to AID_SYSTEM"); - } - } } diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 93ea6a236b..4ae013bad1 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -21,16 +21,15 @@ import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.NetworkStateTracker.EVENT_STATE_CHANGED; -import static com.google.testing.littlemock.LittleMock.anyInt; -import static com.google.testing.littlemock.LittleMock.createCaptor; -import static com.google.testing.littlemock.LittleMock.doNothing; -import static com.google.testing.littlemock.LittleMock.doReturn; -import static com.google.testing.littlemock.LittleMock.doThrow; -import static com.google.testing.littlemock.LittleMock.eq; -import static com.google.testing.littlemock.LittleMock.isA; -import static com.google.testing.littlemock.LittleMock.mock; -import static com.google.testing.littlemock.LittleMock.reset; -import static com.google.testing.littlemock.LittleMock.verify; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Matchers.isA; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.verify; import android.content.Context; import android.net.INetworkPolicyManager; @@ -48,7 +47,7 @@ import android.test.suitebuilder.annotation.LargeTest; import android.util.Log; import android.util.LogPrinter; -import com.google.testing.littlemock.ArgumentCaptor; +import org.mockito.ArgumentCaptor; import java.net.InetAddress; import java.util.concurrent.Future; @@ -128,7 +127,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { doReturn(mWifi.tracker) .when(mNetFactory).createTracker(eq(TYPE_WIFI), isA(NetworkConfig.class)); - final ArgumentCaptor trackerHandler = createCaptor(); + final ArgumentCaptor trackerHandler = ArgumentCaptor.forClass(Handler.class); doNothing().when(mMobile.tracker) .startMonitoring(isA(Context.class), trackerHandler.capture()); From ee9275b9c4f244ab1b9eba07f6eb2531983a22df Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Wed, 20 Feb 2013 18:21:19 -0800 Subject: [PATCH 037/296] Improve notification UI for lockdown VPN. Bug: 7064111 Change-Id: I9554f6a426697b4abeb2ddd0827d314920e88ed6 --- core/java/android/net/ConnectivityManager.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 000c56c3a4..1f44e49f2e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -70,6 +70,7 @@ public class ConnectivityManager { * For a disconnect event, the boolean extra EXTRA_NO_CONNECTIVITY * is set to {@code true} if there are no connected networks at all. */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE"; /** @@ -78,6 +79,7 @@ public class ConnectivityManager { * * @hide */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String CONNECTIVITY_ACTION_IMMEDIATE = "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE"; @@ -198,6 +200,7 @@ public class ConnectivityManager { * the network and it's condition. * @hide */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String INET_CONDITION_ACTION = "android.net.conn.INET_CONDITION_ACTION"; @@ -206,6 +209,7 @@ public class ConnectivityManager { * TODO - finish the doc * @hide */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED"; @@ -233,6 +237,7 @@ public class ConnectivityManager { * notification. * @hide */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_CAPTIVE_PORTAL_TEST_COMPLETED = "android.net.conn.CAPTIVE_PORTAL_TEST_COMPLETED"; /** From faa4b403d9a09a77189cb738e98d65f26af2610a Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 15 Feb 2013 10:56:35 -0800 Subject: [PATCH 038/296] Improve ConnectivityManager docs Also fix some permission problems. bug:5738328 Change-Id: Ib32c223f425b1fc03b8cce528456bcb50b540fdf --- .../java/android/net/ConnectivityManager.java | 458 +++++++++++++++--- .../android/server/ConnectivityService.java | 8 +- 2 files changed, 389 insertions(+), 77 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1f44e49f2e..3a04c271ca 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -62,7 +62,7 @@ public class ConnectivityManager { * NetworkInfo for the new network is also passed as an extra. This lets * any receivers of the broadcast know that they should not necessarily * tell the user that no data traffic will be possible. Instead, the - * reciever should expect another broadcast soon, indicating either that + * receiver should expect another broadcast soon, indicating either that * the failover attempt succeeded (and so there is still overall data * connectivity), or that the failover attempt failed, meaning that all * connectivity has been lost. @@ -151,8 +151,8 @@ public class ConnectivityManager { /** * Broadcast action to indicate the change of data activity status * (idle or active) on a network in a recent period. - * The network becomes active when data transimission is started, or - * idle if there is no data transimition for a period of time. + * The network becomes active when data transmission is started, or + * idle if there is no data transmission for a period of time. * {@hide} */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @@ -205,8 +205,12 @@ public class ConnectivityManager { "android.net.conn.INET_CONDITION_ACTION"; /** - * Broadcast Action: A tetherable connection has come or gone - * TODO - finish the doc + * Broadcast Action: A tetherable connection has come or gone. + * Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER}, + * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER} and + * {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate + * the current state of tethering. Each include a list of + * interface names in that state (may be empty). * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) @@ -215,19 +219,23 @@ public class ConnectivityManager { /** * @hide - * gives a String[] + * gives a String[] listing all the interfaces configured for + * tethering and currently available for tethering. */ public static final String EXTRA_AVAILABLE_TETHER = "availableArray"; /** * @hide - * gives a String[] + * gives a String[] listing all the interfaces currently tethered + * (ie, has dhcp support and packets potentially forwarded/NATed) */ public static final String EXTRA_ACTIVE_TETHER = "activeArray"; /** * @hide - * gives a String[] + * gives a String[] listing all the interfaces we tried to tether and + * failed. Use {@link #getLastTetherError} to find the error code + * for any interfaces listed here. */ public static final String EXTRA_ERRORED_TETHER = "erroredArray"; @@ -248,61 +256,63 @@ public class ConnectivityManager { public static final String EXTRA_IS_CAPTIVE_PORTAL = "captivePortal"; /** - * The absence of APN.. + * The absence of a connection type. * @hide */ public static final int TYPE_NONE = -1; /** - * The Default Mobile data connection. When active, all data traffic - * will use this connection by default. + * The Mobile data connection. When active, all data traffic + * will use this network type's interface by default + * (it has a default route) */ public static final int TYPE_MOBILE = 0; /** - * The Default WIFI data connection. When active, all data traffic - * will use this connection by default. + * The WIFI data connection. When active, all data traffic + * will use this network type's interface by default + * (it has a default route). */ public static final int TYPE_WIFI = 1; /** - * An MMS-specific Mobile data connection. This connection may be the - * same as {@link #TYPE_MOBILE} but it may be different. This is used - * by applications needing to talk to the carrier's Multimedia Messaging - * Service servers. It may coexist with default data connections. + * An MMS-specific Mobile data connection. This network type may use the + * same network interface as {@link #TYPE_MOBILE} or it may use a different + * one. This is used by applications needing to talk to the carrier's + * Multimedia Messaging Service servers. */ public static final int TYPE_MOBILE_MMS = 2; /** - * A SUPL-specific Mobile data connection. This connection may be the - * same as {@link #TYPE_MOBILE} but it may be different. This is used - * by applications needing to talk to the carrier's Secure User Plane - * Location servers for help locating the device. It may coexist with - * default data connections. + * A SUPL-specific Mobile data connection. This network type may use the + * same network interface as {@link #TYPE_MOBILE} or it may use a different + * one. This is used by applications needing to talk to the carrier's + * Secure User Plane Location servers for help locating the device. */ public static final int TYPE_MOBILE_SUPL = 3; /** - * A DUN-specific Mobile data connection. This connection may be the - * same as {@link #TYPE_MOBILE} but it may be different. This is used - * by applicaitons performing a Dial Up Networking bridge so that - * the carrier is aware of DUN traffic. It may coexist with default data - * connections. + * A DUN-specific Mobile data connection. This network type may use the + * same network interface as {@link #TYPE_MOBILE} or it may use a different + * one. This is sometimes by the system when setting up an upstream connection + * for tethering so that the carrier is aware of DUN traffic. */ public static final int TYPE_MOBILE_DUN = 4; /** - * A High Priority Mobile data connection. This connection is typically - * the same as {@link #TYPE_MOBILE} but the routing setup is different. - * Only requesting processes will have access to the Mobile DNS servers - * and only IP's explicitly requested via {@link #requestRouteToHost} - * will route over this interface if a default route exists. + * A High Priority Mobile data connection. This network type uses the + * same network interface as {@link #TYPE_MOBILE} but the routing setup + * is different. Only requesting processes will have access to the + * Mobile DNS servers and only IP's explicitly requested via {@link #requestRouteToHost} + * will route over this interface if no default route exists. */ public static final int TYPE_MOBILE_HIPRI = 5; /** - * The Default WiMAX data connection. When active, all data traffic - * will use this connection by default. + * The WiMAX data connection. When active, all data traffic + * will use this network type's interface by default + * (it has a default route). */ public static final int TYPE_WIMAX = 6; /** - * The Default Bluetooth data connection. When active, all data traffic - * will use this connection by default. + * The Bluetooth data connection. When active, all data traffic + * will use this network type's interface by default + * (it has a default route). */ public static final int TYPE_BLUETOOTH = 7; @@ -312,25 +322,26 @@ public class ConnectivityManager { public static final int TYPE_DUMMY = 8; /** - * The Default Ethernet data connection. When active, all data traffic - * will use this connection by default. + * The Ethernet data connection. When active, all data traffic + * will use this network type's interface by default + * (it has a default route). */ public static final int TYPE_ETHERNET = 9; /** - * Over the air Adminstration. + * Over the air Administration. * {@hide} */ public static final int TYPE_MOBILE_FOTA = 10; /** - * IP Multimedia Subsystem + * IP Multimedia Subsystem. * {@hide} */ public static final int TYPE_MOBILE_IMS = 11; /** - * Carrier Branded Services + * Carrier Branded Services. * {@hide} */ public static final int TYPE_MOBILE_CBS = 12; @@ -354,7 +365,7 @@ public class ConnectivityManager { * * @deprecated Since we support so many more networks now, the single * network default network preference can't really express - * the heirarchy. Instead, the default is defined by the + * the hierarchy. Instead, the default is defined by the * networkAttributes in config.xml. You can determine * the current value by calling {@link #getNetworkPreference()} * from an App. @@ -364,7 +375,11 @@ public class ConnectivityManager { /** * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in - * milliseconds. + * milliseconds. This was introduced because IPv6 routes seem to take a + * moment to settle - trying network activity before the routes are adjusted + * can lead to packets using the wrong interface or having the wrong IP address. + * This delay is a bit crude, but in the future hopefully we will have kernel + * notifications letting us know when it's safe to use the new network. * * @hide */ @@ -372,11 +387,23 @@ public class ConnectivityManager { private final IConnectivityManager mService; + /** + * Tests if a given integer represents a valid network type. + * @param networkType the type to be tested + * @return a boolean. {@code true} if the type is valid, else {@code false} + */ public static boolean isNetworkTypeValid(int networkType) { return networkType >= 0 && networkType <= MAX_NETWORK_TYPE; } - /** {@hide} */ + /** + * Returns a non-localized string representing a given network type. + * ONLY used for debugging output. + * @param type the type needing naming + * @return a String for the given type, or a string version of the type ("87") + * if no name is known. + * {@hide} + */ public static String getNetworkTypeName(int type) { switch (type) { case TYPE_MOBILE: @@ -412,7 +439,13 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * Checks if a given type uses the cellular data connection. + * This should be replaced in the future by a network property. + * @param networkType the type to check + * @return a boolean - {@code true} if uses cellular network, else {@code false} + * {@hide} + */ public static boolean isNetworkTypeMobile(int networkType) { switch (networkType) { case TYPE_MOBILE: @@ -429,6 +462,17 @@ public class ConnectivityManager { } } + /** + * Specifies the preferred network type. When the device has more + * than one type available the preferred network type will be used. + * Note that this made sense when we only had 2 network types, + * but with more and more default networks we need an array to list + * their ordering. This will be deprecated soon. + * + * @param preference the network type to prefer over all others. It is + * unspecified what happens to the old preferred network in the + * overall ordering. + */ public void setNetworkPreference(int preference) { try { mService.setNetworkPreference(preference); @@ -436,6 +480,17 @@ public class ConnectivityManager { } } + /** + * Retrieves the current preferred network type. + * Note that this made sense when we only had 2 network types, + * but with more and more default networks we need an array to list + * their ordering. This will be deprecated soon. + * + * @return an integer representing the preferred network type + * + *

This method requires the caller to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + */ public int getNetworkPreference() { try { return mService.getNetworkPreference(); @@ -445,11 +500,16 @@ public class ConnectivityManager { } /** - * Returns details about the currently active data network. When connected, - * this network is the default route for outgoing connections. You should - * always check {@link NetworkInfo#isConnected()} before initiating network - * traffic. This may return {@code null} when no networks are available. - *

This method requires the caller to hold the permission + * Returns details about the currently active default data network. When + * connected, this network is the default route for outgoing connections. + * You should always check {@link NetworkInfo#isConnected()} before initiating + * network traffic. This may return {@code null} when there is no default + * network. + * + * @return a {@link NetworkInfo} object for the current default network + * or {@code null} if no network default network is currently active + * + *

This method requires the call to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. */ public NetworkInfo getActiveNetworkInfo() { @@ -460,7 +520,19 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * Returns details about the currently active default data network + * for a given uid. This is for internal use only to avoid spying + * other apps. + * + * @return a {@link NetworkInfo} object for the current default network + * for the given uid or {@code null} if no default network is + * available for the specified uid. + * + *

This method requires the caller to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL} + * {@hide} + */ public NetworkInfo getActiveNetworkInfoForUid(int uid) { try { return mService.getActiveNetworkInfoForUid(uid); @@ -469,6 +541,19 @@ public class ConnectivityManager { } } + /** + * Returns connection status information about a particular + * network type. + * + * @param networkType integer specifying which networkType in + * which you're interested. + * @return a {@link NetworkInfo} object for the requested + * network type or {@code null} if the type is not + * supported by the device. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + */ public NetworkInfo getNetworkInfo(int networkType) { try { return mService.getNetworkInfo(networkType); @@ -477,6 +562,16 @@ public class ConnectivityManager { } } + /** + * Returns connection status information about all network + * types supported by the device. + * + * @return an array of {@link NetworkInfo} objects. Check each + * {@link NetworkInfo#getType} for which type each applies. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + */ public NetworkInfo[] getAllNetworkInfo() { try { return mService.getAllNetworkInfo(); @@ -485,7 +580,17 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * Returns the IP information for the current default network. + * + * @return a {@link LinkProperties} object describing the IP info + * for the current default network, or {@code null} if there + * is no current default network. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * {@hide} + */ public LinkProperties getActiveLinkProperties() { try { return mService.getActiveLinkProperties(); @@ -494,7 +599,18 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * Returns the IP information for a given network type. + * + * @param networkType the network type of interest. + * @return a {@link LinkProperties} object describing the IP info + * for the given networkType, or {@code null} if there is + * no current default network. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * {@hide} + */ public LinkProperties getLinkProperties(int networkType) { try { return mService.getLinkProperties(networkType); @@ -503,7 +619,18 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * Tells each network type to set its radio power state as directed. + * + * @param turnOn a boolean, {@code true} to turn the radios on, + * {@code false} to turn them off. + * @return a boolean, {@code true} indicating success. All network types + * will be tried, even if some fail. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. + * {@hide} + */ public boolean setRadios(boolean turnOn) { try { return mService.setRadios(turnOn); @@ -512,7 +639,18 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * Tells a given networkType to set its radio power state as directed. + * + * @param networkType the int networkType of interest. + * @param turnOn a boolean, {@code true} to turn the radio on, + * {@code} false to turn it off. + * @return a boolean, {@code true} indicating success. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. + * {@hide} + */ public boolean setRadio(int networkType, boolean turnOn) { try { return mService.setRadio(networkType, turnOn); @@ -647,6 +785,9 @@ public class ConnectivityManager { * network is active. Quota status can change rapidly, so these values * shouldn't be cached. * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * * @hide */ public NetworkQuotaInfo getActiveNetworkQuotaInfo() { @@ -661,6 +802,9 @@ public class ConnectivityManager { * Gets the value of the setting for enabling Mobile data. * * @return Whether mobile data is enabled. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * @hide */ public boolean getMobileDataEnabled() { @@ -674,8 +818,8 @@ public class ConnectivityManager { /** * Sets the persisted value for enabling/disabling Mobile data. * - * @param enabled Whether the mobile data connection should be - * used or not. + * @param enabled Whether the user wants the mobile data connection used + * or not. * @hide */ public void setMobileDataEnabled(boolean enabled) { @@ -698,6 +842,13 @@ public class ConnectivityManager { } /** + * Get the set of tetherable, available interfaces. This list is limited by + * device configuration and current interface existence. + * + * @return an array of 0 or more Strings of tetherable interface names. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public String[] getTetherableIfaces() { @@ -709,6 +860,12 @@ public class ConnectivityManager { } /** + * Get the set of tethered interfaces. + * + * @return an array of 0 or more String of currently tethered interface names. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public String[] getTetheredIfaces() { @@ -720,6 +877,18 @@ public class ConnectivityManager { } /** + * Get the set of interface names which attempted to tether but + * failed. Re-attempting to tether may cause them to reset to the Tethered + * state. Alternatively, causing the interface to be destroyed and recreated + * may cause them to reset to the available state. + * {@link ConnectivityManager#getLastTetherError} can be used to get more + * information on the cause of the errors. + * + * @return an array of 0 or more String indicating the interface names + * which failed to tether. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public String[] getTetheringErroredIfaces() { @@ -731,7 +900,19 @@ public class ConnectivityManager { } /** - * @return error A TETHER_ERROR value indicating success or failure type + * Attempt to tether the named interface. This will setup a dhcp server + * on the interface, forward and NAT IP packets and forward DNS requests + * to the best active upstream network interface. Note that if no upstream + * IP network interface is available, dhcp will still run and traffic will be + * allowed between the tethered devices and this device, though upstream net + * access will of course fail until an upstream network interface becomes + * active. + * + * @param iface the interface name to tether. + * @return error a {@code TETHER_ERROR} value indicating success or failure type + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ public int tether(String iface) { @@ -743,7 +924,13 @@ public class ConnectivityManager { } /** - * @return error A TETHER_ERROR value indicating success or failure type + * Stop tethering the named interface. + * + * @param iface the interface name to untether. + * @return error a {@code TETHER_ERROR} value indicating success or failure type + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ public int untether(String iface) { @@ -755,6 +942,14 @@ public class ConnectivityManager { } /** + * Check if the device allows for tethering. It may be disabled via + * {@code ro.tether.denied} system property, {@link Settings#TETHER_SUPPORTED} or + * due to device configuration. + * + * @return a boolean - {@code true} indicating Tethering is supported. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public boolean isTetheringSupported() { @@ -766,6 +961,15 @@ public class ConnectivityManager { } /** + * Get the list of regular expressions that define any tetherable + * USB network interfaces. If USB tethering is not supported by the + * device, this list should be empty. + * + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable usb interfaces. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public String[] getTetherableUsbRegexs() { @@ -777,6 +981,15 @@ public class ConnectivityManager { } /** + * Get the list of regular expressions that define any tetherable + * Wifi network interfaces. If Wifi tethering is not supported by the + * device, this list should be empty. + * + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable wifi interfaces. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public String[] getTetherableWifiRegexs() { @@ -788,6 +1001,15 @@ public class ConnectivityManager { } /** + * Get the list of regular expressions that define any tetherable + * Bluetooth network interfaces. If Bluetooth tethering is not supported by the + * device, this list should be empty. + * + * @return an array of 0 or more regular expression Strings defining + * what interfaces are considered tetherable bluetooth interfaces. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public String[] getTetherableBluetoothRegexs() { @@ -799,6 +1021,17 @@ public class ConnectivityManager { } /** + * Attempt to both alter the mode of USB and Tethering of USB. A + * utility method to deal with some of the complexity of USB - will + * attempt to switch to Rndis and subsequently tether the resulting + * interface on {@code true} or turn off tethering and switch off + * Rndis on {@code false}. + * + * @param enable a boolean - {@code true} to enable tethering + * @return error a {@code TETHER_ERROR} value indicating success or failure type + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ public int setUsbTethering(boolean enable) { @@ -833,9 +1066,15 @@ public class ConnectivityManager { public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; /** - * @param iface The name of the interface we're interested in + * Get a more detailed error code after a Tethering or Untethering + * request asynchronously failed. + * + * @param iface The name of the interface of interest * @return error The error code of the last error tethering or untethering the named * interface + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public int getLastTetherError(String iface) { @@ -847,9 +1086,16 @@ public class ConnectivityManager { } /** - * Ensure the device stays awake until we connect with the next network - * @param forWhome The name of the network going down for logging purposes + * Try to ensure the device stays awake until we connect with the next network. + * Actually just holds a wakelock for a number of seconds while we try to connect + * to any default networks. This will expire if the timeout passes or if we connect + * to a default after this is called. For internal use only. + * + * @param forWhom the name of the network going down for logging purposes * @return {@code true} on success, {@code false} on failure + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. * {@hide} */ public boolean requestNetworkTransitionWakelock(String forWhom) { @@ -862,8 +1108,14 @@ public class ConnectivityManager { } /** + * Report network connectivity status. This is currently used only + * to alter status bar UI. + * * @param networkType The type of network you want to report on * @param percentage The quality of the connection 0 is bad, 100 is good + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#STATUS_BAR}. * {@hide} */ public void reportInetCondition(int networkType, int percentage) { @@ -874,7 +1126,16 @@ public class ConnectivityManager { } /** - * @param proxyProperties The definition for the new global http proxy + * Set a network-independent global http proxy. This is not normally what you want + * for typical HTTP proxies - they are general network dependent. However if you're + * doing something unusual like general internal filtering this may be useful. On + * a private network where the proxy is not accessible, you may break HTTP using this. + * + * @param proxyProperties The a {@link ProxyProperites} object defining the new global + * HTTP proxy. A {@code null} value will clear the global HTTP proxy. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ public void setGlobalProxy(ProxyProperties p) { @@ -885,7 +1146,13 @@ public class ConnectivityManager { } /** - * @return proxyProperties for the current global proxy + * Retrieve any network-independent global HTTP proxy. + * + * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null} + * if no global HTTP proxy is set. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public ProxyProperties getGlobalProxy() { @@ -897,7 +1164,14 @@ public class ConnectivityManager { } /** - * @return proxyProperties for the current proxy (global if set, network specific if not) + * Get the HTTP proxy settings for the current default network. Note that + * if a global proxy is set, it will override any per-network setting. + * + * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no + * HTTP proxy is active. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ public ProxyProperties getProxy() { @@ -909,8 +1183,15 @@ public class ConnectivityManager { } /** + * Sets a secondary requirement bit for the given networkType. + * This requirement bit is generally under the control of the carrier + * or its agents and is not directly controlled by the user. + * * @param networkType The network who's dependence has changed - * @param met Boolean - true if network use is ok, false if not + * @param met Boolean - true if network use is OK, false if not + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. * {@hide} */ public void setDataDependency(int networkType, boolean met) { @@ -924,11 +1205,15 @@ public class ConnectivityManager { * Returns true if the hardware supports the given network type * else it returns false. This doesn't indicate we have coverage * or are authorized onto a network, just whether or not the - * hardware supports it. For example a gsm phone without a sim - * should still return true for mobile data, but a wifi only tablet - * would return false. - * @param networkType The nework type we'd like to check - * @return true if supported, else false + * hardware supports it. For example a GSM phone without a SIM + * should still return {@code true} for mobile data, but a wifi only + * tablet would return {@code false}. + * + * @param networkType The network type we'd like to check + * @return {@code true} if supported, else {@code false} + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * @hide */ public boolean isNetworkSupported(int networkType) { @@ -941,9 +1226,16 @@ public class ConnectivityManager { /** * Returns if the currently active data network is metered. A network is * classified as metered when the user is sensitive to heavy data usage on - * that connection. You should check this before doing large data transfers, - * and warn the user or delay the operation until another network is - * available. + * that connection due to monetary costs, data limitations or + * battery/performance issues. You should check this before doing large + * data transfers, and warn the user or delay the operation until another + * network is available. + * + * @return {@code true} if large transfers should be avoided, otherwise + * {@code false}. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. */ public boolean isActiveNetworkMetered() { try { @@ -953,7 +1245,15 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * If the LockdownVpn mechanism is enabled, updates the vpn + * with a reload of its profile. + * + * @return a boolean with {@code} indicating success + * + *

This method can only be called by the system UID + * {@hide} + */ public boolean updateLockdownVpn() { try { return mService.updateLockdownVpn(); @@ -963,6 +1263,14 @@ public class ConnectivityManager { } /** + * Signal that the captive portal check on the indicated network + * is complete and we can turn the network on for general use. + * + * @param info the {@link NetworkInfo} object for the networkType + * in question. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. * {@hide} */ public void captivePortalCheckComplete(NetworkInfo info) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6d817a17e7..7abd530b27 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1823,6 +1823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public void sendConnectedBroadcast(NetworkInfo info) { + enforceConnectivityInternalPermission(); sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } @@ -2107,6 +2108,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** @hide */ public void captivePortalCheckComplete(NetworkInfo info) { + enforceConnectivityInternalPermission(); mNetTrackers[info.getType()].captivePortalCheckComplete(); } @@ -2365,7 +2367,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system * wide use */ - public void updateNetworkSettings(NetworkStateTracker nt) { + private void updateNetworkSettings(NetworkStateTracker nt) { String key = nt.getTcpBufferSizesPropName(); String bufferSizes = key == null ? null : SystemProperties.get(key); @@ -2844,7 +2846,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public int setUsbTethering(boolean enable) { - enforceTetherAccessPermission(); + enforceTetherChangePermission(); if (isTetheringSupported()) { return mTethering.setUsbTethering(enable); } else { @@ -2997,6 +2999,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public ProxyProperties getProxy() { + enforceAccessPermission(); synchronized (mDefaultProxyLock) { return mDefaultProxyDisabled ? null : mDefaultProxy; } @@ -3048,6 +3051,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public ProxyProperties getGlobalProxy() { + enforceAccessPermission(); synchronized (mGlobalProxyLock) { return mGlobalProxy; } From 0e0ae8a849a052ff9e01b82f3710ddba13f7eb4d Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 22 Feb 2013 14:57:00 -0800 Subject: [PATCH 039/296] Remove two new permission checks These checks while technically reasonable are a hard to swallow API change that may break existing apps and pragmatically serves no purpose: the protected data is available in publicly readable java VM properties. Change-Id: I522c493c2604a33e28d99e2be31054326c9a8323 --- .../java/com/android/server/ConnectivityService.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 7abd530b27..5e4855b360 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2999,7 +2999,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public ProxyProperties getProxy() { - enforceAccessPermission(); + // this information is already available as a world read/writable jvm property + // so this API change wouldn't have a benifit. It also breaks the passing + // of proxy info to all the JVMs. + // enforceAccessPermission(); synchronized (mDefaultProxyLock) { return mDefaultProxyDisabled ? null : mDefaultProxy; } @@ -3051,7 +3054,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public ProxyProperties getGlobalProxy() { - enforceAccessPermission(); + // this information is already available as a world read/writable jvm property + // so this API change wouldn't have a benifit. It also breaks the passing + // of proxy info to all the JVMs. + // enforceAccessPermission(); synchronized (mGlobalProxyLock) { return mGlobalProxy; } From db44d2ca9a9a0a29c35de5f8041bcfee886e248f Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Thu, 28 Feb 2013 16:57:58 -0800 Subject: [PATCH 040/296] Allow loopback traffic in lockdown mode. Bug: 8245184 Change-Id: If993e3d6f5c7ce5970bfe701074c85b9245aa2aa --- services/java/com/android/server/ConnectivityService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 5e4855b360..3257d2cb3b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3382,6 +3382,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { if (tracker != null) { mNetd.setFirewallEnabled(true); + mNetd.setFirewallInterfaceRule("lo", true); mLockdownTracker = tracker; mLockdownTracker.init(); } else { From e610dd3e5881ef7151597e7f34c84a6d293e0e21 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 7 Mar 2013 10:04:15 -0800 Subject: [PATCH 041/296] Add default route constants to RouteInfo. Bug: 8276725 Change-Id: I9c3ad7393430de9275f5b1c0189a94e5a27975fc --- core/java/android/net/RouteInfo.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 112e14397e..0c84f78ef6 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -45,6 +45,18 @@ public class RouteInfo implements Parcelable { private final boolean mIsDefault; private final boolean mIsHost; + /** + * The IPv4 default route. + */ + public static final RouteInfo IPV4_DEFAULT = new RouteInfo( + new LinkAddress(Inet4Address.ANY, 0)); + + /** + * The IPv6 default route. + */ + public static final RouteInfo IPV6_DEFAULT = new RouteInfo( + new LinkAddress(Inet6Address.ANY, 0)); + public RouteInfo(LinkAddress destination, InetAddress gateway) { if (destination == null) { if (gateway != null) { From 18fb57af466dd3512941ea6a8eccbbb6bb38929c Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 7 Mar 2013 20:11:18 +0000 Subject: [PATCH 042/296] Revert "Add default route constants to RouteInfo." This reverts commit e610dd3e5881ef7151597e7f34c84a6d293e0e21 Change-Id: Ide6d7f3b935da41477b736ef0ef20ec9872563e1 --- core/java/android/net/RouteInfo.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 0c84f78ef6..112e14397e 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -45,18 +45,6 @@ public class RouteInfo implements Parcelable { private final boolean mIsDefault; private final boolean mIsHost; - /** - * The IPv4 default route. - */ - public static final RouteInfo IPV4_DEFAULT = new RouteInfo( - new LinkAddress(Inet4Address.ANY, 0)); - - /** - * The IPv6 default route. - */ - public static final RouteInfo IPV6_DEFAULT = new RouteInfo( - new LinkAddress(Inet6Address.ANY, 0)); - public RouteInfo(LinkAddress destination, InetAddress gateway) { if (destination == null) { if (gateway != null) { From 73b9785a1553de58b2414bd458b16a472a933483 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 8 Mar 2013 11:30:39 -0800 Subject: [PATCH 043/296] RouteInfo changes. - Add the interface name. - Fix a bug where a default route would match an address of another protocol (e.g., 0.0.0.0/0 would match 2001::). - Tweak the hashCode method. - Write a unit test. Change-Id: Ida8266de440a9b1d9eaa132f182b9f1ce8978c44 --- core/java/android/net/LinkProperties.java | 25 ++- core/java/android/net/RouteInfo.java | 72 +++++-- .../src/android/net/RouteInfoTest.java | 180 ++++++++++++++++++ 3 files changed, 262 insertions(+), 15 deletions(-) create mode 100644 core/tests/coretests/src/android/net/RouteInfoTest.java diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index b9362dabf2..ec8d77e757 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -92,6 +92,11 @@ public class LinkProperties implements Parcelable { public void setInterfaceName(String iface) { mIfaceName = iface; + ArrayList newRoutes = new ArrayList(mRoutes.size()); + for (RouteInfo route : mRoutes) { + newRoutes.add(routeWithInterface(route)); + } + mRoutes = newRoutes; } public String getInterfaceName() { @@ -130,9 +135,25 @@ public class LinkProperties implements Parcelable { mDomains = domains; } - public void addRoute(RouteInfo route) { - if (route != null) mRoutes.add(route); + private RouteInfo routeWithInterface(RouteInfo route) { + return new RouteInfo( + route.getDestination(), + route.getGateway(), + mIfaceName); } + + public void addRoute(RouteInfo route) { + if (route != null) { + String routeIface = route.getInterface(); + if (routeIface != null && !routeIface.equals(mIfaceName)) { + throw new IllegalStateException( + "Route added with non-matching interface: " + routeIface + + " vs. mIfaceName"); + } + mRoutes.add(routeWithInterface(route)); + } + } + public Collection getRoutes() { return Collections.unmodifiableCollection(mRoutes); } diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 112e14397e..46b6cbb557 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -29,6 +29,17 @@ import java.util.Collection; /** * A simple container for route information. * + * In order to be used, a route must have a destination prefix and: + * + * - A gateway address (next-hop, for gatewayed routes), or + * - An interface (for directly-connected routes), or + * - Both a gateway and an interface. + * + * This class does not enforce these constraints because there is code that + * uses RouteInfo objects to store directly-connected routes without interfaces. + * Such objects cannot be used directly, but can be put into a LinkProperties + * object which then specifies the interface. + * * @hide */ public class RouteInfo implements Parcelable { @@ -42,10 +53,30 @@ public class RouteInfo implements Parcelable { */ private final InetAddress mGateway; + /** + * The interface for this route. + */ + private final String mInterface; + private final boolean mIsDefault; private final boolean mIsHost; - public RouteInfo(LinkAddress destination, InetAddress gateway) { + /** + * Constructs a RouteInfo object. + * + * If @destination is null, then @gateway must be specified and the + * constructed route is either the IPv4 default route 0.0.0.0 + * if @gateway is an instance of {@link Inet4Address}, or the IPv6 default + * route ::/0 if @gateway is an instance of + * {@link Inet6Address}. + * + * @destination and @gateway may not both be null. + * + * @param destination the destination prefix + * @param gateway the IP address to route packets through + * @param iface the interface name to send packets on + */ + public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { if (destination == null) { if (gateway != null) { if (gateway instanceof Inet4Address) { @@ -55,7 +86,8 @@ public class RouteInfo implements Parcelable { } } else { // no destination, no gateway. invalid. - throw new RuntimeException("Invalid arguments passed in."); + throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," + + destination); } } if (gateway == null) { @@ -68,16 +100,21 @@ public class RouteInfo implements Parcelable { mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); mGateway = gateway; + mInterface = iface; mIsDefault = isDefault(); mIsHost = isHost(); } + public RouteInfo(LinkAddress destination, InetAddress gateway) { + this(destination, gateway, null); + } + public RouteInfo(InetAddress gateway) { - this(null, gateway); + this(null, gateway, null); } public RouteInfo(LinkAddress host) { - this(host, null); + this(host, null, null); } public static RouteInfo makeHostRoute(InetAddress host) { @@ -119,6 +156,10 @@ public class RouteInfo implements Parcelable { return mGateway; } + public String getInterface() { + return mInterface; + } + public boolean isDefaultRoute() { return mIsDefault; } @@ -153,6 +194,8 @@ public class RouteInfo implements Parcelable { dest.writeByte((byte) 1); dest.writeByteArray(mGateway.getAddress()); } + + dest.writeString(mInterface); } @Override @@ -171,14 +214,19 @@ public class RouteInfo implements Parcelable { target.getGateway() == null : mGateway.equals(target.getGateway()); - return sameDestination && sameAddress + boolean sameInterface = (mInterface == null) ? + target.getInterface() == null + : mInterface.equals(target.getInterface()); + + return sameDestination && sameAddress && sameInterface && mIsDefault == target.mIsDefault; } @Override public int hashCode() { - return (mDestination == null ? 0 : mDestination.hashCode()) - + (mGateway == null ? 0 :mGateway.hashCode()) + return (mDestination == null ? 0 : mDestination.hashCode() * 41) + + (mGateway == null ? 0 :mGateway.hashCode() * 47) + + (mInterface == null ? 0 :mInterface.hashCode() * 67) + (mIsDefault ? 3 : 7); } @@ -206,13 +254,15 @@ public class RouteInfo implements Parcelable { } catch (UnknownHostException e) {} } + String iface = in.readString(); + LinkAddress dest = null; if (destAddr != null) { dest = new LinkAddress(destAddr, prefix); } - return new RouteInfo(dest, gateway); + return new RouteInfo(dest, gateway, iface); } public RouteInfo[] newArray(int size) { @@ -220,13 +270,9 @@ public class RouteInfo implements Parcelable { } }; - private boolean matches(InetAddress destination) { + protected boolean matches(InetAddress destination) { if (destination == null) return false; - // if the destination is present and the route is default. - // return true - if (isDefault()) return true; - // match the route destination and destination with prefix length InetAddress dstNet = NetworkUtils.getNetworkPart(destination, mDestination.getNetworkPrefixLength()); diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java new file mode 100644 index 0000000000..59eb601ff0 --- /dev/null +++ b/core/tests/coretests/src/android/net/RouteInfoTest.java @@ -0,0 +1,180 @@ +/* + * 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 android.net; + +import java.lang.reflect.Method; +import java.net.InetAddress; + +import android.net.LinkAddress; +import android.net.RouteInfo; +import android.os.Parcel; + +import junit.framework.TestCase; +import android.test.suitebuilder.annotation.SmallTest; + +public class RouteInfoTest extends TestCase { + + private InetAddress Address(String addr) { + return InetAddress.parseNumericAddress(addr); + } + + private LinkAddress Prefix(String prefix) { + String[] parts = prefix.split("/"); + return new LinkAddress(Address(parts[0]), Integer.parseInt(parts[1])); + } + + @SmallTest + public void testConstructor() { + RouteInfo r; + + // Invalid input. + try { + r = new RouteInfo(null, null, "rmnet0"); + fail("Expected RuntimeException: destination and gateway null"); + } catch(RuntimeException e) {} + + // Null destination is default route. + r = new RouteInfo(null, Address("2001:db8::1"), null); + assertEquals(Prefix("::/0"), r.getDestination()); + assertEquals(Address("2001:db8::1"), r.getGateway()); + assertNull(r.getInterface()); + + r = new RouteInfo(null, Address("192.0.2.1"), "wlan0"); + assertEquals(Prefix("0.0.0.0/0"), r.getDestination()); + assertEquals(Address("192.0.2.1"), r.getGateway()); + assertEquals("wlan0", r.getInterface()); + + // Null gateway sets gateway to unspecified address (why?). + r = new RouteInfo(Prefix("2001:db8:beef:cafe::/48"), null, "lo"); + assertEquals(Prefix("2001:db8:beef::/48"), r.getDestination()); + assertEquals(Address("::"), r.getGateway()); + assertEquals("lo", r.getInterface()); + + r = new RouteInfo(Prefix("192.0.2.5/24"), null); + assertEquals(Prefix("192.0.2.0/24"), r.getDestination()); + assertEquals(Address("0.0.0.0"), r.getGateway()); + assertNull(r.getInterface()); + } + + public void testMatches() { + class PatchedRouteInfo extends RouteInfo { + public PatchedRouteInfo(LinkAddress destination, InetAddress gateway, String iface) { + super(destination, gateway, iface); + } + + public boolean matches(InetAddress destination) { + return super.matches(destination); + } + } + + RouteInfo r; + + r = new PatchedRouteInfo(Prefix("2001:db8:f00::ace:d00d/127"), null, "rmnet0"); + assertTrue(r.matches(Address("2001:db8:f00::ace:d00c"))); + assertTrue(r.matches(Address("2001:db8:f00::ace:d00d"))); + assertFalse(r.matches(Address("2001:db8:f00::ace:d00e"))); + assertFalse(r.matches(Address("2001:db8:f00::bad:d00d"))); + assertFalse(r.matches(Address("2001:4868:4860::8888"))); + + r = new PatchedRouteInfo(Prefix("192.0.2.0/23"), null, "wlan0"); + assertTrue(r.matches(Address("192.0.2.43"))); + assertTrue(r.matches(Address("192.0.3.21"))); + assertFalse(r.matches(Address("192.0.0.21"))); + assertFalse(r.matches(Address("8.8.8.8"))); + + RouteInfo ipv6Default = new PatchedRouteInfo(Prefix("::/0"), null, "rmnet0"); + assertTrue(ipv6Default.matches(Address("2001:db8::f00"))); + assertFalse(ipv6Default.matches(Address("192.0.2.1"))); + + RouteInfo ipv4Default = new PatchedRouteInfo(Prefix("0.0.0.0/0"), null, "rmnet0"); + assertTrue(ipv4Default.matches(Address("255.255.255.255"))); + assertTrue(ipv4Default.matches(Address("192.0.2.1"))); + assertFalse(ipv4Default.matches(Address("2001:db8::f00"))); + } + + private void assertAreEqual(Object o1, Object o2) { + assertTrue(o1.equals(o2)); + assertTrue(o2.equals(o1)); + } + + private void assertAreNotEqual(Object o1, Object o2) { + assertFalse(o1.equals(o2)); + assertFalse(o2.equals(o1)); + } + + public void testEquals() { + // IPv4 + RouteInfo r1 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0"); + RouteInfo r2 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "wlan0"); + assertAreEqual(r1, r2); + + RouteInfo r3 = new RouteInfo(Prefix("2001:db8:ace::/49"), Address("2001:db8::1"), "wlan0"); + RouteInfo r4 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::2"), "wlan0"); + RouteInfo r5 = new RouteInfo(Prefix("2001:db8:ace::/48"), Address("2001:db8::1"), "rmnet0"); + assertAreNotEqual(r1, r3); + assertAreNotEqual(r1, r4); + assertAreNotEqual(r1, r5); + + // IPv6 + r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0"); + r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "wlan0"); + assertAreEqual(r1, r2); + + r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0"); + r4 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.2"), "wlan0"); + r5 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), "rmnet0"); + assertAreNotEqual(r1, r3); + assertAreNotEqual(r1, r4); + assertAreNotEqual(r1, r5); + + // Interfaces (but not destinations or gateways) can be null. + r1 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null); + r2 = new RouteInfo(Prefix("192.0.2.0/25"), Address("192.0.2.1"), null); + r3 = new RouteInfo(Prefix("192.0.2.0/24"), Address("192.0.2.1"), "wlan0"); + assertAreEqual(r1, r2); + assertAreNotEqual(r1, r3); + } + + public RouteInfo passThroughParcel(RouteInfo r) { + Parcel p = Parcel.obtain(); + RouteInfo r2 = null; + try { + r.writeToParcel(p, 0); + p.setDataPosition(0); + r2 = RouteInfo.CREATOR.createFromParcel(p); + } finally { + p.recycle(); + } + assertNotNull(r2); + return r2; + } + + public void assertParcelingIsLossless(RouteInfo r) { + RouteInfo r2 = passThroughParcel(r); + assertEquals(r, r2); + } + + public void testParceling() { + RouteInfo r; + + r = new RouteInfo(Prefix("::/0"), Address("2001:db8::"), null); + assertParcelingIsLossless(r); + + r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0"); + assertParcelingIsLossless(r); + } +} From 7a43b0f7cf87c269e7d69a5d521ec627ce5811a0 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 8 Mar 2013 12:30:44 -0800 Subject: [PATCH 044/296] Always specify an interface for host routes. Change-Id: I05b4d87e7d7e8237c6f4a70f1fedae00f416f581 --- core/java/android/net/RouteInfo.java | 10 +++++----- .../com/android/server/ConnectivityService.java | 13 ++++++++----- .../android/server/ConnectivityServiceTest.java | 16 ++++++++++------ 3 files changed, 23 insertions(+), 16 deletions(-) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 46b6cbb557..9a3fcb0974 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -117,17 +117,17 @@ public class RouteInfo implements Parcelable { this(host, null, null); } - public static RouteInfo makeHostRoute(InetAddress host) { - return makeHostRoute(host, null); + public static RouteInfo makeHostRoute(InetAddress host, String iface) { + return makeHostRoute(host, null, iface); } - public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway) { + public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) { if (host == null) return null; if (host instanceof Inet4Address) { - return new RouteInfo(new LinkAddress(host, 32), gateway); + return new RouteInfo(new LinkAddress(host, 32), gateway, iface); } else { - return new RouteInfo(new LinkAddress(host, 128), gateway); + return new RouteInfo(new LinkAddress(host, 128), gateway, iface); } } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3257d2cb3b..027f0f39a8 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1430,17 +1430,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, boolean toDefaultTable) { + String iface = lp.getInterfaceName(); RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr); if (bestRoute == null) { - bestRoute = RouteInfo.makeHostRoute(addr); + bestRoute = RouteInfo.makeHostRoute(addr, iface); } else { if (bestRoute.getGateway().equals(addr)) { // if there is no better route, add the implied hostroute for our gateway - bestRoute = RouteInfo.makeHostRoute(addr); + bestRoute = RouteInfo.makeHostRoute(addr, iface); } else { // if we will connect to this through another route, add a direct route // to it's gateway - bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway()); + bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface); } } return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd, toDefaultTable); @@ -1463,11 +1464,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (bestRoute != null) { if (bestRoute.getGateway().equals(r.getGateway())) { // if there is no better route, add the implied hostroute for our gateway - bestRoute = RouteInfo.makeHostRoute(r.getGateway()); + bestRoute = RouteInfo.makeHostRoute(r.getGateway(), ifaceName); } else { // if we will connect to our gateway through another route, add a direct // route to it's gateway - bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway()); + bestRoute = RouteInfo.makeHostRoute(r.getGateway(), + bestRoute.getGateway(), + ifaceName); } modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd, toDefaultTable); } diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index 4ae013bad1..f955f4fd57 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -62,13 +62,17 @@ public class ConnectivityServiceTest extends AndroidTestCase { private static final String MOBILE_IFACE = "rmnet3"; private static final String WIFI_IFACE = "wlan6"; - private static final RouteInfo MOBILE_ROUTE_V4 = RouteInfo.makeHostRoute(parse("10.0.0.33")); - private static final RouteInfo MOBILE_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::33")); + private static final RouteInfo MOBILE_ROUTE_V4 = RouteInfo.makeHostRoute(parse("10.0.0.33"), + MOBILE_IFACE); + private static final RouteInfo MOBILE_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::33"), + MOBILE_IFACE); - private static final RouteInfo WIFI_ROUTE_V4 = RouteInfo.makeHostRoute( - parse("192.168.0.66"), parse("192.168.0.1")); - private static final RouteInfo WIFI_ROUTE_V6 = RouteInfo.makeHostRoute( - parse("fd00::66"), parse("fd00::")); + private static final RouteInfo WIFI_ROUTE_V4 = RouteInfo.makeHostRoute(parse("192.168.0.66"), + parse("192.168.0.1"), + WIFI_IFACE); + private static final RouteInfo WIFI_ROUTE_V6 = RouteInfo.makeHostRoute(parse("fd00::66"), + parse("fd00::"), + WIFI_IFACE); private INetworkManagementService mNetManager; private INetworkStatsService mStatsService; From fb47594d3b48f9c91c19da32d13d12ccac14c7d5 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 12 Mar 2013 04:30:47 +0900 Subject: [PATCH 045/296] Unbreak documentation build. Change-Id: I1e904b111e23d221dcb5f917201d4c27f0c1c05b --- core/java/android/net/RouteInfo.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 9a3fcb0974..3a7abc01a8 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -64,13 +64,13 @@ public class RouteInfo implements Parcelable { /** * Constructs a RouteInfo object. * - * If @destination is null, then @gateway must be specified and the + * If destination is null, then gateway must be specified and the * constructed route is either the IPv4 default route 0.0.0.0 * if @gateway is an instance of {@link Inet4Address}, or the IPv6 default - * route ::/0 if @gateway is an instance of + * route ::/0 if gateway is an instance of * {@link Inet6Address}. * - * @destination and @gateway may not both be null. + * destination and gateway may not both be null. * * @param destination the destination prefix * @param gateway the IP address to route packets through From 53de3366aa50c8114d6558f70c71893c21761066 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 12 Mar 2013 07:39:59 +0900 Subject: [PATCH 046/296] Remove redundant parameter to modifyRoute modifyRoute takes both an interface name and a LinkProperties. This is redundant because all callers get the interface name from the LinkProperties. Make modifyRoute get the interface name from the LinkProperties instead. Change-Id: I41ba8e0a10241c2f1107204fcaca2be74556042b --- .../com/android/server/ConnectivityService.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 027f0f39a8..c83a919efa 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1413,11 +1413,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { - return modifyRoute(p.getInterfaceName(), p, r, 0, ADD, toDefaultTable); + return modifyRoute(p, r, 0, ADD, toDefaultTable); } private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { - return modifyRoute(p.getInterfaceName(), p, r, 0, REMOVE, toDefaultTable); + return modifyRoute(p, r, 0, REMOVE, toDefaultTable); } private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) { @@ -1444,11 +1444,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface); } } - return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd, toDefaultTable); + return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable); } - private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount, - boolean doAdd, boolean toDefaultTable) { + private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd, + boolean toDefaultTable) { + String ifaceName = lp.getInterfaceName(); if ((ifaceName == null) || (lp == null) || (r == null)) { if (DBG) log("modifyRoute got unexpected null: " + ifaceName + ", " + lp + ", " + r); return false; @@ -1472,7 +1473,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute.getGateway(), ifaceName); } - modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd, toDefaultTable); + modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable); } } if (doAdd) { From 8ec0b8a5d60dc0293070f03bdf089ba73e2cd670 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 8 Mar 2013 19:11:40 -0800 Subject: [PATCH 047/296] Unit test routes with interfaces in LinkProperties Change-Id: Ie41a56bc9863ee72f4d7a8f72e436fc57e57b1af --- core/java/android/net/LinkProperties.java | 6 +- .../src/android/net/LinkPropertiesTest.java | 59 +++++++++++++++++++ 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index ec8d77e757..5d13a184e4 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -146,9 +146,9 @@ public class LinkProperties implements Parcelable { if (route != null) { String routeIface = route.getInterface(); if (routeIface != null && !routeIface.equals(mIfaceName)) { - throw new IllegalStateException( + throw new IllegalArgumentException( "Route added with non-matching interface: " + routeIface + - " vs. mIfaceName"); + " vs. " + mIfaceName); } mRoutes.add(routeWithInterface(route)); } @@ -370,7 +370,7 @@ public class LinkProperties implements Parcelable { public CompareResult compareRoutes(LinkProperties target) { /* * Duplicate the RouteInfos into removed, we will be removing - * routes which are common between mDnses and target + * routes which are common between mRoutes and target * leaving the routes that are different. And route address which * are in target but not in mRoutes are placed in added. */ diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index e3b6b5f950..fffaa005ef 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -197,4 +197,63 @@ public class LinkPropertiesTest extends TestCase { } } + private void assertAllRoutesHaveInterface(String iface, LinkProperties lp) { + for (RouteInfo r : lp.getRoutes()) { + assertEquals(iface, r.getInterface()); + } + } + + @SmallTest + public void testRouteInterfaces() { + LinkAddress prefix = new LinkAddress( + NetworkUtils.numericToInetAddress("2001:db8::"), 32); + InetAddress address = NetworkUtils.numericToInetAddress(ADDRV6); + + // Add a route with no interface to a LinkProperties with no interface. No errors. + LinkProperties lp = new LinkProperties(); + RouteInfo r = new RouteInfo(prefix, address, null); + lp.addRoute(r); + assertEquals(1, lp.getRoutes().size()); + assertAllRoutesHaveInterface(null, lp); + + // Add a route with an interface. Except an exception. + r = new RouteInfo(prefix, address, "wlan0"); + try { + lp.addRoute(r); + fail("Adding wlan0 route to LP with no interface, expect exception"); + } catch (IllegalArgumentException expected) {} + + // Change the interface name. All the routes should change their interface name too. + lp.setInterfaceName("rmnet0"); + assertAllRoutesHaveInterface("rmnet0", lp); + + // Now add a route with the wrong interface. This causes an exception too. + try { + lp.addRoute(r); + fail("Adding wlan0 route to rmnet0 LP, expect exception"); + } catch (IllegalArgumentException expected) {} + + // If the interface name matches, the route is added. + lp.setInterfaceName("wlan0"); + lp.addRoute(r); + assertEquals(2, lp.getRoutes().size()); + assertAllRoutesHaveInterface("wlan0", lp); + + // Routes with null interfaces are converted to wlan0. + r = RouteInfo.makeHostRoute(NetworkUtils.numericToInetAddress(ADDRV6), null); + lp.addRoute(r); + assertEquals(3, lp.getRoutes().size()); + assertAllRoutesHaveInterface("wlan0", lp); + + // Check comparisons work. + LinkProperties lp2 = new LinkProperties(lp); + assertAllRoutesHaveInterface("wlan0", lp); + assertEquals(0, lp.compareRoutes(lp2).added.size()); + assertEquals(0, lp.compareRoutes(lp2).removed.size()); + + lp2.setInterfaceName("p2p0"); + assertAllRoutesHaveInterface("p2p0", lp2); + assertEquals(3, lp.compareRoutes(lp2).added.size()); + assertEquals(3, lp.compareRoutes(lp2).removed.size()); + } } From 92abc7f76ff4d8527835819bb194b50bb7e7c031 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 13 Mar 2013 16:33:14 -0700 Subject: [PATCH 048/296] Add logging to track down bug bug:8377625 Change-Id: Ifd0c4081a2f1238dbbc39c6904b993e2fb95455a --- core/java/android/net/LinkProperties.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 5d13a184e4..9292e5f638 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -20,6 +20,7 @@ import android.net.ProxyProperties; import android.os.Parcelable; import android.os.Parcel; import android.text.TextUtils; +import android.util.Log; import java.net.InetAddress; import java.net.UnknownHostException; @@ -57,6 +58,7 @@ public class LinkProperties implements Parcelable { private String mDomains; private Collection mRoutes = new ArrayList(); private ProxyProperties mHttpProxy; + public boolean mLogMe; public static class CompareResult { public Collection removed = new ArrayList(); @@ -75,6 +77,7 @@ public class LinkProperties implements Parcelable { public LinkProperties() { clear(); + mLogMe = false; } // copy constructor instead of clone @@ -91,6 +94,14 @@ public class LinkProperties implements Parcelable { } public void setInterfaceName(String iface) { + if (mLogMe) { + Log.d("LinkProperties", "setInterfaceName from " + mIfaceName + + " to " + iface); + for (StackTraceElement e : Thread.currentThread().getStackTrace()) { + Log.d("LinkProperties", " " + e.toString()); + } + } + mIfaceName = iface; ArrayList newRoutes = new ArrayList(mRoutes.size()); for (RouteInfo route : mRoutes) { @@ -166,6 +177,13 @@ public class LinkProperties implements Parcelable { } public void clear() { + if (mLogMe) { + Log.d("LinkProperties", "clear from " + mIfaceName); + for (StackTraceElement e : Thread.currentThread().getStackTrace()) { + Log.d("LinkProperties", " " + e.toString()); + } + } + mIfaceName = null; mLinkAddresses.clear(); mDnses.clear(); From 24efb41874f8c9773f65511a23190b4e933502b5 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 14 Mar 2013 13:16:04 -0700 Subject: [PATCH 049/296] Fail fast if somebody is adding default routes bug:2655011 Change-Id: I25da940e024825bc6e1d1ac5fe7b0d951609c1c1 --- .../com/android/server/ConnectivityService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index c83a919efa..5ed23cfdc0 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2306,6 +2306,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0); + // look for a radio-added default route (v4-only for now TODO) + RouteInfo[] routes = new RouteInfo[0]; + try { + routes = mNetd.getRoutes(newLp.getInterfaceName()); + } catch (Exception e) {} + + for (RouteInfo route : routes) { + if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address && + mAddedRoutes.contains(route) == false) { + throw new IllegalStateException("Unexpected default route found for interface " + + newLp.getInterfaceName()); + } + } + for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { removeRoute(curLp, r, TO_DEFAULT_TABLE); From 93c1d17a1a90aff8b5e7cfb9ac046cac6cff2590 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 15 Mar 2013 05:07:04 +0000 Subject: [PATCH 050/296] Revert "Fail fast if somebody is adding default routes" This reverts commit 24efb41874f8c9773f65511a23190b4e933502b5 Mako wouldn't boot for me, reverting for now. Change-Id: Ie92d6bf77811e7257e86d65e1e15e1973c027cd7 --- .../com/android/server/ConnectivityService.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 5ed23cfdc0..c83a919efa 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2306,20 +2306,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0); - // look for a radio-added default route (v4-only for now TODO) - RouteInfo[] routes = new RouteInfo[0]; - try { - routes = mNetd.getRoutes(newLp.getInterfaceName()); - } catch (Exception e) {} - - for (RouteInfo route : routes) { - if (route.isDefaultRoute() && route.getGateway() instanceof Inet4Address && - mAddedRoutes.contains(route) == false) { - throw new IllegalStateException("Unexpected default route found for interface " - + newLp.getInterfaceName()); - } - } - for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { removeRoute(curLp, r, TO_DEFAULT_TABLE); From c0803125527b863dca44851dffe573e9dce441cc Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 7 Mar 2013 10:59:25 -0800 Subject: [PATCH 051/296] Add stacked interfaces to LinkProperties. Bug: 8276725 Change-Id: I2f592d4c690e9af0459ae742ab16107a10d89353 --- core/java/android/net/LinkProperties.java | 139 +++++++++++++++++- .../src/android/net/LinkPropertiesTest.java | 26 ++++ 2 files changed, 159 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 9292e5f638..833549f006 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -23,10 +23,13 @@ import android.text.TextUtils; import android.util.Log; import java.net.InetAddress; +import java.net.Inet4Address; + import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; +import java.util.Hashtable; /** * Describes the properties of a network link. @@ -48,10 +51,15 @@ import java.util.Collections; * don't care which is used. The gateways will be * selected based on the destination address and the * source address has no relavence. + * + * Links can also be stacked on top of each other. + * This can be used, for example, to represent a tunnel + * interface that runs on top of a physical interface. + * * @hide */ public class LinkProperties implements Parcelable { - + // The interface described by the network link. private String mIfaceName; private Collection mLinkAddresses = new ArrayList(); private Collection mDnses = new ArrayList(); @@ -60,6 +68,11 @@ public class LinkProperties implements Parcelable { private ProxyProperties mHttpProxy; public boolean mLogMe; + // Stores the properties of links that are "stacked" above this link. + // Indexed by interface name to allow modification and to prevent duplicates being added. + private Hashtable mStackedLinks = + new Hashtable(); + public static class CompareResult { public Collection removed = new ArrayList(); public Collection added = new ArrayList(); @@ -90,6 +103,9 @@ public class LinkProperties implements Parcelable { for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? null : new ProxyProperties(source.getHttpProxy()); + for (LinkProperties l: source.mStackedLinks.values()) { + addStackedLink(l); + } } } @@ -165,10 +181,25 @@ public class LinkProperties implements Parcelable { } } + /** + * Returns all the routes on this link. + */ public Collection getRoutes() { return Collections.unmodifiableCollection(mRoutes); } + /** + * Returns all the routes on this link and all the links stacked above it. + */ + public Collection getAllRoutes() { + Collection routes = new ArrayList(); + routes.addAll(mRoutes); + for (LinkProperties stacked: mStackedLinks.values()) { + routes.addAll(stacked.getAllRoutes()); + } + return Collections.unmodifiableCollection(routes); + } + public void setHttpProxy(ProxyProperties proxy) { mHttpProxy = proxy; } @@ -176,6 +207,46 @@ public class LinkProperties implements Parcelable { return mHttpProxy; } + /** + * Adds a stacked link. + * + * If there is already a stacked link with the same interfacename as link, + * that link is replaced with link. Otherwise, link is added to the list + * of stacked links. If link is null, nothing changes. + * + * @param link The link to add. + */ + public void addStackedLink(LinkProperties link) { + if (link != null && link.getInterfaceName() != null) { + mStackedLinks.put(link.getInterfaceName(), link); + } + } + + /** + * Removes a stacked link. + * + * If there a stacked link with the same interfacename as link, it is + * removed. Otherwise, nothing changes. + * + * @param link The link to add. + */ + public void removeStackedLink(LinkProperties link) { + if (link != null && link.getInterfaceName() != null) { + mStackedLinks.remove(link.getInterfaceName()); + } + } + + /** + * Returns all the links stacked on top of this link. + */ + public Collection getStackedLinks() { + Collection stacked = new ArrayList(); + for (LinkProperties link : mStackedLinks.values()) { + stacked.add(new LinkProperties(link)); + } + return Collections.unmodifiableCollection(stacked); + } + public void clear() { if (mLogMe) { Log.d("LinkProperties", "clear from " + mIfaceName); @@ -190,6 +261,7 @@ public class LinkProperties implements Parcelable { mDomains = null; mRoutes.clear(); mHttpProxy = null; + mStackedLinks.clear(); } /** @@ -219,7 +291,29 @@ public class LinkProperties implements Parcelable { routes += "] "; String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); - return ifaceName + linkAddresses + routes + dns + domainName + proxy; + String stacked = ""; + if (mStackedLinks.values().size() > 0) { + stacked += " Stacked: ["; + for (LinkProperties link: mStackedLinks.values()) { + stacked += " [" + link.toString() + " ],"; + } + stacked += "] "; + } + return ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked; + } + + /** + * Returns true if this link has an IPv4 address. + * + * @return {@code true} if there is an IPv4 address, {@code false} otherwise. + */ + public boolean hasIPv4Address() { + for (LinkAddress address : mLinkAddresses) { + if (address.getAddress() instanceof Inet4Address) { + return true; + } + } + return false; } /** @@ -286,6 +380,26 @@ public class LinkProperties implements Parcelable { getHttpProxy().equals(target.getHttpProxy()); } + /** + * Compares this {@code LinkProperties} stacked links against the target + * + * @param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + */ + public boolean isIdenticalStackedLinks(LinkProperties target) { + if (!mStackedLinks.keys().equals(target.mStackedLinks.keys())) { + return false; + } + for (LinkProperties stacked : mStackedLinks.values()) { + // Hashtable values can never be null. + String iface = stacked.getInterfaceName(); + if (!stacked.equals(target.mStackedLinks.get(iface))) { + return false; + } + } + return true; + } + @Override /** * Compares this {@code LinkProperties} instance against the target @@ -298,6 +412,10 @@ public class LinkProperties implements Parcelable { * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. * 2. Worst case performance is O(n^2). * + * This method does not check that stacked interfaces are equal, because + * stacked interfaces are not so much a property of the link as a + * description of connections between links. + * * @param obj the object to be tested for equality. * @return {@code true} if both objects are equal, {@code false} otherwise. */ @@ -312,7 +430,8 @@ public class LinkProperties implements Parcelable { isIdenticalAddresses(target) && isIdenticalDnses(target) && isIdenticalRoutes(target) && - isIdenticalHttpProxy(target); + isIdenticalHttpProxy(target) && + isIdenticalStackedLinks(target); } /** @@ -394,10 +513,10 @@ public class LinkProperties implements Parcelable { */ CompareResult result = new CompareResult(); - result.removed = new ArrayList(mRoutes); + result.removed = getAllRoutes(); result.added.clear(); if (target != null) { - for (RouteInfo r : target.getRoutes()) { + for (RouteInfo r : target.getAllRoutes()) { if (! result.removed.remove(r)) { result.added.add(r); } @@ -419,7 +538,8 @@ public class LinkProperties implements Parcelable { + mDnses.size() * 37 + ((null == mDomains) ? 0 : mDomains.hashCode()) + mRoutes.size() * 41 - + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode())); + + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) + + mStackedLinks.hashCode() * 47); } /** @@ -449,6 +569,8 @@ public class LinkProperties implements Parcelable { } else { dest.writeByte((byte)0); } + ArrayList stackedLinks = new ArrayList(mStackedLinks.values()); + dest.writeList(stackedLinks); } /** @@ -481,6 +603,11 @@ public class LinkProperties implements Parcelable { if (in.readByte() == 1) { netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); } + ArrayList stackedLinks = new ArrayList(); + in.readList(stackedLinks, LinkProperties.class.getClassLoader()); + for (LinkProperties stackedLink: stackedLinks) { + netProp.addStackedLink(stackedLink); + } return netProp; } diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index fffaa005ef..c746e52901 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -22,6 +22,7 @@ import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; import java.net.InetAddress; +import java.util.ArrayList; public class LinkPropertiesTest extends TestCase { private static String ADDRV4 = "75.208.6.1"; @@ -255,5 +256,30 @@ public class LinkPropertiesTest extends TestCase { assertAllRoutesHaveInterface("p2p0", lp2); assertEquals(3, lp.compareRoutes(lp2).added.size()); assertEquals(3, lp.compareRoutes(lp2).removed.size()); + + @SmallTest + public void testStackedInterfaces() { + LinkProperties rmnet0 = new LinkProperties(); + rmnet0.setInterfaceName("rmnet0"); + + LinkProperties clat4 = new LinkProperties(); + clat4.setInterfaceName("clat4"); + + assertEquals(0, rmnet0.getStackedLinks().size()); + rmnet0.addStackedLink(clat4); + assertEquals(1, rmnet0.getStackedLinks().size()); + rmnet0.addStackedLink(clat4); + assertEquals(1, rmnet0.getStackedLinks().size()); + assertEquals(0, clat4.getStackedLinks().size()); + + // Modify an item in the returned collection to see what happens. + for (LinkProperties link : rmnet0.getStackedLinks()) { + if (link.getInterfaceName().equals("clat4")) { + link.setInterfaceName("newname"); + } + } + for (LinkProperties link : rmnet0.getStackedLinks()) { + assertFalse("newname".equals(link.getInterfaceName())); + } } } From e43b6c4eb3731666d856ddebade4cffd64a3088f Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 15 Mar 2013 13:58:38 +0900 Subject: [PATCH 052/296] Set routes from stacked links as well. Currently, ConnectivityService adds and removes routes to/from the routing table only based on the LinkProperties's routes. Make it update routes based on the stacked links as well. Bug: 8276725 Change-Id: I9a2adf537af5a04de0aaab3780afbcc3bb5c6acb --- .../android/server/ConnectivityService.java | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 5ed23cfdc0..a6ddcab670 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1430,11 +1430,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, boolean toDefaultTable) { - String iface = lp.getInterfaceName(); - RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr); + RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr); if (bestRoute == null) { - bestRoute = RouteInfo.makeHostRoute(addr, iface); + bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName()); } else { + String iface = bestRoute.getInterface(); if (bestRoute.getGateway().equals(addr)) { // if there is no better route, add the implied hostroute for our gateway bestRoute = RouteInfo.makeHostRoute(addr, iface); @@ -1449,9 +1449,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd, boolean toDefaultTable) { - String ifaceName = lp.getInterfaceName(); - if ((ifaceName == null) || (lp == null) || (r == null)) { - if (DBG) log("modifyRoute got unexpected null: " + ifaceName + ", " + lp + ", " + r); + if ((lp == null) || (r == null)) { + if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r); return false; } @@ -1460,8 +1459,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } + String ifaceName = r.getInterface(); + if(ifaceName == null) { + loge("Error modifying route - no interface name"); + return false; + } + if (r.isHostRoute() == false) { - RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), r.getGateway()); + RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), r.getGateway()); if (bestRoute != null) { if (bestRoute.getGateway().equals(r.getGateway())) { // if there is no better route, add the implied hostroute for our gateway @@ -2300,7 +2305,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { routeDiff = curLp.compareRoutes(newLp); dnsDiff = curLp.compareDnses(newLp); } else if (newLp != null) { - routeDiff.added = newLp.getRoutes(); + routeDiff.added = newLp.getAllRoutes(); dnsDiff.added = newLp.getDnses(); } From 7a9d79777169b9a95121d9a6fef01e83baf51e58 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 15 Mar 2013 04:22:37 +0900 Subject: [PATCH 053/296] Framework changes for 464xlat. 1. Add a Nat464Xlat service that ConnectivityService can use to start and stop clat. When clat is started, the service waits for the clat interface to come up and then calls ConnectivityService to add the appropriate routes. 2. Make ConnectivityService start clat when an IPv6-only mobile interface is connected. We only support clat on mobile for now. 3. Make tethering use the interface that has the IPv4 default route insted of using the base interface of the LinkProperties. This allows us to tether to a stacked interface, which is needed for tethering with 464xlat. Bug: 8276725 Change-Id: I24480af69ee280f504399062638af0836a56268e --- .../android/server/ConnectivityService.java | 17 ++ .../server/connectivity/Nat464Xlat.java | 189 ++++++++++++++++++ 2 files changed, 206 insertions(+) create mode 100644 services/java/com/android/server/connectivity/Nat464Xlat.java diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a6ddcab670..f735c4ce79 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -96,6 +96,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; import com.android.server.am.BatteryStatsService; +import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; @@ -154,6 +155,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean mLockdownEnabled; private LockdownVpnTracker mLockdownTracker; + private Nat464Xlat mClat; + /** Lock around {@link #mUidRules} and {@link #mMeteredIfaces}. */ private Object mRulesLock = new Object(); /** Currently active network rules by UID. */ @@ -544,9 +547,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { mVpn = new Vpn(mContext, mVpnCallback, mNetd); mVpn.startMonitoring(mContext, mTrackerHandler); + mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler); + try { mNetd.registerObserver(mTethering); mNetd.registerObserver(mDataActivityObserver); + mNetd.registerObserver(mClat); } catch (RemoteException e) { loge("Error registering observer :" + e); } @@ -2276,6 +2282,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + // Update 464xlat state. + // TODO: Move to handleConnect() + NetworkStateTracker tracker = mNetTrackers[netType]; + if (mClat.requiresClat(netType, tracker)) { + if (mNetTrackers[netType].getNetworkInfo().isConnected()) { + mClat.startClat(tracker); + } else { + mClat.stopClat(); + } + } + // TODO: Temporary notifying upstread change to Tethering. // @see bug/4455071 /** Notify TetheringService if interface name has been changed. */ diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/java/com/android/server/connectivity/Nat464Xlat.java new file mode 100644 index 0000000000..2884eafd07 --- /dev/null +++ b/services/java/com/android/server/connectivity/Nat464Xlat.java @@ -0,0 +1,189 @@ +/* + * 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.connectivity; + +import static android.net.ConnectivityManager.TYPE_MOBILE; + +import java.net.Inet4Address; + +import android.content.Context; +import android.net.IConnectivityManager; +import android.net.InterfaceConfiguration; +import android.net.LinkAddress; +import android.net.LinkProperties; +import android.net.NetworkStateTracker; +import android.net.NetworkUtils; +import android.net.RouteInfo; +import android.os.Handler; +import android.os.Message; +import android.os.INetworkManagementService; +import android.os.RemoteException; +import android.util.Slog; + +import com.android.server.net.BaseNetworkObserver; + +/** + * @hide + * + * Class to manage a 464xlat CLAT daemon. + */ +public class Nat464Xlat extends BaseNetworkObserver { + private Context mContext; + private INetworkManagementService mNMService; + private IConnectivityManager mConnService; + private NetworkStateTracker mTracker; + private Handler mHandler; + + // Whether we started clatd and expect it to be running. + private boolean mIsStarted; + // Whether the clatd interface exists (i.e., clatd is running). + private boolean mIsRunning; + // The LinkProperties of the clat interface. + private LinkProperties mLP; + + // This must match the interface name in clatd.conf. + private static final String CLAT_INTERFACE_NAME = "clat4"; + + private static final String TAG = "Nat464Xlat"; + + public Nat464Xlat(Context context, INetworkManagementService nmService, + IConnectivityManager connService, Handler handler) { + mContext = context; + mNMService = nmService; + mConnService = connService; + mHandler = handler; + + mIsStarted = false; + mIsRunning = false; + mLP = new LinkProperties(); + } + + /** + * Determines whether an interface requires clat. + * @param netType the network type (one of the + * android.net.ConnectivityManager.TYPE_* constants) + * @param tracker the NetworkStateTracker corresponding to the network type. + * @return true if the interface requires clat, false otherwise. + */ + public boolean requiresClat(int netType, NetworkStateTracker tracker) { + LinkProperties lp = tracker.getLinkProperties(); + // Only support clat on mobile for now. + Slog.d(TAG, "requiresClat: netType=" + netType + ", hasIPv4Address=" + + lp.hasIPv4Address()); + return netType == TYPE_MOBILE && !lp.hasIPv4Address(); + } + + /** + * Starts the clat daemon. + * @param lp The link properties of the interface to start clatd on. + */ + public void startClat(NetworkStateTracker tracker) { + if (mIsStarted) { + Slog.e(TAG, "startClat: already started"); + return; + } + mTracker = tracker; + LinkProperties lp = mTracker.getLinkProperties(); + String iface = lp.getInterfaceName(); + Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp); + try { + mNMService.startClatd(iface); + } catch(RemoteException e) { + Slog.e(TAG, "Error starting clat daemon: " + e); + } + mIsStarted = true; + } + + /** + * Stops the clat daemon. + */ + public void stopClat() { + if (mIsStarted) { + Slog.i(TAG, "Stopping clatd"); + try { + mNMService.stopClatd(); + } catch(RemoteException e) { + Slog.e(TAG, "Error stopping clat daemon: " + e); + } + mIsStarted = false; + mIsRunning = false; + mTracker = null; + mLP.clear(); + } else { + Slog.e(TAG, "stopClat: already stopped"); + } + } + + public boolean isStarted() { + return mIsStarted; + } + + public boolean isRunning() { + return mIsRunning; + } + + @Override + public void interfaceAdded(String iface) { + if (iface.equals(CLAT_INTERFACE_NAME)) { + Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + + " added, mIsRunning = " + mIsRunning + " -> true"); + mIsRunning = true; + + // Get the network configuration of the clat interface, store it + // in our link properties, and stack it on top of the interface + // it's running on. + try { + InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); + mLP.clear(); + mLP.setInterfaceName(iface); + RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), null, + iface); + mLP.addRoute(ipv4Default); + mLP.addLinkAddress(config.getLinkAddress()); + mTracker.addStackedLink(mLP); + Slog.i(TAG, "Adding stacked link. tracker LP: " + + mTracker.getLinkProperties()); + } catch(RemoteException e) { + Slog.e(TAG, "Error getting link properties: " + e); + } + + // Inform ConnectivityService that things have changed. + Message msg = mHandler.obtainMessage( + NetworkStateTracker.EVENT_CONFIGURATION_CHANGED, + mTracker.getNetworkInfo()); + Slog.i(TAG, "sending message to ConnectivityService: " + msg); + msg.sendToTarget(); + } + } + + @Override + public void interfaceRemoved(String iface) { + if (iface == CLAT_INTERFACE_NAME) { + if (mIsRunning) { + NetworkUtils.resetConnections( + CLAT_INTERFACE_NAME, + NetworkUtils.RESET_IPV4_ADDRESSES); + } + Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + + " removed, mIsRunning = " + mIsRunning + " -> false"); + mIsRunning = false; + mTracker.removeStackedLink(mLP); + mLP.clear(); + Slog.i(TAG, "mLP = " + mLP); + } + } +}; From 3989de8e16b56ef3bdae1fbf4ca516bcb1b19a34 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 16 Mar 2013 02:42:30 +0900 Subject: [PATCH 054/296] Fix build. Change-Id: Iac84a5f35d7fcaebd096e605a4590f8c90fe97b0 --- core/tests/coretests/src/android/net/LinkPropertiesTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index c746e52901..274ac6b2d9 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -256,6 +256,7 @@ public class LinkPropertiesTest extends TestCase { assertAllRoutesHaveInterface("p2p0", lp2); assertEquals(3, lp.compareRoutes(lp2).added.size()); assertEquals(3, lp.compareRoutes(lp2).removed.size()); + } @SmallTest public void testStackedInterfaces() { From 0c0db62a64e8d10343db975cae35b77a8159253d Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 15 Mar 2013 10:48:46 -0700 Subject: [PATCH 055/296] Don't update routes if Dhcp fails. bug:8377625 Change-Id: I11d2c29728078813bfb1245cc46e8cce2b307a2c --- core/jni/android_net_NetUtils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index f5f22b2d2a..faae11ec3b 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -136,6 +136,10 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, dns, server, &lease, vendorInfo, domains); } + if (result != 0) { + ALOGD("dhcp_do_request failed"); + } + env->ReleaseStringUTFChars(ifname, nameStr); if (result == 0) { env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear); From f338508972555b6d46c0e4f1d3809765c136e924 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 15 Mar 2013 11:28:50 -0700 Subject: [PATCH 056/296] Don't return an unmod collection. It's not needed as people can mess with this, and people do, so this fixes the build. bug:8398355 Change-Id: Iddd00af41009c88b67fb7f9a8789bb416c377922 --- core/java/android/net/LinkProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 833549f006..7044d39221 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -197,7 +197,7 @@ public class LinkProperties implements Parcelable { for (LinkProperties stacked: mStackedLinks.values()) { routes.addAll(stacked.getAllRoutes()); } - return Collections.unmodifiableCollection(routes); + return routes; } public void setHttpProxy(ProxyProperties proxy) { From 79555229c8dbddb8f97e0f0177a047d49e839a85 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 15 Mar 2013 10:48:46 -0700 Subject: [PATCH 057/296] Don't update routes if Dhcp fails. bug:8377625 Change-Id: I11d2c29728078813bfb1245cc46e8cce2b307a2c --- core/jni/android_net_NetUtils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index f5f22b2d2a..faae11ec3b 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -136,6 +136,10 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, dns, server, &lease, vendorInfo, domains); } + if (result != 0) { + ALOGD("dhcp_do_request failed"); + } + env->ReleaseStringUTFChars(ifname, nameStr); if (result == 0) { env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.clear); From fe86530b37fbf7fd3ccbebe0207ccc7463c48cae Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 15 Mar 2013 13:17:11 -0700 Subject: [PATCH 058/296] Revert of Ifd0c4081a. Turning off logging. Found our bug, so switching the logging back off. bug:8377625 Change-Id: I254bd83c48f1dd8dd62db1fcb162d460328169c5 --- core/java/android/net/LinkProperties.java | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 7044d39221..4457a22844 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -20,7 +20,6 @@ import android.net.ProxyProperties; import android.os.Parcelable; import android.os.Parcel; import android.text.TextUtils; -import android.util.Log; import java.net.InetAddress; import java.net.Inet4Address; @@ -66,7 +65,6 @@ public class LinkProperties implements Parcelable { private String mDomains; private Collection mRoutes = new ArrayList(); private ProxyProperties mHttpProxy; - public boolean mLogMe; // Stores the properties of links that are "stacked" above this link. // Indexed by interface name to allow modification and to prevent duplicates being added. @@ -90,7 +88,6 @@ public class LinkProperties implements Parcelable { public LinkProperties() { clear(); - mLogMe = false; } // copy constructor instead of clone @@ -110,14 +107,6 @@ public class LinkProperties implements Parcelable { } public void setInterfaceName(String iface) { - if (mLogMe) { - Log.d("LinkProperties", "setInterfaceName from " + mIfaceName + - " to " + iface); - for (StackTraceElement e : Thread.currentThread().getStackTrace()) { - Log.d("LinkProperties", " " + e.toString()); - } - } - mIfaceName = iface; ArrayList newRoutes = new ArrayList(mRoutes.size()); for (RouteInfo route : mRoutes) { @@ -248,13 +237,6 @@ public class LinkProperties implements Parcelable { } public void clear() { - if (mLogMe) { - Log.d("LinkProperties", "clear from " + mIfaceName); - for (StackTraceElement e : Thread.currentThread().getStackTrace()) { - Log.d("LinkProperties", " " + e.toString()); - } - } - mIfaceName = null; mLinkAddresses.clear(); mDnses.clear(); From 6383982582abac178f2e0fcb17c35304d23e6d09 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 20 Mar 2013 19:22:58 +0900 Subject: [PATCH 059/296] Reset connections on all stacked interfaces. Bug: 8276725 Change-Id: I7fe99c6ea123037cef3e89e3c2c17ed43cc0b1ea --- core/java/android/net/LinkProperties.java | 9 +++++ .../android/server/ConnectivityService.java | 37 ++++++++++--------- 2 files changed, 28 insertions(+), 18 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 4457a22844..e5227548b5 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -119,6 +119,15 @@ public class LinkProperties implements Parcelable { return mIfaceName; } + public Collection getAllInterfaceNames() { + Collection interfaceNames = new ArrayList(mStackedLinks.size() + 1); + interfaceNames.add(new String(mIfaceName)); + for (LinkProperties stacked: mStackedLinks.values()) { + interfaceNames.addAll(stacked.getAllInterfaceNames()); + } + return interfaceNames; + } + public Collection getAddresses() { Collection addresses = new ArrayList(); for (LinkAddress linkAddress : mLinkAddresses) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 72d249aa28..6dcb4034e5 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2256,26 +2256,27 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (resetMask != 0 || resetDns) { LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties(); if (linkProperties != null) { - String iface = linkProperties.getInterfaceName(); - if (TextUtils.isEmpty(iface) == false) { - if (resetMask != 0) { - if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")"); - NetworkUtils.resetConnections(iface, resetMask); + for (String iface : linkProperties.getAllInterfaceNames()) { + if (TextUtils.isEmpty(iface) == false) { + if (resetMask != 0) { + if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")"); + NetworkUtils.resetConnections(iface, resetMask); - // Tell VPN the interface is down. It is a temporary - // but effective fix to make VPN aware of the change. - if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) { - mVpn.interfaceStatusChanged(iface, false); + // Tell VPN the interface is down. It is a temporary + // but effective fix to make VPN aware of the change. + if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) { + mVpn.interfaceStatusChanged(iface, false); + } } - } - if (resetDns) { - flushVmDnsCache(); - if (VDBG) log("resetting DNS cache for " + iface); - try { - mNetd.flushInterfaceDnsCache(iface); - } catch (Exception e) { - // never crash - catch them all - if (DBG) loge("Exception resetting dns cache: " + e); + if (resetDns) { + flushVmDnsCache(); + if (VDBG) log("resetting DNS cache for " + iface); + try { + mNetd.flushInterfaceDnsCache(iface); + } catch (Exception e) { + // never crash - catch them all + if (DBG) loge("Exception resetting dns cache: " + e); + } } } } From 5371dbf5ad8d3fcb8000f2295fb64393e64d44b2 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 22 Mar 2013 12:00:17 -0700 Subject: [PATCH 060/296] Prevent NPE in new API. bug:8455284 Change-Id: I26ecbd024d1fe001f3af792c4e66409b2968c7ec --- core/java/android/net/LinkProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index e5227548b5..eedc372d25 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -121,7 +121,7 @@ public class LinkProperties implements Parcelable { public Collection getAllInterfaceNames() { Collection interfaceNames = new ArrayList(mStackedLinks.size() + 1); - interfaceNames.add(new String(mIfaceName)); + if (mIfaceName != null) interfaceNames.add(new String(mIfaceName)); for (LinkProperties stacked: mStackedLinks.values()) { interfaceNames.addAll(stacked.getAllInterfaceNames()); } From aff5413507e7cd3b6aac656b50fcefc5334947ae Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 27 Mar 2013 13:07:18 +0900 Subject: [PATCH 061/296] Make isHostRoute match only host routes Currently, isHostRoute returns true iff the gateway address is the unspecified address (0.0.0.0 or ::). Thus, it will return true for any route that has no gateway (e.g., a route pointing at a point-to-point interface), even if the route is not a host route. Fix this by checking the prefix length instead. This should be safe because: 1. mDestination cannot be null, since it's created using new. 2. Host routes created using makeHostRoute (which is what ConnectivityService calls) always have the correct prefix lengths (/32 or /128) set. Bug: 8276725 Change-Id: I14285398823fa6c312349128c7cc216cad4a84c9 --- core/java/android/net/RouteInfo.java | 5 ++- .../src/android/net/RouteInfoTest.java | 34 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 3a7abc01a8..cc3c5f7cff 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -132,7 +132,10 @@ public class RouteInfo implements Parcelable { } private boolean isHost() { - return (mGateway.equals(Inet4Address.ANY) || mGateway.equals(Inet6Address.ANY)); + return (mDestination.getAddress() instanceof Inet4Address && + mDestination.getNetworkPrefixLength() == 32) || + (mDestination.getAddress() instanceof Inet6Address && + mDestination.getNetworkPrefixLength() == 128); } private boolean isDefault() { diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java index 59eb601ff0..55d6592d9a 100644 --- a/core/tests/coretests/src/android/net/RouteInfoTest.java +++ b/core/tests/coretests/src/android/net/RouteInfoTest.java @@ -149,6 +149,40 @@ public class RouteInfoTest extends TestCase { assertAreNotEqual(r1, r3); } + public void testHostRoute() { + RouteInfo r; + + r = new RouteInfo(Prefix("0.0.0.0/0"), Address("0.0.0.0"), "wlan0"); + assertFalse(r.isHostRoute()); + + r = new RouteInfo(Prefix("::/0"), Address("::"), "wlan0"); + assertFalse(r.isHostRoute()); + + r = new RouteInfo(Prefix("192.0.2.0/24"), null, "wlan0"); + assertFalse(r.isHostRoute()); + + r = new RouteInfo(Prefix("2001:db8::/48"), null, "wlan0"); + assertFalse(r.isHostRoute()); + + r = new RouteInfo(Prefix("192.0.2.0/32"), Address("0.0.0.0"), "wlan0"); + assertTrue(r.isHostRoute()); + + r = new RouteInfo(Prefix("2001:db8::/128"), Address("::"), "wlan0"); + assertTrue(r.isHostRoute()); + + r = new RouteInfo(Prefix("192.0.2.0/32"), null, "wlan0"); + assertTrue(r.isHostRoute()); + + r = new RouteInfo(Prefix("2001:db8::/128"), null, "wlan0"); + assertTrue(r.isHostRoute()); + + r = new RouteInfo(Prefix("::/128"), Address("fe80::"), "wlan0"); + assertTrue(r.isHostRoute()); + + r = new RouteInfo(Prefix("0.0.0.0/32"), Address("192.0.2.1"), "wlan0"); + assertTrue(r.isHostRoute()); + } + public RouteInfo passThroughParcel(RouteInfo r) { Parcel p = Parcel.obtain(); RouteInfo r2 = null; From 15a4153880e3dd3a3c377b518ae57f7dd6d52d15 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 21 Aug 2012 19:27:00 -0700 Subject: [PATCH 062/296] Add BT - DataTracker connection Allows the external BT stack the means to communicate with ConnectivityService during reverse tethering. bug:8445208 Change-Id: Ice7dfb0b50c9481d359aed14a51372878185171c --- core/java/android/net/ConnectivityManager.java | 14 ++++++++++++++ core/java/android/net/IConnectivityManager.aidl | 3 +++ .../com/android/server/ConnectivityService.java | 11 ++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3a04c271ca..4e4980d557 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -23,6 +23,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; import android.os.Build.VERSION_CODES; +import android.os.Messenger; import android.os.RemoteException; import android.provider.Settings; @@ -1280,4 +1281,17 @@ public class ConnectivityManager { } } + /** + * Supply the backend messenger for a network tracker + * + * @param type NetworkType to set + * @param messenger {@link Messenger} + * {@hide} + */ + public void supplyMessenger(int networkType, Messenger messenger) { + try { + mService.supplyMessenger(networkType, messenger); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 056fa030e9..9e9b43d9ab 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -22,6 +22,7 @@ import android.net.NetworkQuotaInfo; import android.net.NetworkState; import android.net.ProxyProperties; import android.os.IBinder; +import android.os.Messenger; import android.os.ParcelFileDescriptor; import com.android.internal.net.LegacyVpnInfo; @@ -126,4 +127,6 @@ interface IConnectivityManager boolean updateLockdownVpn(); void captivePortalCheckComplete(in NetworkInfo info); + + void supplyMessenger(int networkType, in Messenger messenger); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6dcb4034e5..0bb0366db9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -74,6 +74,7 @@ import android.os.IBinder; import android.os.INetworkManagementService; import android.os.Looper; import android.os.Message; +import android.os.Messenger; import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; @@ -3220,7 +3221,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { throwIfLockdownEnabled(); try { int type = mActiveDefaultNetwork; - if (ConnectivityManager.isNetworkTypeValid(type)) { + if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) { mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName()); return true; } @@ -3425,4 +3426,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalStateException("Unavailable in lockdown mode"); } } + + public void supplyMessenger(int networkType, Messenger messenger) { + enforceConnectivityInternalPermission(); + + if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) { + mNetTrackers[networkType].supplyMessenger(messenger); + } + } } From 22d95f3e82d178cc119b062e209a55f7418e6e3e Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 27 Mar 2013 16:21:43 -0700 Subject: [PATCH 063/296] Cleanup some debug in LinkCapabilities and Properties. Change-Id: I5fe0124d0943f5e538e451645f32533a74c75a47 --- core/java/android/net/LinkProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index eedc372d25..52b238ffd9 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -290,7 +290,7 @@ public class LinkProperties implements Parcelable { } stacked += "] "; } - return ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked; + return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}"; } /** From 4118d082f1834b691f990d76e01cdf5a7a46a412 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 28 Mar 2013 14:13:43 +0900 Subject: [PATCH 064/296] Stop clat if it's no longer in use. Normally, clatd is stopped when a connection disconnects. However, if the connection's LinkProperties change, or if the disconnect somehow gets lost (e.g., because of bug 8486114), then we need to stop it (and possibly restart it). Bug: 8276725 Change-Id: Ib8ad0d653ed8d0cd70b7414bcaa8fdaef8ba5fcc --- .../java/com/android/server/ConnectivityService.java | 10 +++++++++- .../com/android/server/connectivity/Nat464Xlat.java | 4 ++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6dcb4034e5..9daf0386a9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2284,9 +2284,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Update 464xlat state. - // TODO: Move to handleConnect() NetworkStateTracker tracker = mNetTrackers[netType]; if (mClat.requiresClat(netType, tracker)) { + // If the connection was previously using clat, but is not using it now, stop the clat + // daemon. Normally, this happens automatically when the connection disconnects, but if + // the disconnect is not reported, or if the connection's LinkProperties changed for + // some other reason (e.g., handoff changes the IP addresses on the link), it would + // still be running. If it's not running, then stopping it is a no-op. + if (Nat464Xlat.isRunningClat(curLp) && !Nat464Xlat.isRunningClat(newLp)) { + mClat.stopClat(); + } + // If the link requires clat to be running, then start the daemon now. if (mNetTrackers[netType].getNetworkInfo().isConnected()) { mClat.startClat(tracker); } else { diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/java/com/android/server/connectivity/Nat464Xlat.java index 2884eafd07..59403c559d 100644 --- a/services/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/java/com/android/server/connectivity/Nat464Xlat.java @@ -87,6 +87,10 @@ public class Nat464Xlat extends BaseNetworkObserver { return netType == TYPE_MOBILE && !lp.hasIPv4Address(); } + public static boolean isRunningClat(LinkProperties lp) { + return lp != null && lp.getAllInterfaceNames().contains(CLAT_INTERFACE_NAME); + } + /** * Starts the clat daemon. * @param lp The link properties of the interface to start clatd on. From 89218e5e3f095e65f34d4197744aa0430fb928e9 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 1 Apr 2013 10:47:43 +0900 Subject: [PATCH 065/296] Fix LinkProperties's equals() method. LinkProperties's equals() method was broken by the addition of stacked interfaces. The reason was that equals() was checking the equality of mStackedInterfaces.keys(), which is just an enumeration, instead of mStackedInterfaces.keySet(), which actually contains the keys. The test was failing, but I didn't notice. Fix the bug and make the test check the objects more in depth so it can give more detailed error messages when equals() fails. Bug: 8276725 Change-Id: Ie990bd75f641c28e63e54d953dcd0f4de13f7c9f --- core/java/android/net/LinkProperties.java | 2 +- .../src/android/net/LinkPropertiesTest.java | 40 +++++++++++++++---- 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 52b238ffd9..75f8b5948b 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -378,7 +378,7 @@ public class LinkProperties implements Parcelable { * @return {@code true} if both are identical, {@code false} otherwise. */ public boolean isIdenticalStackedLinks(LinkProperties target) { - if (!mStackedLinks.keys().equals(target.mStackedLinks.keys())) { + if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { return false; } for (LinkProperties stacked : mStackedLinks.values()) { diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index 274ac6b2d9..d6a7ee27a2 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -33,14 +33,41 @@ public class LinkPropertiesTest extends TestCase { private static String GATEWAY2 = "69.78.8.1"; private static String NAME = "qmi0"; + public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) { + // Check implementation of equals(), element by element. + assertTrue(source.isIdenticalInterfaceName(target)); + assertTrue(target.isIdenticalInterfaceName(source)); + + assertTrue(source.isIdenticalAddresses(target)); + assertTrue(target.isIdenticalAddresses(source)); + + assertTrue(source.isIdenticalDnses(target)); + assertTrue(target.isIdenticalDnses(source)); + + assertTrue(source.isIdenticalRoutes(target)); + assertTrue(target.isIdenticalRoutes(source)); + + assertTrue(source.isIdenticalHttpProxy(target)); + assertTrue(target.isIdenticalHttpProxy(source)); + + assertTrue(source.isIdenticalStackedLinks(target)); + assertTrue(target.isIdenticalStackedLinks(source)); + + // Check result of equals(). + assertTrue(source.equals(target)); + assertTrue(target.equals(source)); + + // Check hashCode. + assertEquals(source.hashCode(), target.hashCode()); + } + @SmallTest public void testEqualsNull() { LinkProperties source = new LinkProperties(); LinkProperties target = new LinkProperties(); assertFalse(source == target); - assertTrue(source.equals(target)); - assertTrue(source.hashCode() == target.hashCode()); + assertLinkPropertiesEqual(source, target); } @SmallTest @@ -73,8 +100,7 @@ public class LinkPropertiesTest extends TestCase { target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); - assertTrue(source.equals(target)); - assertTrue(source.hashCode() == target.hashCode()); + assertLinkPropertiesEqual(source, target); target.clear(); // change Interface Name @@ -163,8 +189,7 @@ public class LinkPropertiesTest extends TestCase { target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - assertTrue(source.equals(target)); - assertTrue(source.hashCode() == target.hashCode()); + assertLinkPropertiesEqual(source, target); } catch (Exception e) { fail(); } @@ -191,8 +216,7 @@ public class LinkPropertiesTest extends TestCase { target.addLinkAddress(new LinkAddress( NetworkUtils.numericToInetAddress(ADDRV6), 128)); - assertTrue(source.equals(target)); - assertTrue(source.hashCode() == target.hashCode()); + assertLinkPropertiesEqual(source, target); } catch (Exception e) { fail(); } From f9661d357f7d7330703cdd27323615ba6978ccb7 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 5 Apr 2013 17:14:19 -0700 Subject: [PATCH 066/296] Turn back on global proxy support. This reverts 138626. Bug:8557674 Change-Id: I7b117d313c424d75bdeeea507541a96342f256f0 --- .../android/server/ConnectivityService.java | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9e06db83a3..ffc36723eb 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -321,12 +321,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // track the current default http proxy - tell the world if we get a new one (real change) private ProxyProperties mDefaultProxy = null; - private Object mDefaultProxyLock = new Object(); + private Object mProxyLock = new Object(); private boolean mDefaultProxyDisabled = false; // track the global proxy. private ProxyProperties mGlobalProxy = null; - private final Object mGlobalProxyLock = new Object(); private SettingsObserver mSettingsObserver; @@ -3039,14 +3038,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { // so this API change wouldn't have a benifit. It also breaks the passing // of proxy info to all the JVMs. // enforceAccessPermission(); - synchronized (mDefaultProxyLock) { - return mDefaultProxyDisabled ? null : mDefaultProxy; + synchronized (mProxyLock) { + if (mGlobalProxy != null) return mGlobalProxy; + return (mDefaultProxyDisabled ? null : mDefaultProxy); } } public void setGlobalProxy(ProxyProperties proxyProperties) { enforceChangePermission(); - synchronized (mGlobalProxyLock) { + synchronized (mProxyLock) { if (proxyProperties == mGlobalProxy) return; if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return; @@ -3072,7 +3072,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mGlobalProxy == null) { proxyProperties = mDefaultProxy; } - //sendProxyBroadcast(proxyProperties); + sendProxyBroadcast(proxyProperties); } private void loadGlobalProxy() { @@ -3083,7 +3083,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); if (!TextUtils.isEmpty(host)) { ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList); - synchronized (mGlobalProxyLock) { + synchronized (mProxyLock) { mGlobalProxy = proxyProperties; } } @@ -3094,7 +3094,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // so this API change wouldn't have a benifit. It also breaks the passing // of proxy info to all the JVMs. // enforceAccessPermission(); - synchronized (mGlobalProxyLock) { + synchronized (mProxyLock) { return mGlobalProxy; } } @@ -3103,11 +3103,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (proxy != null && TextUtils.isEmpty(proxy.getHost())) { proxy = null; } - synchronized (mDefaultProxyLock) { + synchronized (mProxyLock) { if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return; - if (mDefaultProxy == proxy) return; + if (mDefaultProxy == proxy) return; // catches repeated nulls mDefaultProxy = proxy; + if (mGlobalProxy != null) return; if (!mDefaultProxyDisabled) { sendProxyBroadcast(proxy); } @@ -3350,10 +3351,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { mDnsOverridden = true; } - // Temporarily disable the default proxy. - synchronized (mDefaultProxyLock) { + // Temporarily disable the default proxy (not global). + synchronized (mProxyLock) { mDefaultProxyDisabled = true; - if (mDefaultProxy != null) { + if (mGlobalProxy == null && mDefaultProxy != null) { sendProxyBroadcast(null); } } @@ -3368,9 +3369,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mHandler.sendEmptyMessage(EVENT_RESTORE_DNS); } } - synchronized (mDefaultProxyLock) { + synchronized (mProxyLock) { mDefaultProxyDisabled = false; - if (mDefaultProxy != null) { + if (mGlobalProxy == null && mDefaultProxy != null) { sendProxyBroadcast(mDefaultProxy); } } From 6bd85ba473d56515354933434041c6113af43be5 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 5 Apr 2013 16:49:32 -0700 Subject: [PATCH 067/296] Routing workaround. Change our order of operations so that secondary route table adds succeed. Working to understand the why of this too. bug:8361314 Change-Id: Ie25061eb38c62eaa5e60aa8a488496de49bdbd9d --- .../android/server/ConnectivityService.java | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9e06db83a3..feb2c8bc5e 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2348,28 +2348,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - for (RouteInfo r : routeDiff.added) { - if (isLinkDefault || ! r.isDefaultRoute()) { - addRoute(newLp, r, TO_DEFAULT_TABLE); - } else { - // add to a secondary route table - addRoute(newLp, r, TO_SECONDARY_TABLE); - - // many radios add a default route even when we don't want one. - // remove the default route unless somebody else has asked for it - String ifaceName = newLp.getInterfaceName(); - if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) { - if (VDBG) log("Removing " + r + " for interface " + ifaceName); - try { - mNetd.removeRoute(ifaceName, r); - } catch (Exception e) { - // never crash - catch them all - if (DBG) loge("Exception trying to remove a route: " + e); - } - } - } - } - if (!isLinkDefault) { // handle DNS routes if (routesChanged) { @@ -2394,6 +2372,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } + + for (RouteInfo r : routeDiff.added) { + if (isLinkDefault || ! r.isDefaultRoute()) { + addRoute(newLp, r, TO_DEFAULT_TABLE); + } else { + // add to a secondary route table + addRoute(newLp, r, TO_SECONDARY_TABLE); + + // many radios add a default route even when we don't want one. + // remove the default route unless somebody else has asked for it + String ifaceName = newLp.getInterfaceName(); + if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) { + if (VDBG) log("Removing " + r + " for interface " + ifaceName); + try { + mNetd.removeRoute(ifaceName, r); + } catch (Exception e) { + // never crash - catch them all + if (DBG) loge("Exception trying to remove a route: " + e); + } + } + } + } + return routesChanged; } From 6477bd0519ae7e66456a37e6774032198a9fbe61 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 10 Apr 2013 15:32:18 -0700 Subject: [PATCH 068/296] Use CONNECTIVITY_INTERNAL for global proxy The Global http proxy shouldn't be used by apps, but can be useful in certain conditions. bug:8264794 bug:8557674 Change-Id: Ia3cbe542e448d9e74d0492626a13e9fd34ad797a --- core/java/android/net/ConnectivityManager.java | 2 +- .../com/android/server/ConnectivityService.java | 15 ++++++++++----- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4e4980d557..78bf9afcbb 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1136,7 +1136,7 @@ public class ConnectivityManager { * HTTP proxy. A {@code null} value will clear the global HTTP proxy. * *

This method requires the call to hold the permission - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. * {@hide} */ public void setGlobalProxy(ProxyProperties p) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ffc36723eb..9adf945bd8 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3045,7 +3045,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public void setGlobalProxy(ProxyProperties proxyProperties) { - enforceChangePermission(); + enforceConnectivityInternalPermission(); synchronized (mProxyLock) { if (proxyProperties == mGlobalProxy) return; if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; @@ -3063,10 +3063,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { mGlobalProxy = null; } ContentResolver res = mContext.getContentResolver(); - Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host); - Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port); - Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, - exclList); + final long token = Binder.clearCallingIdentity(); + try { + Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_HOST, host); + Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port); + Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, + exclList); + } finally { + Binder.restoreCallingIdentity(token); + } } if (mGlobalProxy == null) { From 59070cfd32323f38a3e5b6f38a7365f971afe851 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 11 Apr 2013 13:48:16 -0700 Subject: [PATCH 069/296] Add new route.hasGateway() api Fixes issues brought in by change to isHostRoute. isHostRoute was technically correct, but the callers really wanted hasNextHop behavior. bug:8597268 Change-Id: I360761ccfa98b2ba34642f717a78fa71ec1bae4f --- core/java/android/net/RouteInfo.java | 7 +++++++ services/java/com/android/server/ConnectivityService.java | 3 +-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index cc3c5f7cff..1d051dde49 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -60,6 +60,7 @@ public class RouteInfo implements Parcelable { private final boolean mIsDefault; private final boolean mIsHost; + private final boolean mHasGateway; /** * Constructs a RouteInfo object. @@ -97,6 +98,8 @@ public class RouteInfo implements Parcelable { gateway = Inet6Address.ANY; } } + mHasGateway = (!gateway.isAnyLocalAddress()); + mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); mGateway = gateway; @@ -171,6 +174,10 @@ public class RouteInfo implements Parcelable { return mIsHost; } + public boolean hasGateway() { + return mHasGateway; + } + public String toString() { String val = ""; if (mDestination != null) val = mDestination.toString(); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index f320562d8a..01625dd1eb 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1470,8 +1470,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { loge("Error modifying route - no interface name"); return false; } - - if (r.isHostRoute() == false) { + if (r.hasGateway()) { RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), r.getGateway()); if (bestRoute != null) { if (bestRoute.getGateway().equals(r.getGateway())) { From 75267c4ee9c5480de5c9538f02c61ad4d9cd5ef0 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 19 Apr 2013 09:31:24 -0700 Subject: [PATCH 070/296] Remove STOPSHIP and defer removal. bug:8657300 Change-Id: Ia855fdc0db7a33502838648ee002d4929b224960 --- core/java/android/net/DhcpInfo.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index 2b359ebc11..ab4cd9b9ef 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,8 +22,7 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. - * @deprecated - use LinkProperties - To be removed 11/2013 - * STOPSHIP - make sure we expose LinkProperties through ConnectivityManager + * @deprecated - use LinkProperties - To be removed 11/2014 */ public class DhcpInfo implements Parcelable { public int ipAddress; From 9a37e5d28d0ade280de55352f3f1b86407e3e24e Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 22 Apr 2013 11:13:02 -0700 Subject: [PATCH 071/296] Listen for network disconnect. VPN used to just watch the interface, but that is insufficient. There is no promise that the interface will go down when we're done with it. Now that wifi stays on in scan-only mode despite user turning it off it seems that the interface is left up, even in AP mode. Now listening for ConnectivityService broadcast that the network we were on has disconnected and tearing down the VPN then or when the interface goes away. bug:8550083 Change-Id: Icf414497bc55bead69de04e91f39f90ac2e6578a --- core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 9e9b43d9ab..e5d6e5118b 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -129,4 +129,6 @@ interface IConnectivityManager void captivePortalCheckComplete(in NetworkInfo info); void supplyMessenger(int networkType, in Messenger messenger); + + int findConnectionTypeForIface(in String iface); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 01625dd1eb..c2f4a2c12c 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -544,7 +544,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mTethering.getTetherableBluetoothRegexs().length != 0) && mTethering.getUpstreamIfaceTypes().length != 0); - mVpn = new Vpn(mContext, mVpnCallback, mNetd); + mVpn = new Vpn(mContext, mVpnCallback, mNetd, this); mVpn.startMonitoring(mContext, mTrackerHandler); mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler); @@ -3448,4 +3448,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[networkType].supplyMessenger(messenger); } } + + public int findConnectionTypeForIface(String iface) { + enforceConnectivityInternalPermission(); + + if (TextUtils.isEmpty(iface)) return ConnectivityManager.TYPE_NONE; + for (NetworkStateTracker tracker : mNetTrackers) { + if (tracker != null) { + LinkProperties lp = tracker.getLinkProperties(); + if (lp != null && iface.equals(lp.getInterfaceName())) { + return tracker.getNetworkInfo().getType(); + } + } + } + return ConnectivityManager.TYPE_NONE; + } } From 00fe5095f5c4e9a33120a8aced42273a1c8629cd Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 23 Apr 2013 14:26:51 -0700 Subject: [PATCH 072/296] Support WiFi only device at runtime. To date WiFi only devices were defined by the list of networkAttributes in config.xml overriden in on a per-device basis. This change is the simplest change needed to determine this at runtime and therefore allowing a single build to support the two different configurations. Bug: 8562845 Change-Id: I34de5c6accc718b199c13815537de1debfe3dc91 --- services/java/com/android/server/ConnectivityService.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 01625dd1eb..3eeef9e906 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -432,6 +432,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mRadioAttributes[r.mType] = r; } + // TODO: What is the "correct" way to do determine if this is a wifi only device? + boolean wifiOnly = SystemProperties.getBoolean("ro.radio.noril", false); + log("wifiOnly=" + wifiOnly); String[] naStrings = context.getResources().getStringArray( com.android.internal.R.array.networkAttributes); for (String naString : naStrings) { @@ -442,6 +445,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { n.type); continue; } + if (wifiOnly && ConnectivityManager.isNetworkTypeMobile(n.type)) { + log("networkAttributes - ignoring mobile as this dev is wifiOnly " + + n.type); + continue; + } if (mNetConfigs[n.type] != null) { loge("Error in networkAttributes - ignoring attempt to redefine type " + n.type); From 4398f34e478754975cea606b85e106aed93a5fd2 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 23 May 2013 18:33:06 -0700 Subject: [PATCH 073/296] Use the old interface when resetting connections The new one is often null when disconnected, so using the new fails. In other situations, it's the connections on the old network we want to reset anyway, so the old code when it would work would also do the wrong thing (unless new iface == old iface). bug:9112928 Change-Id: I1fcae89cc3aa9d712e516e7c97cece0b89869bd9 --- services/java/com/android/server/ConnectivityService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3e19094bba..37a8cb85c0 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2261,9 +2261,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault()); if (resetMask != 0 || resetDns) { - LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties(); - if (linkProperties != null) { - for (String iface : linkProperties.getAllInterfaceNames()) { + if (curLp != null) { + for (String iface : curLp.getAllInterfaceNames()) { if (TextUtils.isEmpty(iface) == false) { if (resetMask != 0) { if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")"); @@ -2285,6 +2284,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) loge("Exception resetting dns cache: " + e); } } + } else { + loge("Can't reset connection for type "+netType); } } } From 189a9e0ae9552f69e27dec86a953ca42b332fb95 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 23 May 2013 18:33:06 -0700 Subject: [PATCH 074/296] Use the old interface when resetting connections The new one is often null when disconnected, so using the new fails. In other situations, it's the connections on the old network we want to reset anyway, so the old code when it would work would also do the wrong thing (unless new iface == old iface). bug:9112928 Change-Id: I1fcae89cc3aa9d712e516e7c97cece0b89869bd9 --- services/java/com/android/server/ConnectivityService.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3e19094bba..37a8cb85c0 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2261,9 +2261,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault()); if (resetMask != 0 || resetDns) { - LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties(); - if (linkProperties != null) { - for (String iface : linkProperties.getAllInterfaceNames()) { + if (curLp != null) { + for (String iface : curLp.getAllInterfaceNames()) { if (TextUtils.isEmpty(iface) == false) { if (resetMask != 0) { if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")"); @@ -2285,6 +2284,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) loge("Exception resetting dns cache: " + e); } } + } else { + loge("Can't reset connection for type "+netType); } } } From 23bff230fcd5a719e28bf30aaf763fb79d149314 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Tue, 28 May 2013 15:17:37 -0700 Subject: [PATCH 075/296] Fix parsing of global:http_proxy value. This caused a runtime restart for ':' and did not disable the proxy for "" before. Change-Id: Ib88b21e9eba5818a4968ae604abad8a3b3d1766f --- services/java/com/android/server/ConnectivityService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 37a8cb85c0..6f8c32351f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3134,6 +3134,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { Settings.Global.HTTP_PROXY); if (!TextUtils.isEmpty(proxy)) { String data[] = proxy.split(":"); + if (data.length == 0) { + return; + } + String proxyHost = data[0]; int proxyPort = 8080; if (data.length > 1) { @@ -3145,6 +3149,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } ProxyProperties p = new ProxyProperties(data[0], proxyPort, ""); setGlobalProxy(p); + } else { + setGlobalProxy(null); } } From 79f3e029d41bf505ce42f1744718a71401e1c443 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 4 Jun 2013 12:29:00 -0700 Subject: [PATCH 076/296] Accumulate network statistics based on deltas. Network stats are now read out of the kernel in one sweep, instead of reading per-UID. We now accumulate the delta traffic between each stats snapshot using the well-tested SamplingCounter pattern. Since Wi-Fi and mobile traffic have different costs, track each separately. Avoids counting misc interfaces like loopback and ethernet under total. Bug: 5543387 Change-Id: I642004dc530113c27ef79f2abbae51d8af30117f --- core/java/android/net/ConnectivityManager.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 78bf9afcbb..ffcc2974cd 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -463,6 +463,21 @@ public class ConnectivityManager { } } + /** + * Checks if the given network type is backed by a Wi-Fi radio. + * + * @hide + */ + public static boolean isNetworkTypeWifi(int networkType) { + switch (networkType) { + case TYPE_WIFI: + case TYPE_WIFI_P2P: + return true; + default: + return false; + } + } + /** * Specifies the preferred network type. When the device has more * than one type available the preferred network type will be used. From a891d7bd005a7d90befae7801591c70388b44a83 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 11 Jun 2013 14:13:09 -0700 Subject: [PATCH 077/296] Explicit locale when formatting machine strings. Bug: 9390451 Change-Id: I3581c53407554a1dffd541fb42b06d68f20a7be0 --- core/java/android/net/NetworkUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 4ab479e239..333fcc67bc 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -21,6 +21,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.UnknownHostException; import java.util.Collection; +import java.util.Locale; import android.util.Log; @@ -223,7 +224,7 @@ public class NetworkUtils { public static InetAddress hexToInet6Address(String addrHexString) throws IllegalArgumentException { try { - return numericToInetAddress(String.format("%s:%s:%s:%s:%s:%s:%s:%s", + return numericToInetAddress(String.format(Locale.US, "%s:%s:%s:%s:%s:%s:%s:%s", addrHexString.substring(0,4), addrHexString.substring(4,8), addrHexString.substring(8,12), addrHexString.substring(12,16), addrHexString.substring(16,20), addrHexString.substring(20,24), From 1f5cec7fdcf9978fe52d489f18a499db075f37a1 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Mon, 24 Jun 2013 14:20:23 -0400 Subject: [PATCH 078/296] Move battery stats call from SystemUI to system server. The UPDATE_DEVICE_STATS permission is no longer required in sysui. Change-Id: Icc3120b7873563e3727e56bed9f3b4767da0606d --- services/java/com/android/server/ConnectivityService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 6f8c32351f..54f6118242 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -97,6 +97,7 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; import com.android.server.am.BatteryStatsService; +import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; @@ -346,6 +347,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // the set of network types that can only be enabled by system/sig apps List mProtectedNetworks; + private DataConnectionStats mDataConnectionStats; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -574,6 +577,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); loadGlobalProxy(); + + mDataConnectionStats = new DataConnectionStats(mContext); + mDataConnectionStats.startMonitoring(); } /** From d78d557cb86a5796d47b3257da603902ac1a66fa Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 17 Jun 2013 11:10:27 -0700 Subject: [PATCH 079/296] 464xlat: use a gatewayed route, not point-to-point Various applications such as Skype and our legacy VPN code do not understand routes pointed directly at point-to-point interfaces and require a default gateway IPv4 address in order to function. Grudgingly accept that routes without default gateways Are Hard and use gatewayed routes instead. This causes routing to go from: default dev clat4 scope link to: default via 192.0.0.4 dev clat4 scope link 192.0.0.4 dev clat4 scope link and those apps now work. Bug: 9597256 Bug: 9597516 Change-Id: I7b7890873802d3cb99affd6eb70b8ab75e7a2cf6 --- .../server/connectivity/Nat464Xlat.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/java/com/android/server/connectivity/Nat464Xlat.java index 59403c559d..a15d678520 100644 --- a/services/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/java/com/android/server/connectivity/Nat464Xlat.java @@ -147,17 +147,24 @@ public class Nat464Xlat extends BaseNetworkObserver { " added, mIsRunning = " + mIsRunning + " -> true"); mIsRunning = true; - // Get the network configuration of the clat interface, store it - // in our link properties, and stack it on top of the interface - // it's running on. + // Create the LinkProperties for the clat interface by fetching the + // IPv4 address for the interface and adding an IPv4 default route, + // then stack the LinkProperties on top of the link it's running on. + // Although the clat interface is a point-to-point tunnel, we don't + // point the route directly at the interface because some apps don't + // understand routes without gateways (see, e.g., http://b/9597256 + // http://b/9597516). Instead, set the next hop of the route to the + // clat IPv4 address itself (for those apps, it doesn't matter what + // the IP of the gateway is, only that there is one). try { InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); + LinkAddress clatAddress = config.getLinkAddress(); mLP.clear(); mLP.setInterfaceName(iface); - RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), null, - iface); + RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), + clatAddress.getAddress(), iface); mLP.addRoute(ipv4Default); - mLP.addLinkAddress(config.getLinkAddress()); + mLP.addLinkAddress(clatAddress); mTracker.addStackedLink(mLP); Slog.i(TAG, "Adding stacked link. tracker LP: " + mTracker.getLinkProperties()); From 32506bca6f5d618cbd1b157d99ff97dca64f9229 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 29 Jun 2013 21:10:57 -0700 Subject: [PATCH 080/296] Add checkMobileProvisioning to ConnectivityService. Bug: 9279964 Change-Id: I42c326a21e05aa301e9d974ed9ac1d59472780ec --- .../java/android/net/ConnectivityManager.java | 64 +++ .../android/net/IConnectivityManager.aidl | 3 + .../android/server/ConnectivityService.java | 512 +++++++++++++++++- 3 files changed, 576 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 78bf9afcbb..6487c9267e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -25,6 +25,7 @@ import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Messenger; import android.os.RemoteException; +import android.os.ResultReceiver; import android.provider.Settings; import java.net.InetAddress; @@ -1294,4 +1295,67 @@ public class ConnectivityManager { } catch (RemoteException e) { } } + + /** + * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) + */ + + /** + * No connection was possible to the network. + * {@hide} + */ + public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; + + /** + * A connection was made to the internet, all is well. + * {@hide} + */ + public static final int CMP_RESULT_CODE_CONNECTABLE = 1; + + /** + * A connection was made but there was a redirection, we appear to be in walled garden. + * This is an indication of a warm sim on a mobile network. + * {@hide} + */ + public static final int CMP_RESULT_CODE_REDIRECTED = 2; + + /** + * A connection was made but no dns server was available to resolve a name to address. + * This is an indication of a warm sim on a mobile network. + * + * {@hide} + */ + public static final int CMP_RESULT_CODE_NO_DNS = 3; + + /** + * A connection was made but could not open a TCP connection. + * This is an indication of a warm sim on a mobile network. + * {@hide} + */ + public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; + + /** + * Check mobile provisioning. The resultCode passed to + * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above. + * This may take a minute or more to complete. + * + * @param sendNotificaiton, when true a notification will be sent to user. + * @param suggestedTimeOutMs, timeout in milliseconds + * @param resultReceiver needs to be supplied to receive the result + * + * @return time out that will be used, maybe less that suggestedTimeOutMs + * -1 if an error. + * + * {@hide} + */ + public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, + ResultReceiver resultReceiver) { + int timeOutMs = -1; + try { + timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs, + resultReceiver); + } catch (RemoteException e) { + } + return timeOutMs; + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index e5d6e5118b..3dbe078313 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -24,6 +24,7 @@ import android.net.ProxyProperties; import android.os.IBinder; import android.os.Messenger; import android.os.ParcelFileDescriptor; +import android.os.ResultReceiver; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; @@ -131,4 +132,6 @@ interface IConnectivityManager void supplyMessenger(int networkType, in Messenger messenger); int findConnectionTypeForIface(in String iface); + + int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 37a8cb85c0..9e9253a0f3 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -31,6 +31,9 @@ import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import android.app.Notification; +import android.app.NotificationManager; +import android.app.PendingIntent; import android.bluetooth.BluetoothTetheringDataTracker; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -52,11 +55,13 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.Uri; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkInfo.State; import android.net.NetworkQuotaInfo; import android.net.NetworkState; import android.net.NetworkStateTracker; @@ -66,6 +71,7 @@ import android.net.ProxyProperties; import android.net.RouteInfo; import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; +import android.os.AsyncTask; import android.os.Binder; import android.os.FileUtils; import android.os.Handler; @@ -79,6 +85,7 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; +import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; @@ -86,13 +93,16 @@ import android.os.UserHandle; import android.provider.Settings; import android.security.Credentials; import android.security.KeyStore; +import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; import android.util.SparseIntArray; +import com.android.internal.R; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; +import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; @@ -111,9 +121,11 @@ import java.io.FileDescriptor; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Constructor; +import java.net.HttpURLConnection; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; +import java.net.URL; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; @@ -121,6 +133,8 @@ import java.util.Collection; import java.util.GregorianCalendar; import java.util.HashSet; import java.util.List; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; /** * @hide @@ -141,6 +155,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String NETWORK_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; + // Default value if FAIL_FAST_TIME_MS is not set + private static final int DEFAULT_FAIL_FAST_TIME_MS = 1 * 60 * 1000; + // system property that can override DEFAULT_FAIL_FAST_TIME_MS + private static final String FAIL_FAST_TIME_MS = + "persist.radio.fail_fast_time_ms"; + // used in recursive route setting to add gateways for the host for which // a host route was requested. private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10; @@ -292,6 +312,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int EVENT_VPN_STATE_CHANGED = 14; + /** + * Used internally to disable fail fast of mobile data + */ + private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 15; + /** Handler used for internal events. */ private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -346,6 +371,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { // the set of network types that can only be enabled by system/sig apps List mProtectedNetworks; + private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0); + + TelephonyManager mTelephonyManager; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -394,6 +423,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetd = checkNotNull(netManager, "missing INetworkManagementService"); mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); mKeyStore = KeyStore.getInstance(); + mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); try { mPolicyManager.registerListener(mPolicyListener); @@ -1408,8 +1438,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { netState != DetailedState.CAPTIVE_PORTAL_CHECK) || tracker.isTeardownRequested()) { if (VDBG) { - log("requestRouteToHostAddress on down network " + - "(" + networkType + ") - dropped"); + log("requestRouteToHostAddress on down network " + + "(" + networkType + ") - dropped" + + " tracker=" + tracker + + " netState=" + netState + + " isTeardownRequested=" + + ((tracker != null) ? tracker.isTeardownRequested() : "tracker:null")); } return false; } @@ -1417,12 +1451,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { InetAddress addr = InetAddress.getByAddress(hostAddress); LinkProperties lp = tracker.getLinkProperties(); - return addRouteToAddress(lp, addr); + boolean ok = addRouteToAddress(lp, addr); + if (DBG) log("requestRouteToHostAddress ok=" + ok); + return ok; } catch (UnknownHostException e) { if (DBG) log("requestRouteToHostAddress got " + e.toString()); } finally { Binder.restoreCallingIdentity(token); } + if (DBG) log("requestRouteToHostAddress X bottom return false"); return false; } @@ -2824,6 +2861,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { } break; } + case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: { + int tag = mEnableFailFastMobileDataTag.get(); + if (msg.arg1 == tag) { + MobileDataStateTracker mobileDst = + (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + if (mobileDst != null) { + mobileDst.setEnableFailFastMobileData(msg.arg2); + } + } else { + log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1 + + " != tag:" + tag); + } + } } } } @@ -3472,4 +3522,460 @@ public class ConnectivityService extends IConnectivityManager.Stub { } return ConnectivityManager.TYPE_NONE; } + + /** + * Have mobile data fail fast if enabled. + * + * @param enabled DctConstants.ENABLED/DISABLED + */ + private void setEnableFailFastMobileData(int enabled) { + int tag; + + if (enabled == DctConstants.ENABLED) { + tag = mEnableFailFastMobileDataTag.incrementAndGet(); + } else { + tag = mEnableFailFastMobileDataTag.get(); + } + mHandler.sendMessage(mHandler.obtainMessage(EVENT_ENABLE_FAIL_FAST_MOBILE_DATA, tag, + enabled)); + } + + @Override + public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, + final ResultReceiver resultReceiver) { + log("checkMobileProvisioning: E sendNotification=" + sendNotification + + " suggestedTimeOutMs=" + suggestedTimeOutMs + + " resultReceiver=" + resultReceiver); + enforceChangePermission(); + + int timeOutMs = suggestedTimeOutMs; + if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { + timeOutMs = CheckMp.MAX_TIMEOUT_MS; + } + + final long token = Binder.clearCallingIdentity(); + try { + CheckMp checkMp = new CheckMp(mContext, this); + CheckMp.CallBack cb = new CheckMp.CallBack() { + @Override + void onComplete(Integer result) { + log("CheckMp.onComplete: result=" + result); + if (resultReceiver != null) { + log("CheckMp.onComplete: send result"); + resultReceiver.send(result, null); + } + NetworkInfo ni = + mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); + switch(result) { + case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE: + case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: { + log("CheckMp.onComplete: ignore, connected or no connection"); + break; + } + case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { + log("CheckMp.onComplete: warm sim"); + String url = getProvisioningUrl(); + if (TextUtils.isEmpty(url)) { + url = mContext.getResources() + .getString(R.string.mobile_redirected_provisioning_url); + } + if (TextUtils.isEmpty(url) == false) { + log("CheckMp.onComplete: warm sim (redirected), url=" + url); + setNotificationVisible(true, ni, url); + } else { + log("CheckMp.onComplete: warm sim (redirected), no url"); + } + break; + } + case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: + case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { + String url = getProvisioningUrl(); + if (TextUtils.isEmpty(url) == false) { + log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); + setNotificationVisible(true, ni, url); + } else { + log("CheckMp.onComplete: warm sim (no dns/tcp), no url"); + } + break; + } + default: { + loge("CheckMp.onComplete: ignore unexpected result=" + result); + break; + } + } + } + }; + CheckMp.Params params = + new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); + log("checkMobileProvisioning: params=" + params); + setNotificationVisible(false, null, null); + checkMp.execute(params); + } finally { + Binder.restoreCallingIdentity(token); + log("checkMobileProvisioning: X"); + } + return timeOutMs; + } + + static class CheckMp extends + AsyncTask { + private static final String CHECKMP_TAG = "CheckMp"; + public static final int MAX_TIMEOUT_MS = 60000; + private static final int SOCKET_TIMEOUT_MS = 5000; + private Context mContext; + private ConnectivityService mCs; + private TelephonyManager mTm; + private Params mParams; + + /** + * Parameters for AsyncTask.execute + */ + static class Params { + private String mUrl; + private long mTimeOutMs; + private CallBack mCb; + + Params(String url, long timeOutMs, CallBack cb) { + mUrl = url; + mTimeOutMs = timeOutMs; + mCb = cb; + } + + @Override + public String toString() { + return "{" + " url=" + mUrl + " mTimeOutMs=" + mTimeOutMs + " mCb=" + mCb + "}"; + } + } + + /** + * The call back object passed in Params. onComplete will be called + * on the main thread. + */ + abstract static class CallBack { + // Called on the main thread. + abstract void onComplete(Integer result); + } + + public CheckMp(Context context, ConnectivityService cs) { + mContext = context; + mCs = cs; + + // Setup access to TelephonyService we'll be using. + mTm = (TelephonyManager) mContext.getSystemService( + Context.TELEPHONY_SERVICE); + } + + /** + * Get the default url to use for the test. + */ + public String getDefaultUrl() { + // See http://go/clientsdns for usage approval + String server = Settings.Global.getString(mContext.getContentResolver(), + Settings.Global.CAPTIVE_PORTAL_SERVER); + if (server == null) { + server = "clients3.google.com"; + } + return "http://" + server + "/generate_204"; + } + + /** + * Detect if its possible to connect to the http url. DNS based detection techniques + * do not work at all hotspots. The best way to check is to perform a request to + * a known address that fetches the data we expect. + */ + private synchronized Integer isMobileOk(Params params) { + Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + Uri orgUri = Uri.parse(params.mUrl); + Random rand = new Random(); + mParams = params; + + try { + if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { + log("isMobileOk: not mobile capable"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + return result; + } + + // Enable fail fast as we'll do retries here and use a + // hipri connection so the default connection stays active. + log("isMobileOk: start hipri url=" + params.mUrl); + mCs.setEnableFailFastMobileData(DctConstants.ENABLED); + mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + Phone.FEATURE_ENABLE_HIPRI, new Binder()); + + // Continue trying to connect until time has run out + long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + while(SystemClock.elapsedRealtime() < endTime) { + try { + // Wait for hipri to connect. + // TODO: Don't poll and handle situation where hipri fails + // because default is retrying. See b/9569540 + NetworkInfo.State state = mCs + .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); + if (state != NetworkInfo.State.CONNECTED) { + log("isMobileOk: not connected ni=" + + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + sleep(1); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + continue; + } + + // Get of the addresses associated with the url host. We need to use the + // address otherwise HttpURLConnection object will use the name to get + // the addresses and is will try every address but that will bypass the + // route to host we setup and the connection could succeed as the default + // interface might be connected to the internet via wifi or other interface. + InetAddress[] addresses; + try { + addresses = InetAddress.getAllByName(orgUri.getHost()); + } catch (UnknownHostException e) { + log("isMobileOk: UnknownHostException"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS; + return result; + } + log("isMobileOk: addresses=" + inetAddressesToString(addresses)); + + // Get the type of addresses supported by this link + LinkProperties lp = mCs.getLinkProperties( + ConnectivityManager.TYPE_MOBILE_HIPRI); + boolean linkHasIpv4 = hasIPv4Address(lp); + boolean linkHasIpv6 = hasIPv6Address(lp); + log("isMobileOk: linkHasIpv4=" + linkHasIpv4 + + " linkHasIpv6=" + linkHasIpv6); + + // Loop through at most 3 valid addresses or all of the address or until + // we run out of time + int loops = Math.min(3, addresses.length); + for(int validAddr=0, addrTried=0; + (validAddr < loops) && (addrTried < addresses.length) + && (SystemClock.elapsedRealtime() < endTime); + addrTried ++) { + + // Choose the address at random but make sure its type is supported + InetAddress hostAddr = addresses[rand.nextInt(addresses.length)]; + if (((hostAddr instanceof Inet4Address) && linkHasIpv4) + || ((hostAddr instanceof Inet6Address) && linkHasIpv6)) { + // Valid address, so use it + validAddr += 1; + } else { + // Invalid address so try next address + continue; + } + + // Make a route to host so we check the specific interface. + if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI, + hostAddr.getAddress())) { + // Wait a short time to be sure the route is established ?? + log("isMobileOk:" + + " wait to establish route to hostAddr=" + hostAddr); + sleep(3); + } else { + log("isMobileOk:" + + " could not establish route to hostAddr=" + hostAddr); + continue; + } + + // Rewrite the url to have numeric address to use the specific route. + // I also set the "Connection" to "Close" as by default "Keep-Alive" + // is used which is useless in this case. + URL newUrl = new URL(orgUri.getScheme() + "://" + + hostAddr.getHostAddress() + orgUri.getPath()); + log("isMobileOk: newUrl=" + newUrl); + + HttpURLConnection urlConn = null; + try { + // Open the connection set the request header and get the response + urlConn = (HttpURLConnection) newUrl.openConnection( + java.net.Proxy.NO_PROXY); + urlConn.setInstanceFollowRedirects(false); + urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS); + urlConn.setReadTimeout(SOCKET_TIMEOUT_MS); + urlConn.setUseCaches(false); + urlConn.setAllowUserInteraction(false); + urlConn.setRequestProperty("Connection", "close"); + int responseCode = urlConn.getResponseCode(); + if (responseCode == 204) { + result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE; + } else { + result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED; + } + log("isMobileOk: connected responseCode=" + responseCode); + urlConn.disconnect(); + urlConn = null; + return result; + } catch (Exception e) { + log("isMobileOk: HttpURLConnection Exception e=" + e); + if (urlConn != null) { + urlConn.disconnect(); + urlConn = null; + } + } + } + result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION; + log("isMobileOk: loops|timed out"); + return result; + } catch (Exception e) { + log("isMobileOk: Exception e=" + e); + continue; + } + } + log("isMobileOk: timed out"); + } finally { + log("isMobileOk: F stop hipri"); + mCs.setEnableFailFastMobileData(DctConstants.DISABLED); + mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + Phone.FEATURE_ENABLE_HIPRI); + log("isMobileOk: X result=" + result); + } + return result; + } + + @Override + protected Integer doInBackground(Params... params) { + return isMobileOk(params[0]); + } + + @Override + protected void onPostExecute(Integer result) { + log("onPostExecute: result=" + result); + if ((mParams != null) && (mParams.mCb != null)) { + mParams.mCb.onComplete(result); + } + } + + private String inetAddressesToString(InetAddress[] addresses) { + StringBuffer sb = new StringBuffer(); + boolean firstTime = true; + for(InetAddress addr : addresses) { + if (firstTime) { + firstTime = false; + } else { + sb.append(","); + } + sb.append(addr); + } + return sb.toString(); + } + + private void printNetworkInfo() { + boolean hasIccCard = mTm.hasIccCard(); + int simState = mTm.getSimState(); + log("hasIccCard=" + hasIccCard + + " simState=" + simState); + NetworkInfo[] ni = mCs.getAllNetworkInfo(); + if (ni != null) { + log("ni.length=" + ni.length); + for (NetworkInfo netInfo: ni) { + log("netInfo=" + netInfo.toString()); + } + } else { + log("no network info ni=null"); + } + } + + /** + * Sleep for a few seconds then return. + * @param seconds + */ + private static void sleep(int seconds) { + try { + Thread.sleep(seconds * 1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + public boolean hasIPv4Address(LinkProperties lp) { + return lp.hasIPv4Address(); + } + + // Not implemented in LinkProperties, do it here. + public boolean hasIPv6Address(LinkProperties lp) { + for (LinkAddress address : lp.getLinkAddresses()) { + if (address.getAddress() instanceof Inet6Address) { + return true; + } + } + return false; + } + + private void log(String s) { + Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s); + } + } + + private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + + private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) { + log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url); + + Resources r = Resources.getSystem(); + NotificationManager notificationManager = (NotificationManager) mContext + .getSystemService(Context.NOTIFICATION_SERVICE); + + if (visible) { + CharSequence title; + CharSequence details; + int icon; + switch (networkInfo.getType()) { + case ConnectivityManager.TYPE_WIFI: + log("setNotificationVisible: TYPE_WIFI"); + title = r.getString(R.string.wifi_available_sign_in, 0); + details = r.getString(R.string.network_available_sign_in_detailed, + networkInfo.getExtraInfo()); + icon = R.drawable.stat_notify_wifi_in_range; + break; + case ConnectivityManager.TYPE_MOBILE: + case ConnectivityManager.TYPE_MOBILE_HIPRI: + log("setNotificationVisible: TYPE_MOBILE|HIPRI"); + title = r.getString(R.string.network_available_sign_in, 0); + // TODO: Change this to pull from NetworkInfo once a printable + // name has been added to it + details = mTelephonyManager.getNetworkOperatorName(); + icon = R.drawable.stat_notify_rssi_in_range; + break; + default: + log("setNotificationVisible: other type=" + networkInfo.getType()); + title = r.getString(R.string.network_available_sign_in, 0); + details = r.getString(R.string.network_available_sign_in_detailed, + networkInfo.getExtraInfo()); + icon = R.drawable.stat_notify_rssi_in_range; + break; + } + + Notification notification = new Notification(); + notification.when = 0; + notification.icon = icon; + notification.flags = Notification.FLAG_AUTO_CANCEL; + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); + notification.tickerText = title; + notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); + + log("setNotificaitionVisible: notify notificaiton=" + notification); + notificationManager.notify(NOTIFICATION_ID, 1, notification); + } else { + log("setNotificaitionVisible: cancel"); + notificationManager.cancel(NOTIFICATION_ID, 1); + } + log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); + } + + private String getProvisioningUrl() { + String url = mContext.getResources().getString(R.string.mobile_provisioning_url); + log("getProvisioningUrl: resource url=" + url); + + // populate the iccid and imei in the provisioning url. + if (!TextUtils.isEmpty(url)) { + url = String.format(url, + mTelephonyManager.getSimSerialNumber() /* ICCID */, + mTelephonyManager.getDeviceId() /* IMEI */, + mTelephonyManager.getLine1Number() /* Phone numer */); + } + + log("getProvisioningUrl: url=" + url); + return url; + } } From d469c47d5b30d36df54e3183331cf60e2f368845 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 2 Jul 2013 10:55:14 -0700 Subject: [PATCH 081/296] Fix NPE if mobile is not supported in checkMobileProvisioning. Bug: 9664438 Change-Id: If0c4938956a80e8d6a21a968aa771d0d8f546b3c --- .../java/com/android/server/ConnectivityService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9e9253a0f3..e7dd3b79e3 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3553,6 +3553,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { timeOutMs = CheckMp.MAX_TIMEOUT_MS; } + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + log("checkMobileProvisioning: X no mobile network"); + if (resultReceiver != null) { + resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); + } + return timeOutMs; + } + final long token = Binder.clearCallingIdentity(); try { CheckMp checkMp = new CheckMp(mContext, this); From 3ef153324c06e826903f6d4171d8e435cfb3790c Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 2 Jul 2013 10:55:14 -0700 Subject: [PATCH 082/296] Fix NPE if mobile is not supported in checkMobileProvisioning. Bug: 9664438 Change-Id: If0c4938956a80e8d6a21a968aa771d0d8f546b3c --- .../java/com/android/server/ConnectivityService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9e9253a0f3..e7dd3b79e3 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3553,6 +3553,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { timeOutMs = CheckMp.MAX_TIMEOUT_MS; } + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + log("checkMobileProvisioning: X no mobile network"); + if (resultReceiver != null) { + resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); + } + return timeOutMs; + } + final long token = Binder.clearCallingIdentity(); try { CheckMp checkMp = new CheckMp(mContext, this); From 37302074650054778f890453f628caa30e7f2f5d Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 2 Jul 2013 12:41:31 -0700 Subject: [PATCH 083/296] am 6152916c: am db011499: am 753d754c: Merge "Fix NPE if mobile is not supported in checkMobileProvisioning." into jb-mr2-dev * commit '6152916c450942c6eeae8270eb2aed9a16639295': Fix NPE if mobile is not supported in checkMobileProvisioning. --- .../java/com/android/server/ConnectivityService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index fc346a25b7..f2e0f2988e 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3564,6 +3564,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { timeOutMs = CheckMp.MAX_TIMEOUT_MS; } + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + log("checkMobileProvisioning: X no mobile network"); + if (resultReceiver != null) { + resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); + } + return timeOutMs; + } + final long token = Binder.clearCallingIdentity(); try { CheckMp checkMp = new CheckMp(mContext, this); From c118d7efab07dd0bbebbf63f43cb9b068f8a1123 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 10 Jul 2013 23:00:07 -0700 Subject: [PATCH 084/296] VZW wants the phoneNumber to be 10 zero's if there isn't one. Bug: 9784059 Change-Id: I41bba908855648d2560440655d8a75a7cb2e0859 --- .../java/com/android/server/ConnectivityService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index e7dd3b79e3..29c546e197 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3975,17 +3975,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { private String getProvisioningUrl() { String url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: resource url=" + url); + log("getProvisioningUrl: mobile_provisioning_url=" + url); - // populate the iccid and imei in the provisioning url. + // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { + String phoneNumber = mTelephonyManager.getLine1Number(); + if (TextUtils.isEmpty(phoneNumber)) { + phoneNumber = "0000000000"; + } url = String.format(url, mTelephonyManager.getSimSerialNumber() /* ICCID */, mTelephonyManager.getDeviceId() /* IMEI */, - mTelephonyManager.getLine1Number() /* Phone numer */); + phoneNumber /* Phone numer */); } - log("getProvisioningUrl: url=" + url); return url; } } From 3f3b4e646263eb53cc90531b3d9cd32bb9a7b162 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Thu, 11 Jul 2013 13:30:36 -0700 Subject: [PATCH 085/296] Add NetworkUtil function for marking sockets Add NetworkUtil function for setting the SO_MARK field of sockets Change-Id: I94389b64296d87ee928293f24a26f8dd08c3bf37 --- core/java/android/net/NetworkUtils.java | 5 +++++ core/jni/android_net_NetUtils.cpp | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 333fcc67bc..b24d3969f7 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -103,6 +103,11 @@ public class NetworkUtils { */ public native static String getDhcpError(); + /** + * Set the SO_MARK of {@code socketfd} to {@code mark} + */ + public native static void markSocket(int socketfd, int mark); + /** * Convert a IPv4 address from an integer to an InetAddress. * @param hostAddress an int corresponding to the IPv4 address in network byte order diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index faae11ec3b..526159f4f1 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "NetUtils" #include "jni.h" +#include "JNIHelp.h" #include #include #include @@ -239,6 +240,13 @@ static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz) return env->NewStringUTF(::dhcp_get_errmsg()); } +static void android_net_utils_markSocket(JNIEnv *env, jobject thiz, jint socket, jint mark) +{ + if (setsockopt(socket, SOL_SOCKET, SO_MARK, &mark, sizeof(mark)) < 0) { + jniThrowException(env, "java/lang/IllegalStateException", "Error marking socket"); + } +} + // ---------------------------------------------------------------------------- /* @@ -255,6 +263,7 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "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 }, + { "markSocket", "(II)V", (void*) android_net_utils_markSocket }, }; int register_android_net_NetworkUtils(JNIEnv* env) From b7652cde9deb742f2b218a49ae765158c4a18bf1 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 14 Jun 2013 11:16:51 -0700 Subject: [PATCH 086/296] Add per user VPN support VPNs are now per user instead of global. A VPN set by user A routes only user A's traffic and no other user can access it. Change-Id: Ia66463637b6bd088b05768076a1db897fe95c46c --- .../android/server/ConnectivityService.java | 158 ++++++++++++++++-- 1 file changed, 144 insertions(+), 14 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b148b91219..a6344cafab 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -97,6 +97,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; import android.util.SparseIntArray; +import android.util.SparseArray; import com.android.internal.R; import com.android.internal.net.LegacyVpnInfo; @@ -116,6 +117,8 @@ import com.android.server.net.LockdownVpnTracker; import com.google.android.collect.Lists; import com.google.android.collect.Sets; +import com.android.internal.annotations.GuardedBy; + import dalvik.system.DexClassLoader; import java.io.FileDescriptor; @@ -171,7 +174,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private KeyStore mKeyStore; - private Vpn mVpn; + @GuardedBy("mVpns") + private final SparseArray mVpns = new SparseArray(); private VpnCallback mVpnCallback = new VpnCallback(); private boolean mLockdownEnabled; @@ -583,10 +587,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { mTethering.getTetherableWifiRegexs().length != 0 || mTethering.getTetherableBluetoothRegexs().length != 0) && mTethering.getUpstreamIfaceTypes().length != 0); + //set up the listener for user state for creating user VPNs - mVpn = new Vpn(mContext, mVpnCallback, mNetd, this); - mVpn.startMonitoring(mContext, mTrackerHandler); - + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(Intent.ACTION_USER_STARTING); + intentFilter.addAction(Intent.ACTION_USER_STOPPING); + mContext.registerReceiverAsUser( + mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); mClat = new Nat464Xlat(mContext, mNetd, this, mTrackerHandler); try { @@ -2313,7 +2320,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Tell VPN the interface is down. It is a temporary // but effective fix to make VPN aware of the change. if ((resetMask & NetworkUtils.RESET_IPV4_ADDRESSES) != 0) { - mVpn.interfaceStatusChanged(iface, false); + synchronized(mVpns) { + for (int i = 0; i < mVpns.size(); i++) { + mVpns.valueAt(i).interfaceStatusChanged(iface, false); + } + } } } if (resetDns) { @@ -2570,7 +2581,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); - mNetd.setDefaultInterfaceForDns(iface); for (InetAddress dns : dnses) { ++last; String key = "net.dns" + last; @@ -3305,8 +3315,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { throwIfLockdownEnabled(); try { int type = mActiveDefaultNetwork; + int user = UserHandle.getUserId(Binder.getCallingUid()); if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) { - mVpn.protect(socket, mNetTrackers[type].getLinkProperties().getInterfaceName()); + synchronized(mVpns) { + mVpns.get(user).protect(socket, + mNetTrackers[type].getLinkProperties().getInterfaceName()); + } return true; } } catch (Exception e) { @@ -3330,7 +3344,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public boolean prepareVpn(String oldPackage, String newPackage) { throwIfLockdownEnabled(); - return mVpn.prepare(oldPackage, newPackage); + int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized(mVpns) { + return mVpns.get(user).prepare(oldPackage, newPackage); + } } /** @@ -3343,7 +3360,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public ParcelFileDescriptor establishVpn(VpnConfig config) { throwIfLockdownEnabled(); - return mVpn.establish(config); + int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized(mVpns) { + return mVpns.get(user).establish(config); + } } /** @@ -3357,7 +3377,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (egress == null) { throw new IllegalStateException("Missing active network connection"); } - mVpn.startLegacyVpn(profile, mKeyStore, egress); + int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized(mVpns) { + mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress); + } } /** @@ -3369,7 +3392,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public LegacyVpnInfo getLegacyVpnInfo() { throwIfLockdownEnabled(); - return mVpn.getLegacyVpnInfo(); + int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized(mVpns) { + return mVpns.get(user).getLegacyVpnInfo(); + } } /** @@ -3390,7 +3416,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget(); } - public void override(List dnsServers, List searchDomains) { + public void override(String iface, List dnsServers, List searchDomains) { if (dnsServers == null) { restore(); return; @@ -3422,7 +3448,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Apply DNS changes. synchronized (mDnsLock) { - updateDnsLocked("VPN", "VPN", addresses, domains); + updateDnsLocked("VPN", iface, addresses, domains); mDnsOverridden = true; } @@ -3451,6 +3477,67 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } + + public void protect(ParcelFileDescriptor socket) { + try { + final int mark = mNetd.getMarkForProtect(); + NetworkUtils.markSocket(socket.getFd(), mark); + } catch (RemoteException e) { + } + } + + public void setRoutes(String interfaze, List routes) { + for (RouteInfo route : routes) { + try { + mNetd.setMarkedForwardingRoute(interfaze, route); + } catch (RemoteException e) { + } + } + } + + public void setMarkedForwarding(String interfaze) { + try { + mNetd.setMarkedForwarding(interfaze); + } catch (RemoteException e) { + } + } + + public void clearMarkedForwarding(String interfaze) { + try { + mNetd.clearMarkedForwarding(interfaze); + } catch (RemoteException e) { + } + } + + public void addUserForwarding(String interfaze, int uid) { + int uidStart = uid * UserHandle.PER_USER_RANGE; + int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1; + addUidForwarding(interfaze, uidStart, uidEnd); + } + + public void clearUserForwarding(String interfaze, int uid) { + int uidStart = uid * UserHandle.PER_USER_RANGE; + int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1; + clearUidForwarding(interfaze, uidStart, uidEnd); + } + + public void addUidForwarding(String interfaze, int uidStart, int uidEnd) { + try { + mNetd.setUidRangeRoute(interfaze,uidStart, uidEnd); + mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); + } catch (RemoteException e) { + } + + } + + public void clearUidForwarding(String interfaze, int uidStart, int uidEnd) { + try { + mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd); + mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd); + } catch (RemoteException e) { + } + + } } @Override @@ -3471,7 +3558,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN)); final VpnProfile profile = VpnProfile.decode( profileName, mKeyStore.get(Credentials.VPN + profileName)); - setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpn, profile)); + int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized(mVpns) { + setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user), + profile)); + } } else { setLockdownTracker(null); } @@ -4002,4 +4093,43 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + + private void onUserStart(int userId) { + synchronized(mVpns) { + Vpn userVpn = mVpns.get(userId); + if (userVpn != null) { + loge("Starting user already has a VPN"); + return; + } + userVpn = new Vpn(mContext, mVpnCallback, mNetd, this, userId); + mVpns.put(userId, userVpn); + userVpn.startMonitoring(mContext, mTrackerHandler); + } + } + + private void onUserStop(int userId) { + synchronized(mVpns) { + Vpn userVpn = mVpns.get(userId); + if (userVpn == null) { + loge("Stopping user has no VPN"); + return; + } + mVpns.delete(userId); + } + } + + private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String action = intent.getAction(); + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); + if (userId == UserHandle.USER_NULL) return; + + if (Intent.ACTION_USER_STARTING.equals(action)) { + onUserStart(userId); + } else if (Intent.ACTION_USER_STOPPING.equals(action)) { + onUserStop(userId); + } + } + }; } From 11f2225c3dbd285d9f4d0033e85f67b2c9683afb Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Thu, 11 Jul 2013 13:29:30 -0700 Subject: [PATCH 087/296] Support routing sockets as another user Add support for routing sockets as if they were another user's. This is for services that handle delegated network tasks like MediaServer and DownloadManager. Change-Id: Id20efc1f5c2cce6f8838d777762f6c0a703a9437 --- .../android/net/IConnectivityManager.aidl | 2 ++ .../android/server/ConnectivityService.java | 27 +++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3dbe078313..7ee10c3f12 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -119,6 +119,8 @@ interface IConnectivityManager boolean prepareVpn(String oldPackage, String newPackage); + void markSocketAsUser(in ParcelFileDescriptor socket, int uid); + ParcelFileDescriptor establishVpn(in VpnConfig config); void startLegacyVpn(in VpnProfile profile); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a6344cafab..476a6fdffb 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1749,6 +1749,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { "ConnectivityService"); } + private void enforceMarkNetworkSocketPermission() { + //Media server special case + if (Binder.getCallingUid() == Process.MEDIA_UID) { + return; + } + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.MARK_NETWORK_SOCKET, + "ConnectivityService"); + } + /** * Handle a {@code DISCONNECTED} event. If this pertains to the non-active * network, we ignore it. If it is for the active network, we send out a @@ -3350,6 +3360,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + @Override + public void markSocketAsUser(ParcelFileDescriptor socket, int uid) { + enforceMarkNetworkSocketPermission(); + final long token = Binder.clearCallingIdentity(); + try { + int mark = mNetd.getMarkForUid(uid); + // Clear the mark on the socket if no mark is needed to prevent socket reuse issues + if (mark == -1) { + mark = 0; + } + NetworkUtils.markSocket(socket.getFd(), mark); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(token); + } + } + /** * Configure a TUN interface and return its file descriptor. Parameters * are encoded and opaque to this class. This method is used by VpnBuilder From dc7e3ee3ad86e155284a73e5a2480cde2c793d28 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 16 Jul 2013 11:22:32 -0700 Subject: [PATCH 088/296] Move markSocketAsUser to the top of IConnectivityManager.aidl Move markSocketAsUser to the top of IConnectivityManager.aidl to make calls from framework/native/services/connectivitymanager less fragile Change-Id: Iba92c21dfef175b570521f34e7ee2732e5a0a9c9 --- core/java/android/net/IConnectivityManager.aidl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 7ee10c3f12..d537b32ff1 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -37,6 +37,9 @@ import com.android.internal.net.VpnProfile; /** {@hide} */ interface IConnectivityManager { + // Keep this in sync with framework/native/services/connectivitymanager/ConnectivityManager.h + void markSocketAsUser(in ParcelFileDescriptor socket, int uid); + void setNetworkPreference(int pref); int getNetworkPreference(); @@ -119,8 +122,6 @@ interface IConnectivityManager boolean prepareVpn(String oldPackage, String newPackage); - void markSocketAsUser(in ParcelFileDescriptor socket, int uid); - ParcelFileDescriptor establishVpn(in VpnConfig config); void startLegacyVpn(in VpnProfile profile); From f0e9c7fc7fbdd037d4204126c1c54cbfd9ffee4f Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 16 Jul 2013 17:16:37 -0700 Subject: [PATCH 089/296] When a SIM is changed check mobile provisioning. A simple mechanism for doing this is to take advantage of the fact that we require the device to reboot after a sim has been changed. Thus when connectivity service is started we wait to get a connection then call checkMobileProvisioning once. We also add a check that the DEVICE_PROVISIONED is true, i.e. SetupWizard has been run. Bug: 9784024 Change-Id: I5c1936744f6fc55a447ae44cd36eec3849d27e21 --- .../com/android/server/ConnectivityService.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 29c546e197..ca5fc181dc 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -375,6 +375,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; + // We only want one checkMobileProvisioning after booting. + volatile boolean mFirstProvisioningCheckStarted = false; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -2730,6 +2733,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } + // After booting we'll check once for mobile provisioning + // if we've provisioned by and connected. + if (!mFirstProvisioningCheckStarted + && (0 != Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0)) + && (state == NetworkInfo.State.CONNECTED)) { + log("check provisioning after booting"); + mFirstProvisioningCheckStarted = true; + checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); + } + EventLogTags.writeConnectivityStateChanged( info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); @@ -3548,6 +3562,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { + " resultReceiver=" + resultReceiver); enforceChangePermission(); + mFirstProvisioningCheckStarted = true; + int timeOutMs = suggestedTimeOutMs; if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { timeOutMs = CheckMp.MAX_TIMEOUT_MS; From 94f3c8c66d4330b3be137fa2d6cdb86b52b9e54a Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 16 Jul 2013 18:59:12 -0700 Subject: [PATCH 090/296] Support multiple Vpn ManageDialogs Move away from storing the configs in the Intent to prevent issues with PendingIntents and multiple configs. The Dialog now queries ConnectivityService for the configuration to display in the management dialog. Change-Id: I0e0ef52db840152914d117a24f776d8106e836ff --- core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index d537b32ff1..0a476eb88f 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -124,6 +124,8 @@ interface IConnectivityManager ParcelFileDescriptor establishVpn(in VpnConfig config); + VpnConfig getVpnConfig(); + void startLegacyVpn(in VpnProfile profile); LegacyVpnInfo getLegacyVpnInfo(); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 476a6fdffb..3a4b7e382f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3425,6 +3425,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * Returns the information of the ongoing VPN. This method is used by VpnDialogs and + * not available in ConnectivityManager. + * Permissions are checked in Vpn class. + * @hide + */ + @Override + public VpnConfig getVpnConfig() { + int user = UserHandle.getUserId(Binder.getCallingUid()); + synchronized(mVpns) { + return mVpns.get(user).getVpnConfig(); + } + } + /** * Callback for VPN subsystem. Currently VPN is not adapted to the service * through NetworkStateTracker since it works differently. For example, it From 39d560174e75e5cc3ad366332d9912d93bbc6da7 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 16 Jul 2013 12:06:09 -0700 Subject: [PATCH 091/296] Add gservices updater for carrier provisioning url bug:9623159 Change-Id: I36697ed341353b7a3dbec5afe20241102e76f6f1 --- .../java/android/net/ConnectivityManager.java | 12 ++ .../android/net/IConnectivityManager.aidl | 2 + .../android/server/ConnectivityService.java | 126 +++++++++++++++++- 3 files changed, 133 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 6487c9267e..697bde99a2 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1358,4 +1358,16 @@ public class ConnectivityManager { } return timeOutMs; } + + /** + * Get the carrier provisioning url. + * {@hide} + */ + public String getMobileProvisioningUrl() { + try { + return mService.getMobileProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3dbe078313..4600c1a4dc 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -134,4 +134,6 @@ interface IConnectivityManager int findConnectionTypeForIface(in String iface); int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); + + String getMobileProvisioningUrl(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 29c546e197..8d58858b9f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -42,6 +42,7 @@ import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.net.CaptivePortalTracker; @@ -97,6 +98,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; import android.util.SparseIntArray; +import android.util.Xml; import com.android.internal.R; import com.android.internal.net.LegacyVpnInfo; @@ -106,6 +108,7 @@ import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.Tethering; @@ -117,7 +120,13 @@ import com.google.android.collect.Sets; import dalvik.system.DexClassLoader; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Constructor; @@ -3584,10 +3593,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { log("CheckMp.onComplete: warm sim"); - String url = getProvisioningUrl(); + String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url)) { - url = mContext.getResources() - .getString(R.string.mobile_redirected_provisioning_url); + url = getMobileRedirectedProvisioningUrl(); } if (TextUtils.isEmpty(url) == false) { log("CheckMp.onComplete: warm sim (redirected), url=" + url); @@ -3599,7 +3607,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { - String url = getProvisioningUrl(); + String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); setNotificationVisible(true, ni, url); @@ -3973,10 +3981,114 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); } - private String getProvisioningUrl() { - String url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: mobile_provisioning_url=" + url); + /** Location to an updatable file listing carrier provisioning urls. + * An example: + * + * + * + * http://myserver.com/foo?mdn=%3$s&iccid=%1$s&imei=%2$s + * http://www.google.com + * + */ + private static final String PROVISIONING_URL_PATH = + "/data/misc/radio/provisioning_urls.xml"; + private final File mProvisioningUrlFile = new File(PROVISIONING_URL_PATH); + /** XML tag for root element. */ + private static final String TAG_PROVISIONING_URLS = "provisioningUrls"; + /** XML tag for individual url */ + private static final String TAG_PROVISIONING_URL = "provisioningUrl"; + /** XML tag for redirected url */ + private static final String TAG_REDIRECTED_URL = "redirectedUrl"; + /** XML attribute for mcc */ + private static final String ATTR_MCC = "mcc"; + /** XML attribute for mnc */ + private static final String ATTR_MNC = "mnc"; + + private static final int REDIRECTED_PROVISIONING = 1; + private static final int PROVISIONING = 2; + + private String getProvisioningUrlBaseFromFile(int type) { + FileReader fileReader = null; + XmlPullParser parser = null; + Configuration config = mContext.getResources().getConfiguration(); + String tagType; + + switch (type) { + case PROVISIONING: + tagType = TAG_PROVISIONING_URL; + break; + case REDIRECTED_PROVISIONING: + tagType = TAG_REDIRECTED_URL; + break; + default: + throw new RuntimeException("getProvisioningUrlBaseFromFile: Unexpected parameter " + + type); + } + + try { + fileReader = new FileReader(mProvisioningUrlFile); + parser = Xml.newPullParser(); + parser.setInput(fileReader); + XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS); + + while (true) { + XmlUtils.nextElement(parser); + + String element = parser.getName(); + if (element == null) break; + + if (element.equals(tagType)) { + String mcc = parser.getAttributeValue(null, ATTR_MCC); + try { + if (mcc != null && Integer.parseInt(mcc) == config.mcc) { + String mnc = parser.getAttributeValue(null, ATTR_MNC); + if (mnc != null && Integer.parseInt(mnc) == config.mnc) { + parser.next(); + if (parser.getEventType() == XmlPullParser.TEXT) { + return parser.getText(); + } + } + } + } catch (NumberFormatException e) { + loge("NumberFormatException in getProvisioningUrlBaseFromFile: " + e); + } + } + } + return null; + } catch (FileNotFoundException e) { + loge("Carrier Provisioning Urls file not found"); + } catch (XmlPullParserException e) { + loge("Xml parser exception reading Carrier Provisioning Urls file: " + e); + } catch (IOException e) { + loge("I/O exception reading Carrier Provisioning Urls file: " + e); + } finally { + if (fileReader != null) { + try { + fileReader.close(); + } catch (IOException e) {} + } + } + return null; + } + + private String getMobileRedirectedProvisioningUrl() { + String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); + if (TextUtils.isEmpty(url)) { + url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); + } + return url; + } + + public String getMobileProvisioningUrl() { + enforceConnectivityInternalPermission(); + String url = getProvisioningUrlBaseFromFile(PROVISIONING); + if (TextUtils.isEmpty(url)) { + url = mContext.getResources().getString(R.string.mobile_provisioning_url); + log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); + } else { + log("getProvisioningUrl: mobile_provisioning_url from File =" + url); + } // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { String phoneNumber = mTelephonyManager.getLine1Number(); From 5ba1b91400621efc73932d1a35e518b68741ef71 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 16 Jul 2013 17:16:37 -0700 Subject: [PATCH 092/296] When a SIM is changed check mobile provisioning. A simple mechanism for doing this is to take advantage of the fact that we require the device to reboot after a sim has been changed. Thus when connectivity service is started we wait to get a connection then call checkMobileProvisioning once. We also add a check that the DEVICE_PROVISIONED is true, i.e. SetupWizard has been run. Bug: 9784024 Change-Id: I5c1936744f6fc55a447ae44cd36eec3849d27e21 --- .../com/android/server/ConnectivityService.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 29c546e197..ca5fc181dc 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -375,6 +375,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; + // We only want one checkMobileProvisioning after booting. + volatile boolean mFirstProvisioningCheckStarted = false; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -2730,6 +2733,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } + // After booting we'll check once for mobile provisioning + // if we've provisioned by and connected. + if (!mFirstProvisioningCheckStarted + && (0 != Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.DEVICE_PROVISIONED, 0)) + && (state == NetworkInfo.State.CONNECTED)) { + log("check provisioning after booting"); + mFirstProvisioningCheckStarted = true; + checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); + } + EventLogTags.writeConnectivityStateChanged( info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); @@ -3548,6 +3562,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { + " resultReceiver=" + resultReceiver); enforceChangePermission(); + mFirstProvisioningCheckStarted = true; + int timeOutMs = suggestedTimeOutMs; if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { timeOutMs = CheckMp.MAX_TIMEOUT_MS; From a01ffe6f382df78cf02f16de2c820df66900f8ca Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 16 Jul 2013 12:06:09 -0700 Subject: [PATCH 093/296] Add gservices updater for carrier provisioning url bug:9623159 Change-Id: I36697ed341353b7a3dbec5afe20241102e76f6f1 --- .../java/android/net/ConnectivityManager.java | 12 ++ .../android/net/IConnectivityManager.aidl | 2 + .../android/server/ConnectivityService.java | 126 +++++++++++++++++- 3 files changed, 133 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 6487c9267e..697bde99a2 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1358,4 +1358,16 @@ public class ConnectivityManager { } return timeOutMs; } + + /** + * Get the carrier provisioning url. + * {@hide} + */ + public String getMobileProvisioningUrl() { + try { + return mService.getMobileProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3dbe078313..4600c1a4dc 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -134,4 +134,6 @@ interface IConnectivityManager int findConnectionTypeForIface(in String iface); int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); + + String getMobileProvisioningUrl(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ca5fc181dc..54bcdcbb27 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -42,6 +42,7 @@ import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; import android.net.CaptivePortalTracker; @@ -97,6 +98,7 @@ import android.telephony.TelephonyManager; import android.text.TextUtils; import android.util.Slog; import android.util.SparseIntArray; +import android.util.Xml; import com.android.internal.R; import com.android.internal.net.LegacyVpnInfo; @@ -106,6 +108,7 @@ import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; +import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.Tethering; @@ -117,7 +120,13 @@ import com.google.android.collect.Sets; import dalvik.system.DexClassLoader; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.File; import java.io.FileDescriptor; +import java.io.FileNotFoundException; +import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.lang.reflect.Constructor; @@ -3600,10 +3609,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { log("CheckMp.onComplete: warm sim"); - String url = getProvisioningUrl(); + String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url)) { - url = mContext.getResources() - .getString(R.string.mobile_redirected_provisioning_url); + url = getMobileRedirectedProvisioningUrl(); } if (TextUtils.isEmpty(url) == false) { log("CheckMp.onComplete: warm sim (redirected), url=" + url); @@ -3615,7 +3623,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { - String url = getProvisioningUrl(); + String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); setNotificationVisible(true, ni, url); @@ -3989,10 +3997,114 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); } - private String getProvisioningUrl() { - String url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: mobile_provisioning_url=" + url); + /** Location to an updatable file listing carrier provisioning urls. + * An example: + * + * + * + * http://myserver.com/foo?mdn=%3$s&iccid=%1$s&imei=%2$s + * http://www.google.com + * + */ + private static final String PROVISIONING_URL_PATH = + "/data/misc/radio/provisioning_urls.xml"; + private final File mProvisioningUrlFile = new File(PROVISIONING_URL_PATH); + /** XML tag for root element. */ + private static final String TAG_PROVISIONING_URLS = "provisioningUrls"; + /** XML tag for individual url */ + private static final String TAG_PROVISIONING_URL = "provisioningUrl"; + /** XML tag for redirected url */ + private static final String TAG_REDIRECTED_URL = "redirectedUrl"; + /** XML attribute for mcc */ + private static final String ATTR_MCC = "mcc"; + /** XML attribute for mnc */ + private static final String ATTR_MNC = "mnc"; + + private static final int REDIRECTED_PROVISIONING = 1; + private static final int PROVISIONING = 2; + + private String getProvisioningUrlBaseFromFile(int type) { + FileReader fileReader = null; + XmlPullParser parser = null; + Configuration config = mContext.getResources().getConfiguration(); + String tagType; + + switch (type) { + case PROVISIONING: + tagType = TAG_PROVISIONING_URL; + break; + case REDIRECTED_PROVISIONING: + tagType = TAG_REDIRECTED_URL; + break; + default: + throw new RuntimeException("getProvisioningUrlBaseFromFile: Unexpected parameter " + + type); + } + + try { + fileReader = new FileReader(mProvisioningUrlFile); + parser = Xml.newPullParser(); + parser.setInput(fileReader); + XmlUtils.beginDocument(parser, TAG_PROVISIONING_URLS); + + while (true) { + XmlUtils.nextElement(parser); + + String element = parser.getName(); + if (element == null) break; + + if (element.equals(tagType)) { + String mcc = parser.getAttributeValue(null, ATTR_MCC); + try { + if (mcc != null && Integer.parseInt(mcc) == config.mcc) { + String mnc = parser.getAttributeValue(null, ATTR_MNC); + if (mnc != null && Integer.parseInt(mnc) == config.mnc) { + parser.next(); + if (parser.getEventType() == XmlPullParser.TEXT) { + return parser.getText(); + } + } + } + } catch (NumberFormatException e) { + loge("NumberFormatException in getProvisioningUrlBaseFromFile: " + e); + } + } + } + return null; + } catch (FileNotFoundException e) { + loge("Carrier Provisioning Urls file not found"); + } catch (XmlPullParserException e) { + loge("Xml parser exception reading Carrier Provisioning Urls file: " + e); + } catch (IOException e) { + loge("I/O exception reading Carrier Provisioning Urls file: " + e); + } finally { + if (fileReader != null) { + try { + fileReader.close(); + } catch (IOException e) {} + } + } + return null; + } + + private String getMobileRedirectedProvisioningUrl() { + String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); + if (TextUtils.isEmpty(url)) { + url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); + } + return url; + } + + public String getMobileProvisioningUrl() { + enforceConnectivityInternalPermission(); + String url = getProvisioningUrlBaseFromFile(PROVISIONING); + if (TextUtils.isEmpty(url)) { + url = mContext.getResources().getString(R.string.mobile_provisioning_url); + log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); + } else { + log("getProvisioningUrl: mobile_provisioning_url from File =" + url); + } // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { String phoneNumber = mTelephonyManager.getLine1Number(); From 368095f6582960e2de328ab176c46c3d242942d5 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 18 Jul 2013 14:24:42 -0700 Subject: [PATCH 094/296] Make CS.isTetheringSupported dynamic It used to be set at boot, but that was too quick to pick up carrier specific resources. With this change even if you switch sims subequent checks get the new values. bug:9865616 Change-Id: I8c270c6b02fc6bdd3c3d76ceea58172df25e058d --- .../java/com/android/server/ConnectivityService.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 54bcdcbb27..cb4e89cc0f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -175,7 +175,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10; private Tethering mTethering; - private boolean mTetheringConfigValid = false; private KeyStore mKeyStore; @@ -589,10 +588,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper()); - mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 || - mTethering.getTetherableWifiRegexs().length != 0 || - mTethering.getTetherableBluetoothRegexs().length != 0) && - mTethering.getUpstreamIfaceTypes().length != 0); mVpn = new Vpn(mContext, mVpnCallback, mNetd, this); mVpn.startMonitoring(mContext, mTrackerHandler); @@ -3002,7 +2997,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1); boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.TETHER_SUPPORTED, defaultVal) != 0); - return tetherEnabledInSettings && mTetheringConfigValid; + return tetherEnabledInSettings && ((mTethering.getTetherableUsbRegexs().length != 0 || + mTethering.getTetherableWifiRegexs().length != 0 || + mTethering.getTetherableBluetoothRegexs().length != 0) && + mTethering.getUpstreamIfaceTypes().length != 0); } // An API NetworkStateTrackers can call when they lose their network. From 98b10cec42cab3698f1eb80f6ae57ee3e3de38f9 Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Thu, 18 Jul 2013 18:23:57 -0700 Subject: [PATCH 095/296] Fix build & preserve DHCP scheduling as-is Change-Id: I4063b18532c476280f343658bf3641495e526ed4 --- .../src/com/android/server/NetworkStatsServiceTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index cdc4d784cf..ed74fdfccf 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -878,8 +878,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mAlarmManager.remove(isA(PendingIntent.class)); expectLastCall().anyTimes(); - mAlarmManager.setInexactRepeating( - eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class)); + mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class), false); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From 99fedebaa111b760edf3de0afa108818f606becd Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 19 Jul 2013 09:27:56 -0700 Subject: [PATCH 096/296] checkMobileProvisioning is not using sendNotification. Change-Id: Ie5b98b462b29fe9339fcb8207d2d33e3028a155c --- services/java/com/android/server/ConnectivityService.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 476a6fdffb..d2bae28e38 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3670,7 +3670,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } @Override - public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, + public int checkMobileProvisioning(final boolean sendNotification, int suggestedTimeOutMs, final ResultReceiver resultReceiver) { log("checkMobileProvisioning: E sendNotification=" + sendNotification + " suggestedTimeOutMs=" + suggestedTimeOutMs @@ -3703,6 +3703,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("CheckMp.onComplete: send result"); resultReceiver.send(result, null); } + if (!sendNotification) { + log("CheckMp.onComplete: done, not sending notification"); + return; + } NetworkInfo ni = mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { From 49db4221002ae32cfb7b092b4eb30f90aad31e90 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Mon, 15 Jul 2013 16:34:04 -0700 Subject: [PATCH 097/296] Fix supplimentary network connections with VPNs Enables the use of supplimentary mobile networks like MMS, and HIPRI while VPNs are running. Change-Id: I313f57a905b4e16bd4322c68687cbff1cfbe9d3e --- .../java/android/net/ConnectivityManager.java | 16 +++ .../android/server/ConnectivityService.java | 107 ++++++++++++------ 2 files changed, 86 insertions(+), 37 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f920874506..8bbe6c826b 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -479,6 +479,22 @@ public class ConnectivityManager { } } + /** + * Checks if the given network type should be exempt from VPN routing rules + * + * @hide + */ + public static boolean isNetworkTypeExempt(int networkType) { + switch (networkType) { + case TYPE_MOBILE_MMS: + case TYPE_MOBILE_SUPL: + case TYPE_MOBILE_HIPRI: + return true; + default: + return false; + } + } + /** * Specifies the preferred network type. When the device has more * than one type available the preferred network type will be used. diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 0608b6a6f5..1e3f0ef89b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -252,6 +252,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final boolean TO_DEFAULT_TABLE = true; private static final boolean TO_SECONDARY_TABLE = false; + private static final boolean EXEMPT = true; + private static final boolean UNEXEMPT = false; + /** * used internally as a delayed event to make us switch back to the * default network @@ -349,10 +352,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { private InetAddress mDefaultDns; + // Lock for protecting access to mAddedRoutes and mExemptAddresses + private final Object mRoutesLock = new Object(); + // this collection is used to refcount the added routes - if there are none left // it's time to remove the route from the route table + @GuardedBy("mRoutesLock") private Collection mAddedRoutes = new ArrayList(); + // this collection corresponds to the entries of mAddedRoutes that have routing exemptions + // used to handle cleanup of exempt rules + @GuardedBy("mRoutesLock") + private Collection mExemptAddresses = new ArrayList(); + // used in DBG mode to track inet condition reports private static final int INET_CONDITION_LOG_MAX_SIZE = 15; private ArrayList mInetLog; @@ -1470,7 +1482,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { InetAddress addr = InetAddress.getByAddress(hostAddress); LinkProperties lp = tracker.getLinkProperties(); - boolean ok = addRouteToAddress(lp, addr); + boolean ok = addRouteToAddress(lp, addr, EXEMPT); if (DBG) log("requestRouteToHostAddress ok=" + ok); return ok; } catch (UnknownHostException e) { @@ -1482,24 +1494,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } - private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { - return modifyRoute(p, r, 0, ADD, toDefaultTable); + private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, + boolean exempt) { + return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt); } private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { - return modifyRoute(p, r, 0, REMOVE, toDefaultTable); + return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT); } - private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) { - return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE); + private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt) { + return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt); } private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) { - return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE); + return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT); } private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, - boolean toDefaultTable) { + boolean toDefaultTable, boolean exempt) { RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr); if (bestRoute == null) { bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName()); @@ -1514,11 +1527,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface); } } - return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable); + return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt); } private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd, - boolean toDefaultTable) { + boolean toDefaultTable, boolean exempt) { if ((lp == null) || (r == null)) { if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r); return false; @@ -1547,15 +1560,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute.getGateway(), ifaceName); } - modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable); + modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt); } } if (doAdd) { if (VDBG) log("Adding " + r + " for interface " + ifaceName); try { if (toDefaultTable) { - mAddedRoutes.add(r); // only track default table - only one apps can effect - mNetd.addRoute(ifaceName, r); + synchronized (mRoutesLock) { + // only track default table - only one apps can effect + mAddedRoutes.add(r); + mNetd.addRoute(ifaceName, r); + if (exempt) { + LinkAddress dest = r.getDestination(); + if (!mExemptAddresses.contains(dest)) { + mNetd.setHostExemption(dest); + mExemptAddresses.add(dest); + } + } + } } else { mNetd.addSecondaryRoute(ifaceName, r); } @@ -1568,18 +1591,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { // if we remove this one and there are no more like it, then refcount==0 and // we can remove it from the table if (toDefaultTable) { - mAddedRoutes.remove(r); - if (mAddedRoutes.contains(r) == false) { - if (VDBG) log("Removing " + r + " for interface " + ifaceName); - try { - mNetd.removeRoute(ifaceName, r); - } catch (Exception e) { - // never crash - catch them all - if (VDBG) loge("Exception trying to remove a route: " + e); - return false; + synchronized (mRoutesLock) { + mAddedRoutes.remove(r); + if (mAddedRoutes.contains(r) == false) { + if (VDBG) log("Removing " + r + " for interface " + ifaceName); + try { + mNetd.removeRoute(ifaceName, r); + LinkAddress dest = r.getDestination(); + if (mExemptAddresses.contains(dest)) { + mNetd.clearHostExemption(dest); + mExemptAddresses.remove(dest); + } + } catch (Exception e) { + // never crash - catch them all + if (VDBG) loge("Exception trying to remove a route: " + e); + return false; + } + } else { + if (VDBG) log("not removing " + r + " as it's still in use"); } - } else { - if (VDBG) log("not removing " + r + " as it's still in use"); } } else { if (VDBG) log("Removing " + r + " for interface " + ifaceName); @@ -2260,6 +2290,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private void handleConnectivityChange(int netType, boolean doReset) { int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; + boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType); /* * If a non-default network is enabled, add the host routes that @@ -2324,7 +2355,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } mCurrentLinkProperties[netType] = newLp; - boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault()); + boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt); if (resetMask != 0 || resetDns) { if (curLp != null) { @@ -2400,7 +2431,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * returns a boolean indicating the routes changed */ private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp, - boolean isLinkDefault) { + boolean isLinkDefault, boolean exempt) { Collection routesToAdd = null; CompareResult dnsDiff = new CompareResult(); CompareResult routeDiff = new CompareResult(); @@ -2436,7 +2467,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (newLp != null) { for (InetAddress newDns : newLp.getDnses()) { - addRouteToAddress(newLp, newDns); + addRouteToAddress(newLp, newDns, exempt); } } } else { @@ -2445,28 +2476,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { removeRouteToAddress(curLp, oldDns); } for (InetAddress newDns : dnsDiff.added) { - addRouteToAddress(newLp, newDns); + addRouteToAddress(newLp, newDns, exempt); } } } for (RouteInfo r : routeDiff.added) { if (isLinkDefault || ! r.isDefaultRoute()) { - addRoute(newLp, r, TO_DEFAULT_TABLE); + addRoute(newLp, r, TO_DEFAULT_TABLE, exempt); } else { // add to a secondary route table - addRoute(newLp, r, TO_SECONDARY_TABLE); + addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT); // many radios add a default route even when we don't want one. // remove the default route unless somebody else has asked for it String ifaceName = newLp.getInterfaceName(); - if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) { - if (VDBG) log("Removing " + r + " for interface " + ifaceName); - try { - mNetd.removeRoute(ifaceName, r); - } catch (Exception e) { - // never crash - catch them all - if (DBG) loge("Exception trying to remove a route: " + e); + synchronized (mRoutesLock) { + if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) { + if (VDBG) log("Removing " + r + " for interface " + ifaceName); + try { + mNetd.removeRoute(ifaceName, r); + } catch (Exception e) { + // never crash - catch them all + if (DBG) loge("Exception trying to remove a route: " + e); + } } } } From a5e56e1223cfbfcfe87452ad05b84ba9db4900bd Mon Sep 17 00:00:00 2001 From: Guang Zhu Date: Sun, 21 Jul 2013 02:01:34 -0700 Subject: [PATCH 098/296] fix build Change-Id: Ie4bd7c3fe9320d22b7da2962e5e5a4abca510bd2 --- .../src/com/android/server/NetworkStatsServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index ed74fdfccf..aca77b8d87 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -878,7 +878,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mAlarmManager.remove(isA(PendingIntent.class)); expectLastCall().anyTimes(); - mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), isA(PendingIntent.class), false); + mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), isA(PendingIntent.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From 73652d07b898eaa734a5711851bfa8f2928d1ebf Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 23 Jul 2013 17:13:36 -0700 Subject: [PATCH 099/296] Fix default DNS not being set on network changes Change-Id: I3c45404cab34c77b20dadc1d8aee127aa08fd0bd --- .../java/com/android/server/ConnectivityService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 0608b6a6f5..a3b3a1455d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2586,7 +2586,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Caller must grab mDnsLock. private void updateDnsLocked(String network, String iface, - Collection dnses, String domains) { + Collection dnses, String domains, boolean defaultDns) { int last = 0; if (dnses.size() == 0 && mDefaultDns != null) { dnses = new ArrayList(); @@ -2598,6 +2598,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); + if (defaultDns) { + mNetd.setDefaultInterfaceForDns(iface); + } + for (InetAddress dns : dnses) { ++last; String key = "net.dns" + last; @@ -2625,7 +2629,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { String network = nt.getNetworkInfo().getTypeName(); synchronized (mDnsLock) { if (!mDnsOverridden) { - updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains()); + updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true); } } } else { @@ -3496,8 +3500,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Apply DNS changes. synchronized (mDnsLock) { - updateDnsLocked("VPN", iface, addresses, domains); - mDnsOverridden = true; + updateDnsLocked("VPN", iface, addresses, domains, false); } // Temporarily disable the default proxy (not global). From 5fdc14656cde61638c65630eef02e9508154a07d Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 23 Jul 2013 17:44:41 -0700 Subject: [PATCH 100/296] Remove unused mDnsOverridden mDnsOverridden is no longer used now that VPNs do not override the default DNS settings. Change-Id: I69495b9a6de7d60628813f357d3dbdf548695ada --- .../android/server/ConnectivityService.java | 32 +++---------------- 1 file changed, 5 insertions(+), 27 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a3b3a1455d..5681adfd71 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -235,7 +235,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private Object mDnsLock = new Object(); private int mNumDnsEntries; - private boolean mDnsOverridden = false; private boolean mTestMode; private static ConnectivityService sServiceInstance; @@ -306,29 +305,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_SET_DEPENDENCY_MET = 10; - /** - * used internally to restore DNS properties back to the - * default network - */ - private static final int EVENT_RESTORE_DNS = 11; - /** * used internally to send a sticky broadcast delayed. */ - private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 12; + private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11; /** * Used internally to * {@link NetworkStateTracker#setPolicyDataEnable(boolean)}. */ - private static final int EVENT_SET_POLICY_DATA_ENABLE = 13; + private static final int EVENT_SET_POLICY_DATA_ENABLE = 12; - private static final int EVENT_VPN_STATE_CHANGED = 14; + private static final int EVENT_VPN_STATE_CHANGED = 13; /** * Used internally to disable fail fast of mobile data */ - private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 15; + private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14; /** Handler used for internal events. */ private InternalHandler mHandler; @@ -2628,9 +2621,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mNetConfigs[netType].isDefault()) { String network = nt.getNetworkInfo().getTypeName(); synchronized (mDnsLock) { - if (!mDnsOverridden) { - updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true); - } + updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true); } } else { try { @@ -2883,13 +2874,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleSetDependencyMet(msg.arg2, met); break; } - case EVENT_RESTORE_DNS: - { - if (mActiveDefaultNetwork != -1) { - handleDnsConfigurationChange(mActiveDefaultNetwork); - } - break; - } case EVENT_SEND_STICKY_BROADCAST_INTENT: { Intent intent = (Intent)msg.obj; @@ -3515,12 +3499,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public void restore() { - synchronized (mDnsLock) { - if (mDnsOverridden) { - mDnsOverridden = false; - mHandler.sendEmptyMessage(EVENT_RESTORE_DNS); - } - } synchronized (mProxyLock) { mDefaultProxyDisabled = false; if (mGlobalProxy == null && mDefaultProxy != null) { From 512c2204b1c2365451e3a62a8649a263acc5b7a8 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Mon, 29 Jul 2013 15:00:57 -0700 Subject: [PATCH 101/296] Add network type TYPE_MOBILE_IA. Add a network type for establishing connections to the apn used for the initial connection. Enable some debug for now. Bug: 8733613 Change-Id: Ia627ac0cf5715660b6d02bb13a83d46ec1727b87 --- core/java/android/net/ConnectivityManager.java | 16 +++++++++++++--- .../com/android/server/ConnectivityService.java | 3 +++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 8bbe6c826b..1dbe34e201 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -355,11 +355,17 @@ public class ConnectivityManager { */ public static final int TYPE_WIFI_P2P = 13; - /** {@hide} */ - public static final int MAX_RADIO_TYPE = TYPE_WIFI_P2P; + /** + * The network to use for initially attaching to the network + * {@hide} + */ + public static final int TYPE_MOBILE_IA = 14; /** {@hide} */ - public static final int MAX_NETWORK_TYPE = TYPE_WIFI_P2P; + public static final int MAX_RADIO_TYPE = TYPE_MOBILE_IA; + + /** {@hide} */ + public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_IA; /** * If you want to set the default network preference,you can directly @@ -436,6 +442,8 @@ public class ConnectivityManager { return "MOBILE_CBS"; case TYPE_WIFI_P2P: return "WIFI_P2P"; + case TYPE_MOBILE_IA: + return "MOBILE_IA"; default: return Integer.toString(type); } @@ -458,6 +466,7 @@ public class ConnectivityManager { case TYPE_MOBILE_FOTA: case TYPE_MOBILE_IMS: case TYPE_MOBILE_CBS: + case TYPE_MOBILE_IA: return true; default: return false; @@ -489,6 +498,7 @@ public class ConnectivityManager { case TYPE_MOBILE_MMS: case TYPE_MOBILE_SUPL: case TYPE_MOBILE_HIPRI: + case TYPE_MOBILE_IA: return true; default: return false; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b341693245..9615ff5fb8 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -472,6 +472,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { com.android.internal.R.array.radioAttributes); for (String raString : raStrings) { RadioAttributes r = new RadioAttributes(raString); + if (VDBG) log("raString=" + raString + " r=" + r); if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) { loge("Error in radioAttributes - ignoring attempt to define type " + r.mType); continue; @@ -492,6 +493,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (String naString : naStrings) { try { NetworkConfig n = new NetworkConfig(naString); + if (VDBG) log("naString=" + naString + " config=" + n); if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) { loge("Error in networkAttributes - ignoring attempt to define type " + n.type); @@ -518,6 +520,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // ignore it - leave the entry null } } + if (VDBG) log("mNetworksDefined=" + mNetworksDefined); mProtectedNetworks = new ArrayList(); int[] protectedNetworks = context.getResources().getIntArray( From 97049e5111d321b1cbce2fb784aece33794e559e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 17 Jun 2013 11:10:27 -0700 Subject: [PATCH 102/296] 464xlat: use a gatewayed route, not point-to-point Various applications such as Skype and our legacy VPN code do not understand routes pointed directly at point-to-point interfaces and require a default gateway IPv4 address in order to function. Grudgingly accept that routes without default gateways Are Hard and use gatewayed routes instead. This causes routing to go from: default dev clat4 scope link to: default via 192.0.0.4 dev clat4 scope link 192.0.0.4 dev clat4 scope link and those apps now work. Bug: 9597256 Bug: 9597516 Change-Id: I7b7890873802d3cb99affd6eb70b8ab75e7a2cf6 --- .../server/connectivity/Nat464Xlat.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/java/com/android/server/connectivity/Nat464Xlat.java index 59403c559d..a15d678520 100644 --- a/services/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/java/com/android/server/connectivity/Nat464Xlat.java @@ -147,17 +147,24 @@ public class Nat464Xlat extends BaseNetworkObserver { " added, mIsRunning = " + mIsRunning + " -> true"); mIsRunning = true; - // Get the network configuration of the clat interface, store it - // in our link properties, and stack it on top of the interface - // it's running on. + // Create the LinkProperties for the clat interface by fetching the + // IPv4 address for the interface and adding an IPv4 default route, + // then stack the LinkProperties on top of the link it's running on. + // Although the clat interface is a point-to-point tunnel, we don't + // point the route directly at the interface because some apps don't + // understand routes without gateways (see, e.g., http://b/9597256 + // http://b/9597516). Instead, set the next hop of the route to the + // clat IPv4 address itself (for those apps, it doesn't matter what + // the IP of the gateway is, only that there is one). try { InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); + LinkAddress clatAddress = config.getLinkAddress(); mLP.clear(); mLP.setInterfaceName(iface); - RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), null, - iface); + RouteInfo ipv4Default = new RouteInfo(new LinkAddress(Inet4Address.ANY, 0), + clatAddress.getAddress(), iface); mLP.addRoute(ipv4Default); - mLP.addLinkAddress(config.getLinkAddress()); + mLP.addLinkAddress(clatAddress); mTracker.addStackedLink(mLP); Slog.i(TAG, "Adding stacked link. tracker LP: " + mTracker.getLinkProperties()); From e1b474244259bbbe6adbdf780928f987cef51f24 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 31 Jul 2013 23:23:21 +0900 Subject: [PATCH 103/296] Add accessors for all addresses and clarify compare* methods 1. Add a method to return all addresses and all LinkAddresses on all links (both base links and stacked links). We already had one for routes, but did not yet have any for addresses. 2. Rename compareRoutes to compareAllRoutes, because unlike the other compare* methods, it looks at all interfaces. Update what appears to be its only caller. 3. Update the documentation of the compare* methods to match reality (they don't return lists) and clarify whether they look at all links or only the base link. Change-Id: Ie22e6c7f163d5de8e407248b45171dc28382d2d3 --- core/java/android/net/LinkProperties.java | 64 +++++++++++++------ .../src/android/net/LinkPropertiesTest.java | 27 ++++++-- .../android/server/ConnectivityService.java | 2 +- 3 files changed, 69 insertions(+), 24 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 75f8b5948b..6ab810c68d 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -128,6 +128,9 @@ public class LinkProperties implements Parcelable { return interfaceNames; } + /** + * Returns all the addresses on this link. + */ public Collection getAddresses() { Collection addresses = new ArrayList(); for (LinkAddress linkAddress : mLinkAddresses) { @@ -136,14 +139,43 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(addresses); } + /** + * Returns all the addresses on this link and all the links stacked above it. + */ + public Collection getAllAddresses() { + Collection addresses = new ArrayList(); + for (LinkAddress linkAddress : mLinkAddresses) { + addresses.add(linkAddress.getAddress()); + } + for (LinkProperties stacked: mStackedLinks.values()) { + addresses.addAll(stacked.getAllAddresses()); + } + return addresses; + } + public void addLinkAddress(LinkAddress address) { if (address != null) mLinkAddresses.add(address); } + /** + * Returns all the addresses on this link. + */ public Collection getLinkAddresses() { return Collections.unmodifiableCollection(mLinkAddresses); } + /** + * Returns all the addresses on this link and all the links stacked above it. + */ + public Collection getAllLinkAddresses() { + Collection addresses = new ArrayList(); + addresses.addAll(mLinkAddresses); + for (LinkProperties stacked: mStackedLinks.values()) { + addresses.addAll(stacked.getAllLinkAddresses()); + } + return addresses; + } + public void addDns(InetAddress dns) { if (dns != null) mDnses.add(dns); } @@ -426,13 +458,11 @@ public class LinkProperties implements Parcelable { } /** - * Return two lists, a list of addresses that would be removed from - * mLinkAddresses and a list of addresses that would be added to - * mLinkAddress which would then result in target and mLinkAddresses - * being the same list. + * Compares the addresses in this LinkProperties with another + * LinkProperties, examining only addresses on the base link. * - * @param target is a LinkProperties with the new list of addresses - * @return the removed and added lists. + * @param target a LinkProperties with the new list of addresses + * @return the differences between the addresses. */ public CompareResult compareAddresses(LinkProperties target) { /* @@ -456,13 +486,11 @@ public class LinkProperties implements Parcelable { } /** - * Return two lists, a list of dns addresses that would be removed from - * mDnses and a list of addresses that would be added to - * mDnses which would then result in target and mDnses - * being the same list. + * Compares the DNS addresses in this LinkProperties with another + * LinkProperties, examining only DNS addresses on the base link. * - * @param target is a LinkProperties with the new list of dns addresses - * @return the removed and added lists. + * @param target a LinkProperties with the new list of dns addresses + * @return the differences between the DNS addresses. */ public CompareResult compareDnses(LinkProperties target) { /* @@ -487,15 +515,13 @@ public class LinkProperties implements Parcelable { } /** - * Return two lists, a list of routes that would be removed from - * mRoutes and a list of routes that would be added to - * mRoutes which would then result in target and mRoutes - * being the same list. + * Compares all routes in this LinkProperties with another LinkProperties, + * examining both the the base link and all stacked links. * - * @param target is a LinkProperties with the new list of routes - * @return the removed and added lists. + * @param target a LinkProperties with the new list of routes + * @return the differences between the routes. */ - public CompareResult compareRoutes(LinkProperties target) { + public CompareResult compareAllRoutes(LinkProperties target) { /* * Duplicate the RouteInfos into removed, we will be removing * routes which are common between mRoutes and target diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index d6a7ee27a2..d8290f494b 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -273,28 +273,47 @@ public class LinkPropertiesTest extends TestCase { // Check comparisons work. LinkProperties lp2 = new LinkProperties(lp); assertAllRoutesHaveInterface("wlan0", lp); - assertEquals(0, lp.compareRoutes(lp2).added.size()); - assertEquals(0, lp.compareRoutes(lp2).removed.size()); + assertEquals(0, lp.compareAllRoutes(lp2).added.size()); + assertEquals(0, lp.compareAllRoutes(lp2).removed.size()); lp2.setInterfaceName("p2p0"); assertAllRoutesHaveInterface("p2p0", lp2); - assertEquals(3, lp.compareRoutes(lp2).added.size()); - assertEquals(3, lp.compareRoutes(lp2).removed.size()); + assertEquals(3, lp.compareAllRoutes(lp2).added.size()); + assertEquals(3, lp.compareAllRoutes(lp2).removed.size()); } @SmallTest public void testStackedInterfaces() { LinkProperties rmnet0 = new LinkProperties(); rmnet0.setInterfaceName("rmnet0"); + rmnet0.addLinkAddress(new LinkAddress( + NetworkUtils.numericToInetAddress(ADDRV6), 128)); LinkProperties clat4 = new LinkProperties(); clat4.setInterfaceName("clat4"); + clat4.addLinkAddress(new LinkAddress( + NetworkUtils.numericToInetAddress(ADDRV4), 32)); assertEquals(0, rmnet0.getStackedLinks().size()); + assertEquals(1, rmnet0.getAddresses().size()); + assertEquals(1, rmnet0.getLinkAddresses().size()); + assertEquals(1, rmnet0.getAllAddresses().size()); + assertEquals(1, rmnet0.getAllLinkAddresses().size()); + rmnet0.addStackedLink(clat4); assertEquals(1, rmnet0.getStackedLinks().size()); + assertEquals(1, rmnet0.getAddresses().size()); + assertEquals(1, rmnet0.getLinkAddresses().size()); + assertEquals(2, rmnet0.getAllAddresses().size()); + assertEquals(2, rmnet0.getAllLinkAddresses().size()); + rmnet0.addStackedLink(clat4); assertEquals(1, rmnet0.getStackedLinks().size()); + assertEquals(1, rmnet0.getAddresses().size()); + assertEquals(1, rmnet0.getLinkAddresses().size()); + assertEquals(2, rmnet0.getAllAddresses().size()); + assertEquals(2, rmnet0.getAllLinkAddresses().size()); + assertEquals(0, clat4.getStackedLinks().size()); // Modify an item in the returned collection to see what happens. diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9615ff5fb8..af9fdffe88 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2433,7 +2433,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { CompareResult routeDiff = new CompareResult(); if (curLp != null) { // check for the delta between the current set and the new - routeDiff = curLp.compareRoutes(newLp); + routeDiff = curLp.compareAllRoutes(newLp); dnsDiff = curLp.compareDnses(newLp); } else if (newLp != null) { routeDiff.added = newLp.getAllRoutes(); From d28eef464a2c1e8a5f6964ff668587b34c87156c Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 31 Jul 2013 15:49:04 -0700 Subject: [PATCH 104/296] Fix excessive log spew. Bug: 10115060 Change-Id: I61fd83071da1224f38757b8d90f58c8d6c41d36b --- services/java/com/android/server/ConnectivityService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 9615ff5fb8..cdf9f213f5 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3909,8 +3909,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - log("isMobileOk: not connected ni=" + + if (VDBG) { + log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } sleep(1); result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; continue; From fa9d82b877308b3c53576ddb3407c85e0c090ef4 Mon Sep 17 00:00:00 2001 From: David Christie Date: Fri, 26 Jul 2013 13:23:29 -0700 Subject: [PATCH 105/296] Add WorkSource capability to AlarmManager. Change-Id: I663ea3078d405f0fa667a04bdaa376ae6652e994 --- .../src/com/android/server/NetworkStatsServiceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index aca77b8d87..5fa046aa4f 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -878,7 +878,8 @@ public class NetworkStatsServiceTest extends AndroidTestCase { mAlarmManager.remove(isA(PendingIntent.class)); expectLastCall().anyTimes(); - mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), isA(PendingIntent.class)); + mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), + isA(PendingIntent.class), isA(WorkSource.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From d201f880de31e4ab30f882c679de493158e3cca9 Mon Sep 17 00:00:00 2001 From: David Christie Date: Fri, 2 Aug 2013 10:54:55 -0700 Subject: [PATCH 106/296] Fix build breakage Change-Id: Ia684fb55db301fdadaa3aae93f82b2cdcfc200af --- .../src/com/android/server/NetworkStatsServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 5fa046aa4f..a9909b2ecf 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -63,6 +63,7 @@ import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.INetworkManagementService; +import android.os.WorkSource; import android.telephony.TelephonyManager; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.LargeTest; From 4bd59212450cc566126abb10af4e0fe139287ed5 Mon Sep 17 00:00:00 2001 From: David Christie Date: Fri, 2 Aug 2013 11:06:02 -0700 Subject: [PATCH 107/296] Fix broken unit test Change-Id: I4aa0035233749f6d585c151329436439ae9b2921 --- .../src/com/android/server/NetworkStatsServiceTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index a9909b2ecf..90a9b6a5f0 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -40,6 +40,7 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; import static org.easymock.EasyMock.anyLong; +import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.aryEq; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMock; @@ -880,7 +881,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectLastCall().anyTimes(); mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), - isA(PendingIntent.class), isA(WorkSource.class)); + isA(PendingIntent.class), anyObject(WorkSource.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From 1a168466464eb4c2a1a55b4d60542bd49ead5dfb Mon Sep 17 00:00:00 2001 From: Dmitry Shmidt Date: Wed, 24 Jul 2013 17:42:56 -0700 Subject: [PATCH 108/296] dhcp: Get mtu property from dhcp results Change-Id: I1b032094e0945b27d98f7ac786247b7cc9d60131 Signed-off-by: Dmitry Shmidt --- core/jni/android_net_NetUtils.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 526159f4f1..7e70c7c5eb 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -37,7 +37,8 @@ int dhcp_do_request(const char * const ifname, const char *server, uint32_t *lease, const char *vendorInfo, - const char *domains); + const char *domains, + const char *mtu); int dhcp_do_request_renew(const char * const ifname, const char *ipaddr, @@ -47,7 +48,8 @@ int dhcp_do_request_renew(const char * const ifname, const char *server, uint32_t *lease, const char *vendorInfo, - const char *domains); + const char *domains, + const char *mtu); int dhcp_stop(const char *ifname); int dhcp_release_lease(const char *ifname); @@ -126,16 +128,17 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr 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; if (renew) { result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength, - dns, server, &lease, vendorInfo, domains); + dns, server, &lease, vendorInfo, domains, mtu); } else { result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, - dns, server, &lease, vendorInfo, domains); + dns, server, &lease, vendorInfo, domains, mtu); } if (result != 0) { ALOGD("dhcp_do_request failed"); From 4e3475964be68a27ef432157fc69e0acab75637f Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Fri, 2 Aug 2013 10:00:44 -0700 Subject: [PATCH 109/296] If frameworks wants ASCII casing, it should explicity ask for it. http://elliotth.blogspot.com/2012/01/beware-convenience-methods.html Bug: https://code.google.com/p/android/issues/detail?id=58359 Change-Id: Iaab02e718a7be7bda22e626dca05d79bfd2a8fc4 --- core/java/android/net/NetworkConfig.java | 3 ++- core/java/android/net/ProxyProperties.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java index 3cc0bc5eae..5d95f41c6c 100644 --- a/core/java/android/net/NetworkConfig.java +++ b/core/java/android/net/NetworkConfig.java @@ -17,6 +17,7 @@ package android.net; import android.util.Log; +import java.util.Locale; /** * Describes the buildtime configuration of a network. @@ -63,7 +64,7 @@ public class NetworkConfig { */ public NetworkConfig(String init) { String fragments[] = init.split(","); - name = fragments[0].trim().toLowerCase(); + name = fragments[0].trim().toLowerCase(Locale.ROOT); type = Integer.parseInt(fragments[1]); radio = Integer.parseInt(fragments[2]); priority = Integer.parseInt(fragments[3]); diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index cd799da9d7..9c4772b90f 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -25,6 +25,7 @@ import android.util.Log; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; +import java.util.Locale; /** * A container class for the http proxy info @@ -87,7 +88,7 @@ public class ProxyProperties implements Parcelable { if (mExclusionList == null) { mParsedExclusionList = new String[0]; } else { - String splitExclusionList[] = exclusionList.toLowerCase().split(","); + String splitExclusionList[] = exclusionList.toLowerCase(Locale.ROOT).split(","); mParsedExclusionList = new String[splitExclusionList.length * 2]; for (int i = 0; i < splitExclusionList.length; i++) { String s = splitExclusionList[i].trim(); From 8432cf46212acd6542d48c45b31f0c5756b1a189 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 20 Jul 2013 20:31:59 -0700 Subject: [PATCH 110/296] Have CaptivePortalTracker use gservices updateable provisioning urls. After detecting there is a captive portal the url used in the notification for mobile networks should be updateable via gservices. These urls will be the same as used by CheckMp and is needed for carriers that have specific provisioning urls such as AT&T and Verizon. Bug: 9622647 Change-Id: Idcf4dabc72ece1dbbe1d5e5a21e550dd06fe16c7 --- core/java/android/net/ConnectivityManager.java | 14 +++++++++++++- core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 9 ++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 697bde99a2..b6df2fa660 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1360,7 +1360,7 @@ public class ConnectivityManager { } /** - * Get the carrier provisioning url. + * Get the mobile provisioning url. * {@hide} */ public String getMobileProvisioningUrl() { @@ -1370,4 +1370,16 @@ public class ConnectivityManager { } return null; } + + /** + * Get the mobile redirected provisioning url. + * {@hide} + */ + public String getMobileRedirectedProvisioningUrl() { + try { + return mService.getMobileRedirectedProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 4600c1a4dc..5daf39c60d 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -136,4 +136,6 @@ interface IConnectivityManager int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); String getMobileProvisioningUrl(); + + String getMobileRedirectedProvisioningUrl(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb4e89cc0f..6a90376557 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4086,7 +4086,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { return null; } - private String getMobileRedirectedProvisioningUrl() { + @Override + public String getMobileRedirectedProvisioningUrl() { + enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); @@ -4094,14 +4096,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + @Override public String getMobileProvisioningUrl() { enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); + log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url); } else { - log("getProvisioningUrl: mobile_provisioning_url from File =" + url); + log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url); } // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { From d6085f847c7586e22148ce78c3962a51905554d5 Mon Sep 17 00:00:00 2001 From: David Christie Date: Tue, 6 Aug 2013 17:28:03 +0000 Subject: [PATCH 111/296] Revert "Fix broken unit test" This reverts commit 4bd59212450cc566126abb10af4e0fe139287ed5. Change-Id: I67f5e7227a8a874158c4f0954e62a77a317f1edd --- .../src/com/android/server/NetworkStatsServiceTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index 90a9b6a5f0..a9909b2ecf 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -40,7 +40,6 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.aryEq; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMock; @@ -881,7 +880,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expectLastCall().anyTimes(); mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), - isA(PendingIntent.class), anyObject(WorkSource.class)); + isA(PendingIntent.class), isA(WorkSource.class)); expectLastCall().atLeastOnce(); mNetManager.setGlobalAlert(anyLong()); From 15f129209d65abb36643c91fa869f905a6d05a92 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 7 Aug 2013 11:02:57 -0700 Subject: [PATCH 112/296] Check that hipri has started. I needed to test the result of startUsingNetworkFeature, otherwise on mobile networks that are slow to come up, we won't detect warm SIMs after booting. Bug: 9962943 Change-Id: Ib638a4e43867ecaa85d6abff65643b77a63526b6 --- .../android/server/ConnectivityService.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb4e89cc0f..caab49ece7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3732,11 +3732,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - Phone.FEATURE_ENABLE_HIPRI, new Binder()); // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + + // First wait until we can start using hipri + Binder binder = new Binder(); + while(SystemClock.elapsedRealtime() < endTime) { + int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + Phone.FEATURE_ENABLE_HIPRI, binder); + if ((ret == PhoneConstants.APN_ALREADY_ACTIVE) + || (ret == PhoneConstants.APN_REQUEST_STARTED)) { + log("isMobileOk: hipri started"); + break; + } + if (VDBG) log("isMobileOk: hipri not started yet"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + sleep(1); + } + + // Continue trying to connect until time has run out while(SystemClock.elapsedRealtime() < endTime) { try { // Wait for hipri to connect. @@ -3745,8 +3760,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - log("isMobileOk: not connected ni=" + + if (VDBG) { + log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } sleep(1); result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; continue; From 674777e622d33c48b068f7dc4c84aa6f0c24cdd1 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 7 Aug 2013 16:22:47 -0700 Subject: [PATCH 113/296] If in a mobile captive portal is detected enable fail fast. When captive portal checking completes pass back the result. This is used to enable/disable failing fast for mobile. When failing fast is enabled we don't check for data stalls and thus won't be continually trying to do recovery operations, such as restarting the radio. Bug: 9462512 Change-Id: I0dea0eee519f8ee7f94e79d40e82c18f30d7fe2e --- .../java/android/net/ConnectivityManager.java | 19 +++++++++++++++++++ .../android/net/IConnectivityManager.aidl | 2 ++ .../android/server/ConnectivityService.java | 11 +++++++++++ 3 files changed, 32 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 697bde99a2..855a2ef93b 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1282,6 +1282,25 @@ public class ConnectivityManager { } } + /** + * Signal that the captive portal check on the indicated network + * is complete and whether its a captive portal or not. + * + * @param info the {@link NetworkInfo} object for the networkType + * in question. + * @param isCaptivePortal true/false. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * {@hide} + */ + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + try { + mService.captivePortalCheckCompleted(info, isCaptivePortal); + } catch (RemoteException e) { + } + } + /** * Supply the backend messenger for a network tracker * diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 4600c1a4dc..45bb184e48 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -129,6 +129,8 @@ interface IConnectivityManager void captivePortalCheckComplete(in NetworkInfo info); + void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); + void supplyMessenger(int networkType, in Messenger messenger); int findConnectionTypeForIface(in String iface); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb4e89cc0f..f3dc7257f9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2169,15 +2169,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + if (DBG) log("handleCaptivePortalTrackerCheck: call captivePortalCheckComplete ni=" + info); thisNet.captivePortalCheckComplete(); } /** @hide */ + @Override public void captivePortalCheckComplete(NetworkInfo info) { enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckComplete: ni=" + info); mNetTrackers[info.getType()].captivePortalCheckComplete(); } + /** @hide */ + @Override + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal); + mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal); + } + /** * Setup data activity tracking for the given network interface. * From a5bf2840cc81f7bd9a2b74a1ebb383c343edffc0 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Wed, 3 Jul 2013 17:04:33 -0400 Subject: [PATCH 114/296] Add PAC File support for proxy configuration PAC (Proxy auto-config) files contain a single javascript function, FindProxyForURL(url, host). It gets called to determine what proxy should be used for a specific request. This adds PAC support to the system. The ProxyProperties has been modified to hold the PAC file when one is present. The Proxy method setHttpProxySystemProperty has been modified to insert a PacProxySelector as the default ProxySelector when it is required. This new ProxySelector makes calls to the ConnectivityService to parse the PAC file. The ConnectivityService and the WifiConfigStore have been modified to support saving the extra PAC file data. The ConnectivityService now has a class attached (PacProxyNative) that interfaces to the native calls for PAC files. The parsing of the PAC file is handled by libpac (which is being added to external/) which utilizes libv8 to parse the javascript. As a fallback to applications that don't use the java ProxySelector, the proxy is setup to point to a local proxy server that will handle the pac parsing. bug:10182711 Change-Id: I5eb8df893c632fd3e1b732385cb7720ad646f401 --- core/java/android/net/ProxyProperties.java | 45 +++++++++++++++++-- .../android/server/ConnectivityService.java | 40 ++++++++++++----- 2 files changed, 71 insertions(+), 14 deletions(-) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 9c4772b90f..76aea9f58e 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -20,9 +20,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import android.util.Log; -import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.util.Locale; @@ -38,17 +36,30 @@ public class ProxyProperties implements Parcelable { private String mExclusionList; private String[] mParsedExclusionList; + private String mPacFileUrl; + public static final String LOCAL_EXCL_LIST = ""; + public static final int LOCAL_PORT = 8182; + public static final String LOCAL_HOST = "localhost"; + public ProxyProperties(String host, int port, String exclList) { mHost = host; mPort = port; setExclusionList(exclList); } + public ProxyProperties(String pacFileUrl) { + mHost = LOCAL_HOST; + mPort = LOCAL_PORT; + setExclusionList(LOCAL_EXCL_LIST); + mPacFileUrl = pacFileUrl; + } + private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) { mHost = host; mPort = port; mExclusionList = exclList; mParsedExclusionList = parsedExclList; + mPacFileUrl = null; } // copy constructor instead of clone @@ -56,6 +67,7 @@ public class ProxyProperties implements Parcelable { if (source != null) { mHost = source.getHost(); mPort = source.getPort(); + mPacFileUrl = source.getPacFileUrl(); mExclusionList = source.getExclusionList(); mParsedExclusionList = source.mParsedExclusionList; } @@ -69,6 +81,10 @@ public class ProxyProperties implements Parcelable { return inetSocketAddress; } + public String getPacFileUrl() { + return mPacFileUrl; + } + public String getHost() { return mHost; } @@ -130,7 +146,10 @@ public class ProxyProperties implements Parcelable { @Override public String toString() { StringBuilder sb = new StringBuilder(); - if (mHost != null) { + if (mPacFileUrl != null) { + sb.append("PAC Script: "); + sb.append(mPacFileUrl); + } else if (mHost != null) { sb.append("["); sb.append(mHost); sb.append("] "); @@ -148,6 +167,14 @@ public class ProxyProperties implements Parcelable { public boolean equals(Object o) { if (!(o instanceof ProxyProperties)) return false; ProxyProperties p = (ProxyProperties)o; + // If PAC URL is present in either then they must be equal. + // Other parameters will only be for fall back. + if (!TextUtils.isEmpty(mPacFileUrl)) { + return mPacFileUrl.equals(p.getPacFileUrl()); + } + if (!TextUtils.isEmpty(p.getPacFileUrl())) { + return false; + } if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false; if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { return false; @@ -181,6 +208,13 @@ public class ProxyProperties implements Parcelable { * @hide */ public void writeToParcel(Parcel dest, int flags) { + if (mPacFileUrl != null) { + dest.writeByte((byte)1); + dest.writeString(mPacFileUrl); + return; + } else { + dest.writeByte((byte)0); + } if (mHost != null) { dest.writeByte((byte)1); dest.writeString(mHost); @@ -201,7 +235,10 @@ public class ProxyProperties implements Parcelable { public ProxyProperties createFromParcel(Parcel in) { String host = null; int port = 0; - if (in.readByte() == 1) { + if (in.readByte() != 0) { + return new ProxyProperties(in.readString()); + } + if (in.readByte() != 0) { host = in.readString(); port = in.readInt(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 17ae85f39a..3ae2eb542c 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -56,13 +56,11 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.Uri; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; -import android.net.NetworkInfo.State; import android.net.NetworkQuotaInfo; import android.net.NetworkState; import android.net.NetworkStateTracker; @@ -70,6 +68,7 @@ import android.net.NetworkUtils; import android.net.Proxy; import android.net.ProxyProperties; import android.net.RouteInfo; +import android.net.Uri; import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; import android.os.AsyncTask; @@ -102,6 +101,7 @@ import android.util.SparseIntArray; import android.util.Xml; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; @@ -110,9 +110,11 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; +import com.android.net.IProxyService; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; +import com.android.server.connectivity.PacManager; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; import com.android.server.net.BaseNetworkObserver; @@ -120,8 +122,6 @@ import com.android.server.net.LockdownVpnTracker; import com.google.android.collect.Lists; import com.google.android.collect.Sets; -import com.android.internal.annotations.GuardedBy; - import dalvik.system.DexClassLoader; import org.xmlpull.v1.XmlPullParser; @@ -370,6 +370,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // track the global proxy. private ProxyProperties mGlobalProxy = null; + private PacManager mPacManager = null; + private SettingsObserver mSettingsObserver; NetworkConfig[] mNetConfigs; @@ -631,6 +633,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); + + mPacManager = new PacManager(mContext); } /** @@ -3168,13 +3172,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { // of proxy info to all the JVMs. // enforceAccessPermission(); synchronized (mProxyLock) { - if (mGlobalProxy != null) return mGlobalProxy; - return (mDefaultProxyDisabled ? null : mDefaultProxy); + ProxyProperties ret = mGlobalProxy; + if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy; + return ret; } } public void setGlobalProxy(ProxyProperties proxyProperties) { enforceConnectivityInternalPermission(); + synchronized (mProxyLock) { if (proxyProperties == mGlobalProxy) return; if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; @@ -3183,11 +3189,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { String host = ""; int port = 0; String exclList = ""; - if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) { + String pacFileUrl = ""; + if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) || + !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) { mGlobalProxy = new ProxyProperties(proxyProperties); host = mGlobalProxy.getHost(); port = mGlobalProxy.getPort(); exclList = mGlobalProxy.getExclusionList(); + if (proxyProperties.getPacFileUrl() != null) { + pacFileUrl = proxyProperties.getPacFileUrl(); + } } else { mGlobalProxy = null; } @@ -3198,6 +3209,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { Settings.Global.putInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, port); Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST, exclList); + Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl); } finally { Binder.restoreCallingIdentity(token); } @@ -3215,8 +3227,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { int port = Settings.Global.getInt(res, Settings.Global.GLOBAL_HTTP_PROXY_PORT, 0); String exclList = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); - if (!TextUtils.isEmpty(host)) { - ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList); + String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC); + if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) { + ProxyProperties proxyProperties; + if (!TextUtils.isEmpty(pacFileUrl)) { + proxyProperties = new ProxyProperties(pacFileUrl); + } else { + proxyProperties = new ProxyProperties(host, port, exclList); + } synchronized (mProxyLock) { mGlobalProxy = proxyProperties; } @@ -3234,7 +3252,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void handleApplyDefaultProxy(ProxyProperties proxy) { - if (proxy != null && TextUtils.isEmpty(proxy.getHost())) { + if (proxy != null && TextUtils.isEmpty(proxy.getHost()) + && TextUtils.isEmpty(proxy.getPacFileUrl())) { proxy = null; } synchronized (mProxyLock) { @@ -3276,6 +3295,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendProxyBroadcast(ProxyProperties proxy) { if (proxy == null) proxy = new ProxyProperties("", 0, ""); + mPacManager.setCurrentProxyScriptUrl(proxy); if (DBG) log("sending Proxy Broadcast for " + proxy); Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | From a2dc69a8931e718c631f5a9a8fd30aef25de09e4 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 8 Aug 2013 10:56:22 +0900 Subject: [PATCH 115/296] Simplify LinkPropertiesTest. Instead of converting IP addresses to strings throughout the test, do so once at the beginning. Change-Id: I7f0dae5d2e9e2cdc6ec808e2cf71197ba6ade0a4 --- .../src/android/net/LinkPropertiesTest.java | 149 ++++++++---------- 1 file changed, 65 insertions(+), 84 deletions(-) diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index d8290f494b..9fdfd0e641 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -25,14 +25,18 @@ import java.net.InetAddress; import java.util.ArrayList; public class LinkPropertiesTest extends TestCase { - private static String ADDRV4 = "75.208.6.1"; - private static String ADDRV6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334"; - private static String DNS1 = "75.208.7.1"; - private static String DNS2 = "69.78.7.1"; - private static String GATEWAY1 = "75.208.8.1"; - private static String GATEWAY2 = "69.78.8.1"; + private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1"); + private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress( + "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); + private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1"); + private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1"); + private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1"); + private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1"); private static String NAME = "qmi0"; + private static LinkAddress LINKADDRV4 = new LinkAddress(ADDRV4, 32); + private static LinkAddress LINKADDRV6 = new LinkAddress(ADDRV6, 128); + public void assertLinkPropertiesEqual(LinkProperties source, LinkProperties target) { // Check implementation of equals(), element by element. assertTrue(source.isIdenticalInterfaceName(target)); @@ -76,43 +80,37 @@ public class LinkPropertiesTest extends TestCase { LinkProperties source = new LinkProperties(); source.setInterfaceName(NAME); // set 2 link addresses - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); // set 2 dnses - source.addDns(NetworkUtils.numericToInetAddress(DNS1)); - source.addDns(NetworkUtils.numericToInetAddress(DNS2)); + source.addDns(DNS1); + source.addDns(DNS2); // set 2 gateways - source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + source.addRoute(new RouteInfo(GATEWAY1)); + source.addRoute(new RouteInfo(GATEWAY2)); LinkProperties target = new LinkProperties(); // All fields are same target.setInterfaceName(NAME); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDns(DNS1); + target.addDns(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); assertLinkPropertiesEqual(source, target); target.clear(); // change Interface Name target.setInterfaceName("qmi1"); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDns(DNS1); + target.addDns(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); assertFalse(source.equals(target)); target.clear(); @@ -120,38 +118,33 @@ public class LinkPropertiesTest extends TestCase { // change link addresses target.addLinkAddress(new LinkAddress( NetworkUtils.numericToInetAddress("75.208.6.2"), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addLinkAddress(LINKADDRV6); + target.addDns(DNS1); + target.addDns(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); assertFalse(source.equals(target)); target.clear(); target.setInterfaceName(NAME); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); // change dnses target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2")); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addDns(DNS2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); assertFalse(source.equals(target)); target.clear(); target.setInterfaceName(NAME); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addDns(DNS1); + target.addDns(DNS2); // change gateway target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2"))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + target.addRoute(new RouteInfo(GATEWAY2)); assertFalse(source.equals(target)); } catch (Exception e) { @@ -166,28 +159,24 @@ public class LinkPropertiesTest extends TestCase { LinkProperties source = new LinkProperties(); source.setInterfaceName(NAME); // set 2 link addresses - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); // set 2 dnses - source.addDns(NetworkUtils.numericToInetAddress(DNS1)); - source.addDns(NetworkUtils.numericToInetAddress(DNS2)); + source.addDns(DNS1); + source.addDns(DNS2); // set 2 gateways - source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); - source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); + source.addRoute(new RouteInfo(GATEWAY1)); + source.addRoute(new RouteInfo(GATEWAY2)); LinkProperties target = new LinkProperties(); // Exchange order target.setInterfaceName(NAME); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addDns(NetworkUtils.numericToInetAddress(DNS2)); - target.addDns(NetworkUtils.numericToInetAddress(DNS1)); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2))); - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1))); + target.addLinkAddress(LINKADDRV6); + target.addLinkAddress(LINKADDRV4); + target.addDns(DNS2); + target.addDns(DNS1); + target.addRoute(new RouteInfo(GATEWAY2)); + target.addRoute(new RouteInfo(GATEWAY1)); assertLinkPropertiesEqual(source, target); } catch (Exception e) { @@ -200,21 +189,15 @@ public class LinkPropertiesTest extends TestCase { try { LinkProperties source = new LinkProperties(); // set 3 link addresses, eg, [A, A, B] - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - source.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV4); + source.addLinkAddress(LINKADDRV6); LinkProperties target = new LinkProperties(); // set 3 link addresses, eg, [A, B, B] - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + target.addLinkAddress(LINKADDRV4); + target.addLinkAddress(LINKADDRV6); + target.addLinkAddress(LINKADDRV6); assertLinkPropertiesEqual(source, target); } catch (Exception e) { @@ -232,7 +215,7 @@ public class LinkPropertiesTest extends TestCase { public void testRouteInterfaces() { LinkAddress prefix = new LinkAddress( NetworkUtils.numericToInetAddress("2001:db8::"), 32); - InetAddress address = NetworkUtils.numericToInetAddress(ADDRV6); + InetAddress address = ADDRV6; // Add a route with no interface to a LinkProperties with no interface. No errors. LinkProperties lp = new LinkProperties(); @@ -265,7 +248,7 @@ public class LinkPropertiesTest extends TestCase { assertAllRoutesHaveInterface("wlan0", lp); // Routes with null interfaces are converted to wlan0. - r = RouteInfo.makeHostRoute(NetworkUtils.numericToInetAddress(ADDRV6), null); + r = RouteInfo.makeHostRoute(ADDRV6, null); lp.addRoute(r); assertEquals(3, lp.getRoutes().size()); assertAllRoutesHaveInterface("wlan0", lp); @@ -286,13 +269,11 @@ public class LinkPropertiesTest extends TestCase { public void testStackedInterfaces() { LinkProperties rmnet0 = new LinkProperties(); rmnet0.setInterfaceName("rmnet0"); - rmnet0.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV6), 128)); + rmnet0.addLinkAddress(LINKADDRV6); LinkProperties clat4 = new LinkProperties(); clat4.setInterfaceName("clat4"); - clat4.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress(ADDRV4), 32)); + clat4.addLinkAddress(LINKADDRV4); assertEquals(0, rmnet0.getStackedLinks().size()); assertEquals(1, rmnet0.getAddresses().size()); From e0fac27d4d02cb2c0b096b2fed4e34ba422d9e92 Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Thu, 8 Aug 2013 10:38:53 -0700 Subject: [PATCH 116/296] Use a single socket to communicate with supplicant This helps to prepare for future updates from external sources. Bug: 9298955 Change-Id: I4c63ad5fc1ea3564aab38cfce955de19bad75c0c (cherry picked from commit fb40801ed8c217ae01082fb1cbd0c30bbf5532ac) --- core/jni/android_net_NetUtils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 7e70c7c5eb..6d23c32b33 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -141,7 +141,7 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr dns, server, &lease, vendorInfo, domains, mtu); } if (result != 0) { - ALOGD("dhcp_do_request failed"); + ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new"); } env->ReleaseStringUTFChars(ifname, nameStr); From bd53d843fa4a179a1e9dcea2900350b75b2e94af Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 7 Aug 2013 11:02:57 -0700 Subject: [PATCH 117/296] Check that hipri has started. I needed to test the result of startUsingNetworkFeature, otherwise on mobile networks that are slow to come up, we won't detect warm SIMs after booting. Bug: 9962943 Change-Id: Ib638a4e43867ecaa85d6abff65643b77a63526b6 --- .../android/server/ConnectivityService.java | 23 ++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb4e89cc0f..caab49ece7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3732,11 +3732,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, - Phone.FEATURE_ENABLE_HIPRI, new Binder()); // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + + // First wait until we can start using hipri + Binder binder = new Binder(); + while(SystemClock.elapsedRealtime() < endTime) { + int ret = mCs.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, + Phone.FEATURE_ENABLE_HIPRI, binder); + if ((ret == PhoneConstants.APN_ALREADY_ACTIVE) + || (ret == PhoneConstants.APN_REQUEST_STARTED)) { + log("isMobileOk: hipri started"); + break; + } + if (VDBG) log("isMobileOk: hipri not started yet"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + sleep(1); + } + + // Continue trying to connect until time has run out while(SystemClock.elapsedRealtime() < endTime) { try { // Wait for hipri to connect. @@ -3745,8 +3760,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - log("isMobileOk: not connected ni=" + + if (VDBG) { + log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } sleep(1); result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; continue; From 830e29b51bb65548a80dc86b6786f35031870cdd Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 20 Jul 2013 20:31:59 -0700 Subject: [PATCH 118/296] Have CaptivePortalTracker use gservices updateable provisioning urls. After detecting there is a captive portal the url used in the notification for mobile networks should be updateable via gservices. These urls will be the same as used by CheckMp and is needed for carriers that have specific provisioning urls such as AT&T and Verizon. Bug: 9622647 Change-Id: Idcf4dabc72ece1dbbe1d5e5a21e550dd06fe16c7 --- core/java/android/net/ConnectivityManager.java | 14 +++++++++++++- core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 9 ++++++--- 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 697bde99a2..b6df2fa660 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1360,7 +1360,7 @@ public class ConnectivityManager { } /** - * Get the carrier provisioning url. + * Get the mobile provisioning url. * {@hide} */ public String getMobileProvisioningUrl() { @@ -1370,4 +1370,16 @@ public class ConnectivityManager { } return null; } + + /** + * Get the mobile redirected provisioning url. + * {@hide} + */ + public String getMobileRedirectedProvisioningUrl() { + try { + return mService.getMobileRedirectedProvisioningUrl(); + } catch (RemoteException e) { + } + return null; + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 4600c1a4dc..5daf39c60d 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -136,4 +136,6 @@ interface IConnectivityManager int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); String getMobileProvisioningUrl(); + + String getMobileRedirectedProvisioningUrl(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index caab49ece7..68037e08d2 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4103,7 +4103,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { return null; } - private String getMobileRedirectedProvisioningUrl() { + @Override + public String getMobileRedirectedProvisioningUrl() { + enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); @@ -4111,14 +4113,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + @Override public String getMobileProvisioningUrl() { enforceConnectivityInternalPermission(); String url = getProvisioningUrlBaseFromFile(PROVISIONING); if (TextUtils.isEmpty(url)) { url = mContext.getResources().getString(R.string.mobile_provisioning_url); - log("getProvisioningUrl: mobile_provisioining_url from resource =" + url); + log("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url); } else { - log("getProvisioningUrl: mobile_provisioning_url from File =" + url); + log("getMobileProvisioningUrl: mobile_provisioning_url from File =" + url); } // populate the iccid, imei and phone number in the provisioning url. if (!TextUtils.isEmpty(url)) { From 11f99735ee7ca0d16c696997295c876947f1cabd Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Wed, 7 Aug 2013 16:22:47 -0700 Subject: [PATCH 119/296] If in a mobile captive portal is detected enable fail fast. When captive portal checking completes pass back the result. This is used to enable/disable failing fast for mobile. When failing fast is enabled we don't check for data stalls and thus won't be continually trying to do recovery operations, such as restarting the radio. Bug: 9462512 Change-Id: I0dea0eee519f8ee7f94e79d40e82c18f30d7fe2e --- .../java/android/net/ConnectivityManager.java | 19 +++++++++++++++++++ .../android/net/IConnectivityManager.aidl | 2 ++ .../android/server/ConnectivityService.java | 11 +++++++++++ 3 files changed, 32 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index b6df2fa660..aa2d4ce92e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1282,6 +1282,25 @@ public class ConnectivityManager { } } + /** + * Signal that the captive portal check on the indicated network + * is complete and whether its a captive portal or not. + * + * @param info the {@link NetworkInfo} object for the networkType + * in question. + * @param isCaptivePortal true/false. + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * {@hide} + */ + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + try { + mService.captivePortalCheckCompleted(info, isCaptivePortal); + } catch (RemoteException e) { + } + } + /** * Supply the backend messenger for a network tracker * diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 5daf39c60d..3ac5f1367f 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -129,6 +129,8 @@ interface IConnectivityManager void captivePortalCheckComplete(in NetworkInfo info); + void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); + void supplyMessenger(int networkType, in Messenger messenger); int findConnectionTypeForIface(in String iface); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 68037e08d2..00935f3472 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2169,15 +2169,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + if (DBG) log("handleCaptivePortalTrackerCheck: call captivePortalCheckComplete ni=" + info); thisNet.captivePortalCheckComplete(); } /** @hide */ + @Override public void captivePortalCheckComplete(NetworkInfo info) { enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckComplete: ni=" + info); mNetTrackers[info.getType()].captivePortalCheckComplete(); } + /** @hide */ + @Override + public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { + enforceConnectivityInternalPermission(); + if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal); + mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal); + } + /** * Setup data activity tracking for the given network interface. * From 69e2de0a4e9973174eb890b88350eaa288646be5 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 13 Aug 2013 12:41:06 -0700 Subject: [PATCH 120/296] In isMobileOk don't execute finally if mobile data is not supported. Move the early return outside the try {} finally so we don't call setEnableFailFastMobileData(DctContants.DISABLED). Otherwise referencing counting is wrong and an exception is thrown in DcTrackerBase. Bug: 10304904 Change-Id: I5ba5121e473bada9f3daa8d6f3d3577cec8212fc --- .../java/com/android/server/ConnectivityService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index bb0d2483ae..a0e6dd1a87 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3916,13 +3916,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { Random rand = new Random(); mParams = params; - try { - if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; - return result; - } + if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { + log("isMobileOk: not mobile capable"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + return result; + } + try { // Enable fail fast as we'll do retries here and use a // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); From 884a8d284993412b83e167c09a488938d7761c75 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 13 Aug 2013 12:41:06 -0700 Subject: [PATCH 121/296] In isMobileOk don't execute finally if mobile data is not supported. Move the early return outside the try {} finally so we don't call setEnableFailFastMobileData(DctContants.DISABLED). Otherwise referencing counting is wrong and an exception is thrown in DcTrackerBase. Bug: 10304904 Change-Id: I5ba5121e473bada9f3daa8d6f3d3577cec8212fc --- .../java/com/android/server/ConnectivityService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index bb0d2483ae..a0e6dd1a87 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3916,13 +3916,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { Random rand = new Random(); mParams = params; - try { - if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; - return result; - } + if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { + log("isMobileOk: not mobile capable"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + return result; + } + try { // Enable fail fast as we'll do retries here and use a // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); From 54c5e16978b25a17d0bcc75f7040cab9ec920aeb Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Tue, 13 Aug 2013 12:41:06 -0700 Subject: [PATCH 122/296] In isMobileOk don't execute finally if mobile data is not supported. Move the early return outside the try {} finally so we don't call setEnableFailFastMobileData(DctContants.DISABLED). Otherwise referencing counting is wrong and an exception is thrown in DcTrackerBase. Bug: 10304904 Change-Id: I5ba5121e473bada9f3daa8d6f3d3577cec8212fc --- .../java/com/android/server/ConnectivityService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 00935f3472..fa016f4587 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3732,13 +3732,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { Random rand = new Random(); mParams = params; - try { - if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; - return result; - } + if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { + log("isMobileOk: not mobile capable"); + result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + return result; + } + try { // Enable fail fast as we'll do retries here and use a // hipri connection so the default connection stays active. log("isMobileOk: start hipri url=" + params.mUrl); From d23fa090e9cd4e05f0c65492b055397a68f1f2cf Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 16 Aug 2013 17:17:28 -0700 Subject: [PATCH 123/296] DO NOT MERGE: MDST is not ready until connected to DcTracker. When the system becomes loaded the PhoneApp can be delayed significantly and a call to setEnableFailFastMobileData may not occur because the channel between the MobileDataStateTracker (MDST) and DcTracker (DCT) is not connected. Solution: Add a isReady to MDST and isMobileDataStateTrackerReady to ConnectivityService and call it from isMobileOk. Bug: 10351868 Change-Id: I92f9d58121b88186b636cd71c2fd2ef9a28f7cf6 --- .../android/server/ConnectivityService.java | 28 +++++++++++++++---- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index fa016f4587..06708191d9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3572,6 +3572,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { enabled)); } + private boolean isMobileDataStateTrackerReady() { + MobileDataStateTracker mdst = + (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + return (mdst != null) && (mdst.isReady()); + } + @Override public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, final ResultReceiver resultReceiver) { @@ -3739,14 +3745,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { } try { - // Enable fail fast as we'll do retries here and use a - // hipri connection so the default connection stays active. - log("isMobileOk: start hipri url=" + params.mUrl); - mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + if (!mCs.isMobileDataStateTrackerReady()) { + // Wait for MobileDataStateTracker to be ready. + if (DBG) log("isMobileOk: mdst is not ready"); + while(SystemClock.elapsedRealtime() < endTime) { + if (mCs.isMobileDataStateTrackerReady()) { + // Enable fail fast as we'll do retries here and use a + // hipri connection so the default connection stays active. + if (DBG) log("isMobileOk: mdst ready, enable fail fast of mobile data"); + mCs.setEnableFailFastMobileData(DctConstants.ENABLED); + break; + } + sleep(1); + } + } + + log("isMobileOk: start hipri url=" + params.mUrl); + // First wait until we can start using hipri Binder binder = new Binder(); while(SystemClock.elapsedRealtime() < endTime) { From b48bb0801ae26fd0d4c759df6aa05d51f05f9c31 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 8 Aug 2013 19:24:09 +0900 Subject: [PATCH 124/296] Add a string constructor to LinkAddress. This will allow us to do new LinkAddress("2001:db8::1/64"). Bug: 10232006 Change-Id: If479bdbab16826afe9d82732215141841c282299 --- core/java/android/net/LinkAddress.java | 41 ++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index f6a114c834..a390add89e 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -32,27 +32,56 @@ public class LinkAddress implements Parcelable { /** * IPv4 or IPv6 address. */ - private final InetAddress address; + private InetAddress address; /** * Network prefix length */ - private final int prefixLength; + private int prefixLength; - public LinkAddress(InetAddress address, int prefixLength) { + private void init(InetAddress address, int prefixLength) { if (address == null || prefixLength < 0 || ((address instanceof Inet4Address) && prefixLength > 32) || (prefixLength > 128)) { throw new IllegalArgumentException("Bad LinkAddress params " + address + - prefixLength); + "/" + prefixLength); } this.address = address; this.prefixLength = prefixLength; } + public LinkAddress(InetAddress address, int prefixLength) { + init(address, prefixLength); + } + public LinkAddress(InterfaceAddress interfaceAddress) { - this.address = interfaceAddress.getAddress(); - this.prefixLength = interfaceAddress.getNetworkPrefixLength(); + init(interfaceAddress.getAddress(), + interfaceAddress.getNetworkPrefixLength()); + } + + /** + * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or + * "2001:db8::1/64". + * @param string The string to parse. + */ + public LinkAddress(String address) { + InetAddress inetAddress = null; + int prefixLength = -1; + try { + String [] pieces = address.split("/", 2); + prefixLength = Integer.parseInt(pieces[1]); + inetAddress = InetAddress.parseNumericAddress(pieces[0]); + } catch (NullPointerException e) { // Null string. + } catch (ArrayIndexOutOfBoundsException e) { // No prefix length. + } catch (NumberFormatException e) { // Non-numeric prefix. + } catch (IllegalArgumentException e) { // Invalid IP address. + } + + if (inetAddress == null || prefixLength == -1) { + throw new IllegalArgumentException("Bad LinkAddress params " + address); + } + + init(inetAddress, prefixLength); } @Override From 09de418b17408ca907452a56a70e58bba70fb540 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 8 Aug 2013 11:00:12 +0900 Subject: [PATCH 125/296] Modify LinkProperties address update methods. 1. Make addLinkAddress a no-op if the address already exists. 2. Make addLinkAddress, addStackedLink and removeStackedLink return a boolean indicating whether something changed. 3. Add a removeLinkAddress method (currently there is no way of removing an address). 3. Move hasIPv6Address from ConnectivityService to LinkProperties, where it belongs. Bug: 9625448 Bug: 10232006 Change-Id: If641d0198432a7a505e358c059171f25bc9f13d5 --- core/java/android/net/LinkProperties.java | 53 ++++++++++++++++-- .../src/android/net/LinkPropertiesTest.java | 56 +++++++++++++++++++ .../android/server/ConnectivityService.java | 18 +----- 3 files changed, 105 insertions(+), 22 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 6ab810c68d..1f73c4ad71 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -23,6 +23,7 @@ import android.text.TextUtils; import java.net.InetAddress; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.UnknownHostException; import java.util.ArrayList; @@ -153,8 +154,28 @@ public class LinkProperties implements Parcelable { return addresses; } - public void addLinkAddress(LinkAddress address) { - if (address != null) mLinkAddresses.add(address); + /** + * Adds a link address if it does not exist, or update it if it does. + * @param address The {@code LinkAddress} to add. + * @return true if the address was added, false if it already existed. + */ + public boolean addLinkAddress(LinkAddress address) { + // TODO: when the LinkAddress has other attributes beyond the + // address and the prefix length, update them here. + if (address != null && !mLinkAddresses.contains(address)) { + mLinkAddresses.add(address); + return true; + } + return false; + } + + /** + * Removes a link address. + * @param address The {@code LinkAddress} to remove. + * @return true if the address was removed, false if it did not exist. + */ + public boolean removeLinkAddress(LinkAddress toRemove) { + return mLinkAddresses.remove(toRemove); } /** @@ -245,11 +266,14 @@ public class LinkProperties implements Parcelable { * of stacked links. If link is null, nothing changes. * * @param link The link to add. + * @return true if the link was stacked, false otherwise. */ - public void addStackedLink(LinkProperties link) { + public boolean addStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { mStackedLinks.put(link.getInterfaceName(), link); + return true; } + return false; } /** @@ -258,12 +282,15 @@ public class LinkProperties implements Parcelable { * If there a stacked link with the same interfacename as link, it is * removed. Otherwise, nothing changes. * - * @param link The link to add. + * @param link The link to remove. + * @return true if the link was removed, false otherwise. */ - public void removeStackedLink(LinkProperties link) { + public boolean removeStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { - mStackedLinks.remove(link.getInterfaceName()); + LinkProperties removed = mStackedLinks.remove(link.getInterfaceName()); + return removed != null; } + return false; } /** @@ -339,6 +366,20 @@ public class LinkProperties implements Parcelable { return false; } + /** + * Returns true if this link has an IPv6 address. + * + * @return {@code true} if there is an IPv6 address, {@code false} otherwise. + */ + public boolean hasIPv6Address() { + for (LinkAddress address : mLinkAddresses) { + if (address.getAddress() instanceof Inet6Address) { + return true; + } + } + return false; + } + /** * Compares this {@code LinkProperties} interface name against the target * diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index 9fdfd0e641..a570802d29 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -306,5 +306,61 @@ public class LinkPropertiesTest extends TestCase { for (LinkProperties link : rmnet0.getStackedLinks()) { assertFalse("newname".equals(link.getInterfaceName())); } + + assertTrue(rmnet0.removeStackedLink(clat4)); + assertEquals(0, rmnet0.getStackedLinks().size()); + assertEquals(1, rmnet0.getAddresses().size()); + assertEquals(1, rmnet0.getLinkAddresses().size()); + assertEquals(1, rmnet0.getAllAddresses().size()); + assertEquals(1, rmnet0.getAllLinkAddresses().size()); + + assertFalse(rmnet0.removeStackedLink(clat4)); + } + + @SmallTest + public void testAddressMethods() { + LinkProperties lp = new LinkProperties(); + + // No addresses. + assertFalse(lp.hasIPv4Address()); + assertFalse(lp.hasIPv6Address()); + + // Addresses on stacked links don't count. + LinkProperties stacked = new LinkProperties(); + stacked.setInterfaceName("stacked"); + lp.addStackedLink(stacked); + stacked.addLinkAddress(LINKADDRV4); + stacked.addLinkAddress(LINKADDRV6); + assertTrue(stacked.hasIPv4Address()); + assertTrue(stacked.hasIPv6Address()); + assertFalse(lp.hasIPv4Address()); + assertFalse(lp.hasIPv6Address()); + lp.removeStackedLink(stacked); + assertFalse(lp.hasIPv4Address()); + assertFalse(lp.hasIPv6Address()); + + // Addresses on the base link. + // Check the return values of hasIPvXAddress and ensure the add/remove methods return true + // iff something changes. + assertTrue(lp.addLinkAddress(LINKADDRV6)); + assertFalse(lp.hasIPv4Address()); + assertTrue(lp.hasIPv6Address()); + + assertTrue(lp.removeLinkAddress(LINKADDRV6)); + assertTrue(lp.addLinkAddress(LINKADDRV4)); + assertTrue(lp.hasIPv4Address()); + assertFalse(lp.hasIPv6Address()); + + assertTrue(lp.addLinkAddress(LINKADDRV6)); + assertTrue(lp.hasIPv4Address()); + assertTrue(lp.hasIPv6Address()); + + // Adding an address twice has no effect. + // Removing an address that's not present has no effect. + assertFalse(lp.addLinkAddress(LINKADDRV4)); + assertTrue(lp.hasIPv4Address()); + assertTrue(lp.removeLinkAddress(LINKADDRV4)); + assertFalse(lp.hasIPv4Address()); + assertFalse(lp.removeLinkAddress(LINKADDRV4)); } } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a0e6dd1a87..07a7fbab74 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3982,8 +3982,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Get the type of addresses supported by this link LinkProperties lp = mCs.getLinkProperties( ConnectivityManager.TYPE_MOBILE_HIPRI); - boolean linkHasIpv4 = hasIPv4Address(lp); - boolean linkHasIpv6 = hasIPv6Address(lp); + boolean linkHasIpv4 = lp.hasIPv4Address(); + boolean linkHasIpv6 = lp.hasIPv6Address(); log("isMobileOk: linkHasIpv4=" + linkHasIpv4 + " linkHasIpv6=" + linkHasIpv6); @@ -4129,20 +4129,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - public boolean hasIPv4Address(LinkProperties lp) { - return lp.hasIPv4Address(); - } - - // Not implemented in LinkProperties, do it here. - public boolean hasIPv6Address(LinkProperties lp) { - for (LinkAddress address : lp.getLinkAddresses()) { - if (address.getAddress() instanceof Inet6Address) { - return true; - } - } - return false; - } - private void log(String s) { Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s); } From 30ad254a1e10e1d410719496c8cfda794015795f Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Wed, 21 Aug 2013 13:09:01 -0700 Subject: [PATCH 126/296] Introduce network link quality statistics This change starts tracking traffic quality data for WiFi and mobile networks. The quality is tracked based on incidental traffic, and not on specific measurements. Theoretical bandwidths are hard-coded, as well as sampling interval; although sampling interval can be changed by setting a system policy. Bugs filed to remove shortcomings of this change - 10342372 Change LinkInfo name to something better 10342318 Move hardcoded values of MobileLinkInfo to resources so they can be updated without changing code Bug: 10006249 Change-Id: I83d8c7594da20fe53abbd5e1f909b1f606b035bb --- .../java/android/net/ConnectivityManager.java | 39 +++++ .../android/net/IConnectivityManager.aidl | 8 + .../android/server/ConnectivityService.java | 150 +++++++++++++++++- 3 files changed, 194 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1b418fa5f8..f6a3a4a772 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1442,4 +1442,43 @@ public class ConnectivityManager { } return null; } + + /** + * get the information about a specific network link + * @hide + */ + public LinkInfo getLinkInfo(int networkType) { + try { + LinkInfo li = mService.getLinkInfo(networkType); + return li; + } catch (RemoteException e) { + return null; + } + } + + /** + * get the information of currently active network link + * @hide + */ + public LinkInfo getActiveLinkInfo() { + try { + LinkInfo li = mService.getActiveLinkInfo(); + return li; + } catch (RemoteException e) { + return null; + } + } + + /** + * get the information of all network links + * @hide + */ + public LinkInfo[] getAllLinkInfo() { + try { + LinkInfo[] li = mService.getAllLinkInfo(); + return li; + } catch (RemoteException e) { + return null; + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 992ec37cda..bf2dade3bc 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -16,6 +16,7 @@ package android.net; +import android.net.LinkInfo; import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; @@ -145,4 +146,11 @@ interface IConnectivityManager String getMobileProvisioningUrl(); String getMobileRedirectedProvisioningUrl(); + + LinkInfo getLinkInfo(int networkType); + + LinkInfo getActiveLinkInfo(); + + LinkInfo[] getAllLinkInfo(); + } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index a0e6dd1a87..27614d0f7d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -31,6 +31,7 @@ import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; +import android.app.AlarmManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -56,6 +57,7 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; +import android.net.LinkInfo; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; @@ -68,6 +70,7 @@ import android.net.NetworkUtils; import android.net.Proxy; import android.net.ProxyProperties; import android.net.RouteInfo; +import android.net.SamplingDataTracker; import android.net.Uri; import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; @@ -144,8 +147,10 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.GregorianCalendar; +import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; @@ -174,6 +179,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String FAIL_FAST_TIME_MS = "persist.radio.fail_fast_time_ms"; + private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED = + "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED"; + + private static final int SAMPLE_INTERVAL_ELAPSED_REQURST_CODE = 0; + + private PendingIntent mSampleIntervalElapsedIntent; + + // Set network sampling interval at 12 minutes, this way, even if the timers get + // aggregated, it will fire at around 15 minutes, which should allow us to + // aggregate this timer with other timers (specially the socket keep alive timers) + private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 12 * 60); + + // start network sampling a minute after booting ... + private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 60); + + AlarmManager mAlarmManager; + // used in recursive route setting to add gateways for the host for which // a host route was requested. private static final int MAX_HOSTROUTE_CYCLE_COUNT = 10; @@ -326,6 +348,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14; + /** + * user internally to indicate that data sampling interval is up + */ + private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15; + /** Handler used for internal events. */ private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -392,6 +419,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { List mProtectedNetworks; private DataConnectionStats mDataConnectionStats; + private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0); TelephonyManager mTelephonyManager; @@ -634,6 +662,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); + // start network sampling .. + Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null); + mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext, + SAMPLE_INTERVAL_ELAPSED_REQURST_CODE, intent, 0); + + mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); + setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent); + + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED); + mContext.registerReceiver( + new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (action.equals(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED)) { + mHandler.sendMessage(mHandler.obtainMessage + (EVENT_SAMPLE_INTERVAL_ELAPSED)); + } + } + }, + new IntentFilter(filter)); + mPacManager = new PacManager(mContext); } @@ -1911,6 +1962,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // if (mActiveDefaultNetwork != -1) { // currentPriority = mNetConfigs[mActiveDefaultNetwork].mPriority; // } + for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { if (checkType == prevNetType) continue; if (mNetConfigs[checkType] == null) continue; @@ -1925,6 +1977,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // optimization should work and we need to investigate why it doesn't work. // This could be related to how DEACTIVATE_DATA_CALL is reporting its // complete before it is really complete. + // if (!mNetTrackers[checkType].isAvailable()) continue; // if (currentPriority >= mNetConfigs[checkType].mPriority) continue; @@ -2520,12 +2573,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } - /** + /** * Reads the network specific TCP buffer sizes from SystemProperties * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system * wide use */ - private void updateNetworkSettings(NetworkStateTracker nt) { + private void updateNetworkSettings(NetworkStateTracker nt) { String key = nt.getTcpBufferSizesPropName(); String bufferSizes = key == null ? null : SystemProperties.get(key); @@ -2547,7 +2600,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - /** + /** * Writes TCP buffer sizes to /sys/kernel/ipv4/tcp_[r/w]mem_[min/def/max] * which maps to /proc/sys/net/ipv4/tcp_rmem and tcpwmem * @@ -2956,6 +3009,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { + " != tag:" + tag); } } + case EVENT_SAMPLE_INTERVAL_ELAPSED: + handleNetworkSamplingTimeout(); + break; } } } @@ -4371,4 +4427,92 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } }; + + @Override + public LinkInfo getLinkInfo(int networkType) { + enforceAccessPermission(); + if (isNetworkTypeValid(networkType)) { + return mNetTrackers[networkType].getLinkInfo(); + } else { + return null; + } + } + + @Override + public LinkInfo getActiveLinkInfo() { + enforceAccessPermission(); + if (isNetworkTypeValid(mActiveDefaultNetwork)) { + return mNetTrackers[mActiveDefaultNetwork].getLinkInfo(); + } else { + return null; + } + } + + @Override + public LinkInfo[] getAllLinkInfo() { + enforceAccessPermission(); + final ArrayList result = Lists.newArrayList(); + for (NetworkStateTracker tracker : mNetTrackers) { + if (tracker != null) { + LinkInfo li = tracker.getLinkInfo(); + if (li != null) { + result.add(li); + } + } + } + + return result.toArray(new LinkInfo[result.size()]); + } + + /* Infrastructure for network sampling */ + + private void handleNetworkSamplingTimeout() { + + log("Sampling interval elapsed, updating statistics .."); + + // initialize list of interfaces .. + Map mapIfaceToSample = + new HashMap(); + for (NetworkStateTracker tracker : mNetTrackers) { + if (tracker != null) { + String ifaceName = tracker.getNetworkInterfaceName(); + if (ifaceName != null) { + mapIfaceToSample.put(ifaceName, null); + } + } + } + + // Read samples for all interfaces + SamplingDataTracker.getSamplingSnapshots(mapIfaceToSample); + + // process samples for all networks + for (NetworkStateTracker tracker : mNetTrackers) { + if (tracker != null) { + String ifaceName = tracker.getNetworkInterfaceName(); + SamplingDataTracker.SamplingSnapshot ss = mapIfaceToSample.get(ifaceName); + if (ss != null) { + // end the previous sampling cycle + tracker.stopSampling(ss); + // start a new sampling cycle .. + tracker.startSampling(ss); + } + } + } + + log("Done."); + + int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS, + DEFAULT_SAMPLING_INTERVAL_IN_SECONDS); + + if (DBG) log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds"); + + setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent); + } + + void setAlarm(int timeoutInMilliseconds, PendingIntent intent) { + long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds; + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent); + } } + From 2337946b4f5f072a0d404183860365ce87a98bd2 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 20 Aug 2013 22:51:24 +0900 Subject: [PATCH 127/296] Add a simple test for NetworkManagementService. For now, this only tests network observers. It works by starting NetworkManagementService with a fake netd socket, feeding it inputs, and seeing if the appropriate observer methods are called. Bug: 10232006 Change-Id: I827681575642a4ee13ae48b81272521544b676bd --- .../server/NetworkManagementServiceTest.java | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java new file mode 100644 index 0000000000..56dd7c40df --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -0,0 +1,175 @@ +/* + * 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.content.Context; +import android.net.LocalSocket; +import android.net.LocalServerSocket; +import android.os.Binder; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.LargeTest; +import com.android.server.net.BaseNetworkObserver; + +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoMoreInteractions; + +import java.io.IOException; +import java.io.OutputStream; + +/** + * Tests for {@link NetworkManagementService}. + */ +@LargeTest +public class NetworkManagementServiceTest extends AndroidTestCase { + + private static final String SOCKET_NAME = "__test__NetworkManagementServiceTest"; + private NetworkManagementService mNMService; + private LocalServerSocket mServerSocket; + private LocalSocket mSocket; + private OutputStream mOutputStream; + + @Override + public void setUp() throws Exception { + super.setUp(); + // TODO: make this unnecessary. runtest might already make it unnecessary. + System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString()); + + // Set up a sheltered test environment. + BroadcastInterceptingContext context = new BroadcastInterceptingContext(getContext()); + mServerSocket = new LocalServerSocket(SOCKET_NAME); + + // Start the service and wait until it connects to our socket. + mNMService = NetworkManagementService.create(context, SOCKET_NAME); + mSocket = mServerSocket.accept(); + mOutputStream = mSocket.getOutputStream(); + } + + @Override + public void tearDown() throws Exception { + if (mSocket != null) mSocket.close(); + if (mServerSocket != null) mServerSocket.close(); + super.tearDown(); + } + + /** + * Sends a message on the netd socket and gives the events some time to make it back. + */ + private void sendMessage(String message) throws IOException { + // Strings are null-terminated, so add "\0" at the end. + mOutputStream.write((message + "\0").getBytes()); + } + + private static T expectSoon(T mock) { + return verify(mock, timeout(100)); + } + + /** + * Tests that network observers work properly. + */ + public void testNetworkObservers() throws Exception { + BaseNetworkObserver observer = mock(BaseNetworkObserver.class); + doReturn(new Binder()).when(observer).asBinder(); // Used by registerObserver. + mNMService.registerObserver(observer); + + // Forget everything that happened to the mock so far, so we can explicitly verify + // everything that happens and does not happen to it from now on. + reset(observer); + + // Now send NetworkManagementService messages and ensure that the observer methods are + // called. After every valid message we expect a callback soon after; to ensure that + // invalid messages don't cause any callbacks, we call verifyNoMoreInteractions at the end. + + /** + * Interface changes. + */ + sendMessage("600 Iface added rmnet12"); + expectSoon(observer).interfaceAdded("rmnet12"); + + sendMessage("600 Iface removed eth1"); + expectSoon(observer).interfaceRemoved("eth1"); + + sendMessage("607 Iface removed eth1"); + // Invalid code. + + sendMessage("600 Iface borked lo down"); + // Invalid event. + + sendMessage("600 Iface changed clat4 up again"); + // Extra tokens. + + sendMessage("600 Iface changed clat4 up"); + expectSoon(observer).interfaceStatusChanged("clat4", true); + + sendMessage("600 Iface linkstate rmnet0 down"); + expectSoon(observer).interfaceLinkStateChanged("rmnet0", false); + + sendMessage("600 IFACE linkstate clat4 up"); + // Invalid group. + + /** + * Bandwidth control events. + */ + sendMessage("601 limit alert data rmnet_usb0"); + expectSoon(observer).limitReached("data", "rmnet_usb0"); + + sendMessage("601 invalid alert data rmnet0"); + // Invalid group. + + sendMessage("601 limit increased data rmnet0"); + // Invalid event. + + + /** + * Interface class activity. + */ + sendMessage("613 IfaceClass active rmnet0"); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true); + + sendMessage("613 IfaceClass idle eth0"); + expectSoon(observer).interfaceClassDataActivityChanged("eth0", false); + + sendMessage("613 IfaceClass reallyactive rmnet0"); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", false); + + sendMessage("613 InterfaceClass reallyactive rmnet0"); + // Invalid group. + + + /** + * IP address changes. + */ + sendMessage("614 Address updated fe80::1/64 wlan0 128 253"); + expectSoon(observer).addressUpdated("fe80::1/64", "wlan0", 128, 253); + + // There is no "added". + sendMessage("614 Address added fe80::1/64 wlan0 128 253"); + expectSoon(observer).addressRemoved("fe80::1/64", "wlan0", 128, 253); + + sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0"); + expectSoon(observer).addressRemoved("2001:db8::1/64", "wlan0", 1, 0); + + sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); + // Invalid code. + + // Make sure nothing else was called. + verifyNoMoreInteractions(observer); + } +} From 01a790ad556662f09097ab59462c66e0fa6a6185 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Tue, 27 Aug 2013 10:51:24 -0400 Subject: [PATCH 128/296] Don't clear Global Proxy on boot. Doesn't clear the global proxy when a deprecated one is not found because there still may be a non-deprecated global proxy present. Bug: 10457179 Change-Id: I68e6d5aee7b4940f9315484060c7d82cb8ccfa70 --- services/java/com/android/server/ConnectivityService.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ec6b063e82..136a85e0af 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3355,8 +3355,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } ProxyProperties p = new ProxyProperties(data[0], proxyPort, ""); setGlobalProxy(p); - } else { - setGlobalProxy(null); } } From 1b5a3acb8b1f303f14a330aa2a0616fb1612178e Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Tue, 27 Aug 2013 11:41:19 -0700 Subject: [PATCH 129/296] Minor fixes: Add a missing "break" and some cosmetic fixes. Change-Id: Ie614a7b47185fd511fdc3f064620e46ab7d6d8f8 --- .../android/server/ConnectivityService.java | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ec6b063e82..5e0ee151ea 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -182,7 +182,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED = "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED"; - private static final int SAMPLE_INTERVAL_ELAPSED_REQURST_CODE = 0; + private static final int SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE = 0; private PendingIntent mSampleIntervalElapsedIntent; @@ -665,7 +665,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // start network sampling .. Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED, null); mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext, - SAMPLE_INTERVAL_ELAPSED_REQURST_CODE, intent, 0); + SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0); mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent); @@ -2924,7 +2924,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { - case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: + case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: { String causedBy = null; synchronized (ConnectivityService.this) { if (msg.arg1 == mNetTransitionWakeLockSerialNumber && @@ -2937,49 +2937,44 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("NetTransition Wakelock for " + causedBy + " released by timeout"); } break; - case EVENT_RESTORE_DEFAULT_NETWORK: + } + case EVENT_RESTORE_DEFAULT_NETWORK: { FeatureUser u = (FeatureUser)msg.obj; u.expire(); break; - case EVENT_INET_CONDITION_CHANGE: - { + } + case EVENT_INET_CONDITION_CHANGE: { int netType = msg.arg1; int condition = msg.arg2; handleInetConditionChange(netType, condition); break; } - case EVENT_INET_CONDITION_HOLD_END: - { + case EVENT_INET_CONDITION_HOLD_END: { int netType = msg.arg1; int sequence = msg.arg2; handleInetConditionHoldEnd(netType, sequence); break; } - case EVENT_SET_NETWORK_PREFERENCE: - { + case EVENT_SET_NETWORK_PREFERENCE: { int preference = msg.arg1; handleSetNetworkPreference(preference); break; } - case EVENT_SET_MOBILE_DATA: - { + case EVENT_SET_MOBILE_DATA: { boolean enabled = (msg.arg1 == ENABLED); handleSetMobileData(enabled); break; } - case EVENT_APPLY_GLOBAL_HTTP_PROXY: - { + case EVENT_APPLY_GLOBAL_HTTP_PROXY: { handleDeprecatedGlobalHttpProxy(); break; } - case EVENT_SET_DEPENDENCY_MET: - { + case EVENT_SET_DEPENDENCY_MET: { boolean met = (msg.arg1 == ENABLED); handleSetDependencyMet(msg.arg2, met); break; } - case EVENT_SEND_STICKY_BROADCAST_INTENT: - { + case EVENT_SEND_STICKY_BROADCAST_INTENT: { Intent intent = (Intent)msg.obj; sendStickyBroadcast(intent); break; @@ -3008,10 +3003,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1 + " != tag:" + tag); } + break; } - case EVENT_SAMPLE_INTERVAL_ELAPSED: + case EVENT_SAMPLE_INTERVAL_ELAPSED: { handleNetworkSamplingTimeout(); break; + } } } } From 9a1a7ef57c704f58aac2f8c7c546e0b9d1b53dcc Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 29 Aug 2013 08:55:16 -0700 Subject: [PATCH 130/296] Add support for handling mobile provisioning networks. When a sim is new or it has expired it needs to be provisioned with the carrier. Basically provisioning is associating a sim with a user account. When a sim isn't provisioned then operators will restrict access to the network and only allow certain addresses or services to be used. This set of changes allows two types of provisioning networks to be recognized. The first is a network that causes all DNS lookups to be redirected to a different address than was intended. This is exemplified by how T-Mobile works. The second technique uses a special apn for provisioning. An example is AT&T where lwaactivate is the provisioning apn and broadband is the normal apn. We first try broadband and if we are unable to connect we try lwaactivate. When we see the activate we identify it as special and the ApnContext.isProvisioningApn will return true. In the future our plan is to create a new network type that can be added to the apn list, but for now it identified by name. Here is a list of significant changes: - CaptivePortalTracker now only test WiFi networks instead of all networks - checkMobileProvisioning checks for provisioning networks and doesn't try to ping. - IConnectivityManager.aidl changes: * getProvisioningOrActiveNetworkInfo was added to and used by Manage mobile plan in WirelessSettings so even when there is no active network it will still allow provisioning. Otherwise it would report no internet connection. * setSignInErrorNotificationVisible is used by both CaptiviePortalTracker and checkMobileProvisioning so they use the same code for the notifications. * checkMobileProvisioning was simplified to have only a timeout as returning the result is now harder as we abort simultaneous call otherwise we'd could get into loops because we now check every time we connect to mobile. - Enhanced MDST to handle the provisioning network. - Added CONNECTED_TO_PROVISIONING_NETWORK to NetworkInfo to make a new state so we don't announce to the world we're connected. - TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN is sent by the low level data connection code to notify Connectivity Service that a provisioning apn has connected. This allows CS to handle the connection differently than a normal connection. Bug: 10328264 Change-Id: I3925004011bb1243793c4c1b963d923dc2b00cb5 --- .../java/android/net/ConnectivityManager.java | 89 ++-- .../android/net/IConnectivityManager.aidl | 6 +- core/java/android/net/NetworkInfo.java | 7 + .../android/server/ConnectivityService.java | 451 ++++++++++++++---- 4 files changed, 410 insertions(+), 143 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index aa2d4ce92e..02a649401f 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -582,6 +582,29 @@ public class ConnectivityManager { } } + /** + * Returns details about the Provisioning or currently active default data network. When + * connected, this network is the default route for outgoing connections. + * You should always check {@link NetworkInfo#isConnected()} before initiating + * network traffic. This may return {@code null} when there is no default + * network. + * + * @return a {@link NetworkInfo} object for the current default network + * or {@code null} if no network default network is currently active + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * + * {@hide} + */ + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + try { + return mService.getProvisioningOrActiveNetworkInfo(); + } catch (RemoteException e) { + return null; + } + } + /** * Returns the IP information for the current default network. * @@ -1316,63 +1339,19 @@ public class ConnectivityManager { } /** - * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) - */ - - /** - * No connection was possible to the network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; - - /** - * A connection was made to the internet, all is well. - * {@hide} - */ - public static final int CMP_RESULT_CODE_CONNECTABLE = 1; - - /** - * A connection was made but there was a redirection, we appear to be in walled garden. - * This is an indication of a warm sim on a mobile network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_REDIRECTED = 2; - - /** - * A connection was made but no dns server was available to resolve a name to address. - * This is an indication of a warm sim on a mobile network. + * Check mobile provisioning. * - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_DNS = 3; - - /** - * A connection was made but could not open a TCP connection. - * This is an indication of a warm sim on a mobile network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; - - /** - * Check mobile provisioning. The resultCode passed to - * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above. - * This may take a minute or more to complete. - * - * @param sendNotificaiton, when true a notification will be sent to user. * @param suggestedTimeOutMs, timeout in milliseconds - * @param resultReceiver needs to be supplied to receive the result * * @return time out that will be used, maybe less that suggestedTimeOutMs * -1 if an error. * * {@hide} */ - public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, - ResultReceiver resultReceiver) { + public int checkMobileProvisioning(int suggestedTimeOutMs) { int timeOutMs = -1; try { - timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs, - resultReceiver); + timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs); } catch (RemoteException e) { } return timeOutMs; @@ -1401,4 +1380,20 @@ public class ConnectivityManager { } return null; } + + /** + * Set sign in error notification to visible or in visible + * + * @param visible + * @param networkType + * + * {@hide} + */ + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + try { + mService.setProvisioningNotificationVisible(visible, networkType, extraInfo, url); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 3ac5f1367f..a17b4f5f95 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -46,6 +46,8 @@ interface IConnectivityManager NetworkInfo getNetworkInfo(int networkType); NetworkInfo[] getAllNetworkInfo(); + NetworkInfo getProvisioningOrActiveNetworkInfo(); + boolean isNetworkSupported(int networkType); LinkProperties getActiveLinkProperties(); @@ -135,9 +137,11 @@ interface IConnectivityManager int findConnectionTypeForIface(in String iface); - int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); + int checkMobileProvisioning(int suggestedTimeOutMs); String getMobileProvisioningUrl(); String getMobileRedirectedProvisioningUrl(); + + void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 689dae5301..dabc73a716 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -84,6 +84,12 @@ public class NetworkInfo implements Parcelable { VERIFYING_POOR_LINK, /** Checking if network is a captive portal */ CAPTIVE_PORTAL_CHECK, + /** + * Network is connected to provisioning network + * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK + * @hide + */ + CONNECTED_TO_PROVISIONING_NETWORK } /** @@ -108,6 +114,7 @@ public class NetworkInfo implements Parcelable { stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); stateMap.put(DetailedState.FAILED, State.DISCONNECTED); stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); + stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED); } private int mNetworkType; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 06708191d9..ee23b13d3f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -35,6 +35,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothTetheringDataTracker; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -143,6 +144,7 @@ import java.util.GregorianCalendar; import java.util.HashSet; import java.util.List; import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** @@ -383,9 +385,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; - // We only want one checkMobileProvisioning after booting. - volatile boolean mFirstProvisioningCheckStarted = false; - public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -609,8 +608,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); mSettingsObserver.observe(mContext); - mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); - loadGlobalProxy(); + IntentFilter filter = new IntentFilter(); + filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + mContext.registerReceiver(mProvisioningReceiver, filter); } /** @@ -879,6 +879,46 @@ public class ConnectivityService extends IConnectivityManager.Stub { return getNetworkInfo(mActiveDefaultNetwork, uid); } + /** + * Find the first Provisioning network. + * + * @return NetworkInfo or null if none. + */ + private NetworkInfo getProvisioningNetworkInfo() { + enforceAccessPermission(); + + // Find the first Provisioning Network + NetworkInfo provNi = null; + for (NetworkInfo ni : getAllNetworkInfo()) { + if (ni.getDetailedState() + == NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + provNi = ni; + break; + } + } + if (DBG) log("getProvisioningNetworkInfo: X provNi=" + provNi); + return provNi; + } + + /** + * Find the first Provisioning network or the ActiveDefaultNetwork + * if there is no Provisioning network + * + * @return NetworkInfo or null if none. + */ + @Override + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + enforceAccessPermission(); + + NetworkInfo provNi = getProvisioningNetworkInfo(); + if (provNi == null) { + final int uid = Binder.getCallingUid(); + provNi = getNetworkInfo(mActiveDefaultNetwork, uid); + } + if (DBG) log("getProvisioningOrActiveNetworkInfo: X provNi=" + provNi); + return provNi; + } + public NetworkInfo getActiveNetworkInfoUnfiltered() { enforceAccessPermission(); if (isNetworkTypeValid(mActiveDefaultNetwork)) { @@ -1241,8 +1281,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { feature); } if (network.reconnect()) { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED"); return PhoneConstants.APN_REQUEST_STARTED; } else { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED"); return PhoneConstants.APN_REQUEST_FAILED; } } else { @@ -1254,9 +1296,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[usedNetworkType].add(currentPid); } } + if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature."); return -1; } } + if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE"); return PhoneConstants.APN_TYPE_NOT_AVAILABLE; } finally { if (DBG) { @@ -1290,11 +1334,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } if (found && u != null) { + if (VDBG) log("stopUsingNetworkFeature: X"); // stop regardless of how many other time this proc had called start return stopUsingNetworkFeature(u, true); } else { // none found! - if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring"); + if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring"); return 1; } } @@ -1849,6 +1894,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ if (mNetConfigs[prevNetType].isDefault()) { if (mActiveDefaultNetwork == prevNetType) { + if (DBG) { + log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType); + } mActiveDefaultNetwork = -1; } @@ -2041,6 +2089,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void systemReady() { + mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); + loadGlobalProxy(); + synchronized(this) { mSystemReady = true; if (mInitialBroadcast != null) { @@ -2071,10 +2122,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; private boolean isNewNetTypePreferredOverCurrentNetType(int type) { - if ((type != mNetworkPreference && - mNetConfigs[mActiveDefaultNetwork].priority > - mNetConfigs[type].priority) || - mNetworkPreference == mActiveDefaultNetwork) return false; + if (((type != mNetworkPreference) + && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority)) + || (mNetworkPreference == mActiveDefaultNetwork)) { + return false; + } return true; } @@ -2088,6 +2140,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { final NetworkStateTracker thisNet = mNetTrackers[newNetType]; final String thisIface = thisNet.getLinkProperties().getInterfaceName(); + if (VDBG) { + log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface + + " isFailover" + isFailover); + } + // if this is a default net and other default is running // kill the one not preferred if (mNetConfigs[newNetType].isDefault()) { @@ -2249,6 +2306,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private void handleConnectivityChange(int netType, boolean doReset) { int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; + if (VDBG) { + log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset + + " resetMask=" + resetMask); + } /* * If a non-default network is enabled, add the host routes that @@ -2316,7 +2377,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault()); if (resetMask != 0 || resetDns) { + if (VDBG) log("handleConnectivityChange: resetting"); if (curLp != null) { + if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp); for (String iface : curLp.getAllInterfaceNames()) { if (TextUtils.isEmpty(iface) == false) { if (resetMask != 0) { @@ -2349,6 +2412,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Update 464xlat state. NetworkStateTracker tracker = mNetTrackers[netType]; if (mClat.requiresClat(netType, tracker)) { + // If the connection was previously using clat, but is not using it now, stop the clat // daemon. Normally, this happens automatically when the connection disconnects, but if // the disconnect is not reported, or if the connection's LinkProperties changed for @@ -2402,6 +2466,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { + if (VDBG) log("updateRoutes: default remove route r=" + r); removeRoute(curLp, r, TO_DEFAULT_TABLE); } if (isLinkDefault == false) { @@ -2446,7 +2511,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { // remove the default route unless somebody else has asked for it String ifaceName = newLp.getInterfaceName(); if (TextUtils.isEmpty(ifaceName) == false && mAddedRoutes.contains(r) == false) { - if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { mNetd.removeRoute(ifaceName, r); } catch (Exception e) { @@ -2736,9 +2800,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { - case NetworkStateTracker.EVENT_STATE_CHANGED: + case NetworkStateTracker.EVENT_STATE_CHANGED: { info = (NetworkInfo) msg.obj; - int type = info.getType(); NetworkInfo.State state = info.getState(); if (VDBG || (state == NetworkInfo.State.CONNECTED) || @@ -2748,15 +2811,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } - // After booting we'll check once for mobile provisioning - // if we've provisioned by and connected. - if (!mFirstProvisioningCheckStarted + // Since mobile has the notion of a network/apn that can be used for + // provisioning we need to check every time we're connected as + // CaptiveProtalTracker won't detected it because DCT doesn't report it + // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its + // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which + // is received by MDST and sent here as EVENT_STATE_CHANGED. + if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) && (state == NetworkInfo.State.CONNECTED)) { - log("check provisioning after booting"); - mFirstProvisioningCheckStarted = true; - checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); + checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } EventLogTags.writeConnectivityStateChanged( @@ -2768,6 +2833,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (info.getDetailedState() == DetailedState.CAPTIVE_PORTAL_CHECK) { handleCaptivePortalTrackerCheck(info); + } else if (info.getDetailedState() == + DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + /** + * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING + * for now its an in between network, its a network that + * is actually a default network but we don't want it to be + * announced as such to keep background applications from + * trying to use it. It turns out that some still try so we + * take the additional step of clearing any default routes + * to the link that may have incorrectly setup by the lower + * levels. + */ + LinkProperties lp = getLinkProperties(info.getType()); + if (DBG) { + log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp); + } + + // Clear any default routes setup by the radio so + // any activity by applications trying to use this + // connection will fail until the provisioning network + // is enabled. + for (RouteInfo r : lp.getRoutes()) { + removeRoute(lp, r, TO_DEFAULT_TABLE); + } } else if (state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) { @@ -2786,18 +2875,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { mLockdownTracker.onNetworkInfoChanged(info); } break; - case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: + } + case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: { info = (NetworkInfo) msg.obj; // TODO: Temporary allowing network configuration // change not resetting sockets. // @see bug/4455071 handleConnectivityChange(info.getType(), false); break; - case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + } + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { info = (NetworkInfo) msg.obj; - type = info.getType(); + int type = info.getType(); updateNetworkSettings(mNetTrackers[type]); break; + } } } } @@ -3574,76 +3666,151 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean isMobileDataStateTrackerReady() { MobileDataStateTracker mdst = - (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; return (mdst != null) && (mdst.isReady()); } + /** + * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) + */ + + /** + * No connection was possible to the network. + */ + public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; + + /** + * A connection was made to the internet, all is well. + */ + public static final int CMP_RESULT_CODE_CONNECTABLE = 1; + + /** + * A connection was made but there was a redirection, we appear to be in walled garden. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_REDIRECTED = 2; + + /** + * A connection was made but no dns server was available to resolve a name to address. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_NO_DNS = 3; + + /** + * A connection was made but could not open a TCP connection. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; + + /** + * The mobile network is a provisioning network. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + + AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); + @Override - public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, - final ResultReceiver resultReceiver) { - log("checkMobileProvisioning: E sendNotification=" + sendNotification - + " suggestedTimeOutMs=" + suggestedTimeOutMs - + " resultReceiver=" + resultReceiver); - enforceChangePermission(); - - mFirstProvisioningCheckStarted = true; - - int timeOutMs = suggestedTimeOutMs; - if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { - timeOutMs = CheckMp.MAX_TIMEOUT_MS; - } - - // Check that mobile networks are supported - if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) - || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { - log("checkMobileProvisioning: X no mobile network"); - if (resultReceiver != null) { - resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); - } - return timeOutMs; - } + public int checkMobileProvisioning(int suggestedTimeOutMs) { + int timeOutMs = -1; + if (DBG) log("checkMobileProvisioning: E suggestedTimeOutMs=" + suggestedTimeOutMs); + enforceConnectivityInternalPermission(); final long token = Binder.clearCallingIdentity(); try { + timeOutMs = suggestedTimeOutMs; + if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { + timeOutMs = CheckMp.MAX_TIMEOUT_MS; + } + + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + if (DBG) log("checkMobileProvisioning: X no mobile network"); + return timeOutMs; + } + + // If we're already checking don't do it again + // TODO: Add a queue of results... + if (mIsCheckingMobileProvisioning.getAndSet(true)) { + if (DBG) log("checkMobileProvisioning: X already checking ignore for the moment"); + return timeOutMs; + } + + // Start off with notification off + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // See if we've alreadying determined if we've got a provsioning connection + // if so we don't need to do anything active + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + + if (isDefaultProvisioning || isHipriProvisioning) { + if (mIsNotificationVisible) { + if (DBG) { + log("checkMobileProvisioning: provisioning-ignore notification is visible"); + } + } else { + NetworkInfo ni = null; + if (isDefaultProvisioning) { + ni = mdstDefault.getNetworkInfo(); + } + if (isHipriProvisioning) { + ni = mdstHipri.getNetworkInfo(); + } + String url = getMobileProvisioningUrl(); + if ((ni != null) && (!TextUtils.isEmpty(url))) { + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); + } else { + if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); + } + } + mIsCheckingMobileProvisioning.set(false); + return timeOutMs; + } + CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override void onComplete(Integer result) { - log("CheckMp.onComplete: result=" + result); - if (resultReceiver != null) { - log("CheckMp.onComplete: send result"); - resultReceiver.send(result, null); - } + if (DBG) log("CheckMp.onComplete: result=" + result); NetworkInfo ni = mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { - case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE: - case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: { - log("CheckMp.onComplete: ignore, connected or no connection"); + case CMP_RESULT_CODE_CONNECTABLE: + case CMP_RESULT_CODE_NO_CONNECTION: { + if (DBG) log("CheckMp.onComplete: ignore, connected or no connection"); break; } - case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { - log("CheckMp.onComplete: warm sim"); + case CMP_RESULT_CODE_REDIRECTED: { + if (DBG) log("CheckMp.onComplete: warm sim"); String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url)) { url = getMobileRedirectedProvisioningUrl(); } if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (redirected), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (redirected), no url"); + if (DBG) log("CheckMp.onComplete: warm (redirected), no url"); } break; } - case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: - case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { + case CMP_RESULT_CODE_NO_DNS: + case CMP_RESULT_CODE_NO_TCP_CONNECTION: { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (no dns/tcp), no url"); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); } break; } @@ -3652,16 +3819,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } } + mIsCheckingMobileProvisioning.set(false); } }; CheckMp.Params params = new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); - log("checkMobileProvisioning: params=" + params); - setNotificationVisible(false, null, null); + if (DBG) log("checkMobileProvisioning: params=" + params); checkMp.execute(params); } finally { Binder.restoreCallingIdentity(token); - log("checkMobileProvisioning: X"); + if (DBG) log("checkMobileProvisioning: X"); } return timeOutMs; } @@ -3733,14 +3900,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { * a known address that fetches the data we expect. */ private synchronized Integer isMobileOk(Params params) { - Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + Integer result = CMP_RESULT_CODE_NO_CONNECTION; Uri orgUri = Uri.parse(params.mUrl); Random rand = new Random(); mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; return result; } @@ -3776,7 +3943,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } if (VDBG) log("isMobileOk: hipri not started yet"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; sleep(1); } @@ -3789,15 +3956,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - if (VDBG) { + if (true/*VDBG*/) { log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } sleep(1); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; continue; } + // Hipri has started check if this is a provisioning url + MobileDataStateTracker mdst = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + if (mdst.isProvisioningNetwork()) { + if (DBG) log("isMobileOk: isProvisioningNetwork is true, no TCP conn"); + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; + return result; + } else { + if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); + } + // Get of the addresses associated with the url host. We need to use the // address otherwise HttpURLConnection object will use the name to get // the addresses and is will try every address but that will bypass the @@ -3808,7 +3986,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { log("isMobileOk: UnknownHostException"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS; + result = CMP_RESULT_CODE_NO_DNS; return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -3873,9 +4051,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); if (responseCode == 204) { - result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE; + result = CMP_RESULT_CODE_CONNECTABLE; } else { - result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED; + result = CMP_RESULT_CODE_REDIRECTED; } log("isMobileOk: connected responseCode=" + responseCode); urlConn.disconnect(); @@ -3889,7 +4067,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION; + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; log("isMobileOk: loops|timed out"); return result; } catch (Exception e) { @@ -3903,6 +4081,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCs.setEnableFailFastMobileData(DctConstants.DISABLED); mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_HIPRI); + + // Wait for hipri to disconnect. + long endTime = SystemClock.elapsedRealtime() + 5000; + + while(SystemClock.elapsedRealtime() < endTime) { + NetworkInfo.State state = mCs + .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); + if (state != NetworkInfo.State.DISCONNECTED) { + if (VDBG) { + log("isMobileOk: connected ni=" + + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } + sleep(1); + continue; + } + } + log("isMobileOk: X result=" + result); } return result; @@ -3982,10 +4177,55 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + // TODO: Move to ConnectivityManager and make public? + private static final String CONNECTED_TO_PROVISIONING_NETWORK_ACTION = + "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION"; - private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) { - log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url); + private BroadcastReceiver mProvisioningReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CONNECTED_TO_PROVISIONING_NETWORK_ACTION)) { + handleMobileProvisioningAction(intent.getStringExtra("EXTRA_URL")); + } + } + }; + + private void handleMobileProvisioningAction(String url) { + // Notication mark notification as not visible + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // If provisioning network handle as a special case, + // otherwise launch browser with the intent directly. + NetworkInfo ni = getProvisioningNetworkInfo(); + if ((ni != null) && ni.getDetailedState() == + NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if (DBG) log("handleMobileProvisioningAction: on provisioning network"); + MobileDataStateTracker mdst = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.enableMobileProvisioning(url); + } else { + if (DBG) log("handleMobileProvisioningAction: on default network"); + Intent newIntent = + new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(newIntent); + } catch (ActivityNotFoundException e) { + loge("handleMobileProvisioningAction: startActivity failed" + e); + } + } + } + + private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + private volatile boolean mIsNotificationVisible = false; + + private void setProvNotificationVisible(boolean visible, int networkType, String extraInfo, + String url) { + if (DBG) { + log("setProvNotificationVisible: E visible=" + visible + " networkType=" + networkType + + " extraInfo=" + extraInfo + " url=" + url); + } Resources r = Resources.getSystem(); NotificationManager notificationManager = (NotificationManager) mContext @@ -3995,50 +4235,64 @@ public class ConnectivityService extends IConnectivityManager.Stub { CharSequence title; CharSequence details; int icon; - switch (networkInfo.getType()) { + Intent intent; + Notification notification = new Notification(); + switch (networkType) { case ConnectivityManager.TYPE_WIFI: - log("setNotificationVisible: TYPE_WIFI"); title = r.getString(R.string.wifi_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_wifi_in_range; + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); break; case ConnectivityManager.TYPE_MOBILE: case ConnectivityManager.TYPE_MOBILE_HIPRI: - log("setNotificationVisible: TYPE_MOBILE|HIPRI"); title = r.getString(R.string.network_available_sign_in, 0); // TODO: Change this to pull from NetworkInfo once a printable // name has been added to it details = mTelephonyManager.getNetworkOperatorName(); icon = R.drawable.stat_notify_rssi_in_range; + intent = new Intent(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + intent.putExtra("EXTRA_URL", url); + intent.setFlags(0); + notification.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); break; default: - log("setNotificationVisible: other type=" + networkInfo.getType()); title = r.getString(R.string.network_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_rssi_in_range; + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); break; } - Notification notification = new Notification(); notification.when = 0; notification.icon = icon; notification.flags = Notification.FLAG_AUTO_CANCEL; - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | - Intent.FLAG_ACTIVITY_NEW_TASK); - notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); notification.tickerText = title; notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); - log("setNotificaitionVisible: notify notificaiton=" + notification); - notificationManager.notify(NOTIFICATION_ID, 1, notification); + try { + notificationManager.notify(NOTIFICATION_ID, 1, notification); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: visible notificationManager npe=" + npe); + npe.printStackTrace(); + } } else { - log("setNotificaitionVisible: cancel"); - notificationManager.cancel(NOTIFICATION_ID, 1); + try { + notificationManager.cancel(NOTIFICATION_ID, 1); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: cancel notificationManager npe=" + npe); + npe.printStackTrace(); + } } - log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); + mIsNotificationVisible = visible; } /** Location to an updatable file listing carrier provisioning urls. @@ -4166,4 +4420,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + + @Override + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + enforceConnectivityInternalPermission(); + setProvNotificationVisible(visible, networkType, extraInfo, url); + } } From 5fda0c1e0d3203ffb3708c664a2110b425d435a7 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 29 Aug 2013 14:57:08 -0700 Subject: [PATCH 131/296] Merge commit 'a37f06d7' into manualmerge * commit 'a37f06d7': Add support for handling mobile provisioning networks. Conflicts: core/java/android/net/CaptivePortalTracker.java core/java/android/net/ConnectivityManager.java core/java/android/net/IConnectivityManager.aidl core/java/android/net/MobileDataStateTracker.java core/res/AndroidManifest.xml services/java/com/android/server/ConnectivityService.java Change-Id: I3925004011bb1243793c4c1b963d923dc2b00cb5 --- .../java/android/net/ConnectivityManager.java | 89 ++-- .../android/net/IConnectivityManager.aidl | 5 +- core/java/android/net/NetworkInfo.java | 7 + .../android/server/ConnectivityService.java | 482 ++++++++++++++---- 4 files changed, 432 insertions(+), 151 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f6a3a4a772..3874369fcc 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -623,6 +623,29 @@ public class ConnectivityManager { } } + /** + * Returns details about the Provisioning or currently active default data network. When + * connected, this network is the default route for outgoing connections. + * You should always check {@link NetworkInfo#isConnected()} before initiating + * network traffic. This may return {@code null} when there is no default + * network. + * + * @return a {@link NetworkInfo} object for the current default network + * or {@code null} if no network default network is currently active + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * + * {@hide} + */ + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + try { + return mService.getProvisioningOrActiveNetworkInfo(); + } catch (RemoteException e) { + return null; + } + } + /** * Returns the IP information for the current default network. * @@ -1357,63 +1380,19 @@ public class ConnectivityManager { } /** - * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) - */ - - /** - * No connection was possible to the network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; - - /** - * A connection was made to the internet, all is well. - * {@hide} - */ - public static final int CMP_RESULT_CODE_CONNECTABLE = 1; - - /** - * A connection was made but there was a redirection, we appear to be in walled garden. - * This is an indication of a warm sim on a mobile network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_REDIRECTED = 2; - - /** - * A connection was made but no dns server was available to resolve a name to address. - * This is an indication of a warm sim on a mobile network. + * Check mobile provisioning. * - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_DNS = 3; - - /** - * A connection was made but could not open a TCP connection. - * This is an indication of a warm sim on a mobile network. - * {@hide} - */ - public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; - - /** - * Check mobile provisioning. The resultCode passed to - * onReceiveResult will be one of the CMP_RESULT_CODE_xxxx values above. - * This may take a minute or more to complete. - * - * @param sendNotificaiton, when true a notification will be sent to user. * @param suggestedTimeOutMs, timeout in milliseconds - * @param resultReceiver needs to be supplied to receive the result * * @return time out that will be used, maybe less that suggestedTimeOutMs * -1 if an error. * * {@hide} */ - public int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, - ResultReceiver resultReceiver) { + public int checkMobileProvisioning(int suggestedTimeOutMs) { int timeOutMs = -1; try { - timeOutMs = mService.checkMobileProvisioning(sendNotification, suggestedTimeOutMs, - resultReceiver); + timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs); } catch (RemoteException e) { } return timeOutMs; @@ -1481,4 +1460,20 @@ public class ConnectivityManager { return null; } } + + /** + * Set sign in error notification to visible or in visible + * + * @param visible + * @param networkType + * + * {@hide} + */ + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + try { + mService.setProvisioningNotificationVisible(visible, networkType, extraInfo, url); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index bf2dade3bc..c07e900ba2 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -50,6 +50,8 @@ interface IConnectivityManager NetworkInfo getNetworkInfo(int networkType); NetworkInfo[] getAllNetworkInfo(); + NetworkInfo getProvisioningOrActiveNetworkInfo(); + boolean isNetworkSupported(int networkType); LinkProperties getActiveLinkProperties(); @@ -141,7 +143,7 @@ interface IConnectivityManager int findConnectionTypeForIface(in String iface); - int checkMobileProvisioning(boolean sendNotification, int suggestedTimeOutMs, in ResultReceiver resultReceiver); + int checkMobileProvisioning(int suggestedTimeOutMs); String getMobileProvisioningUrl(); @@ -153,4 +155,5 @@ interface IConnectivityManager LinkInfo[] getAllLinkInfo(); + void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 689dae5301..dabc73a716 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -84,6 +84,12 @@ public class NetworkInfo implements Parcelable { VERIFYING_POOR_LINK, /** Checking if network is a captive portal */ CAPTIVE_PORTAL_CHECK, + /** + * Network is connected to provisioning network + * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK + * @hide + */ + CONNECTED_TO_PROVISIONING_NETWORK } /** @@ -108,6 +114,7 @@ public class NetworkInfo implements Parcelable { stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); stateMap.put(DetailedState.FAILED, State.DISCONNECTED); stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); + stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED); } private int mNetworkType; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 136a85e0af..9c146549a1 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -36,6 +36,7 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; import android.bluetooth.BluetoothTetheringDataTracker; +import android.content.ActivityNotFoundException; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -152,6 +153,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; /** @@ -424,9 +426,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; - // We only want one checkMobileProvisioning after booting. - volatile boolean mFirstProvisioningCheckStarted = false; - public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -656,9 +655,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); mSettingsObserver.observe(mContext); - mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); - loadGlobalProxy(); - mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); @@ -686,6 +682,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { new IntentFilter(filter)); mPacManager = new PacManager(mContext); + + filter = new IntentFilter(); + filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + mContext.registerReceiver(mProvisioningReceiver, filter); } /** @@ -954,6 +954,46 @@ public class ConnectivityService extends IConnectivityManager.Stub { return getNetworkInfo(mActiveDefaultNetwork, uid); } + /** + * Find the first Provisioning network. + * + * @return NetworkInfo or null if none. + */ + private NetworkInfo getProvisioningNetworkInfo() { + enforceAccessPermission(); + + // Find the first Provisioning Network + NetworkInfo provNi = null; + for (NetworkInfo ni : getAllNetworkInfo()) { + if (ni.getDetailedState() + == NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + provNi = ni; + break; + } + } + if (DBG) log("getProvisioningNetworkInfo: X provNi=" + provNi); + return provNi; + } + + /** + * Find the first Provisioning network or the ActiveDefaultNetwork + * if there is no Provisioning network + * + * @return NetworkInfo or null if none. + */ + @Override + public NetworkInfo getProvisioningOrActiveNetworkInfo() { + enforceAccessPermission(); + + NetworkInfo provNi = getProvisioningNetworkInfo(); + if (provNi == null) { + final int uid = Binder.getCallingUid(); + provNi = getNetworkInfo(mActiveDefaultNetwork, uid); + } + if (DBG) log("getProvisioningOrActiveNetworkInfo: X provNi=" + provNi); + return provNi; + } + public NetworkInfo getActiveNetworkInfoUnfiltered() { enforceAccessPermission(); if (isNetworkTypeValid(mActiveDefaultNetwork)) { @@ -1316,8 +1356,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { feature); } if (network.reconnect()) { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_STARTED"); return PhoneConstants.APN_REQUEST_STARTED; } else { + if (DBG) log("startUsingNetworkFeature X: return APN_REQUEST_FAILED"); return PhoneConstants.APN_REQUEST_FAILED; } } else { @@ -1329,9 +1371,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetRequestersPids[usedNetworkType].add(currentPid); } } + if (DBG) log("startUsingNetworkFeature X: return -1 unsupported feature."); return -1; } } + if (DBG) log("startUsingNetworkFeature X: return APN_TYPE_NOT_AVAILABLE"); return PhoneConstants.APN_TYPE_NOT_AVAILABLE; } finally { if (DBG) { @@ -1365,11 +1409,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } if (found && u != null) { + if (VDBG) log("stopUsingNetworkFeature: X"); // stop regardless of how many other time this proc had called start return stopUsingNetworkFeature(u, true); } else { // none found! - if (VDBG) log("stopUsingNetworkFeature - not a live request, ignoring"); + if (VDBG) log("stopUsingNetworkFeature: X not a live request, ignoring"); return 1; } } @@ -1952,6 +1997,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ if (mNetConfigs[prevNetType].isDefault()) { if (mActiveDefaultNetwork == prevNetType) { + if (DBG) { + log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType); + } mActiveDefaultNetwork = -1; } @@ -2146,6 +2194,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } void systemReady() { + mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); + loadGlobalProxy(); + synchronized(this) { mSystemReady = true; if (mInitialBroadcast != null) { @@ -2176,10 +2227,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; private boolean isNewNetTypePreferredOverCurrentNetType(int type) { - if ((type != mNetworkPreference && - mNetConfigs[mActiveDefaultNetwork].priority > - mNetConfigs[type].priority) || - mNetworkPreference == mActiveDefaultNetwork) return false; + if (((type != mNetworkPreference) + && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority)) + || (mNetworkPreference == mActiveDefaultNetwork)) { + return false; + } return true; } @@ -2193,6 +2245,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { final NetworkStateTracker thisNet = mNetTrackers[newNetType]; final String thisIface = thisNet.getLinkProperties().getInterfaceName(); + if (VDBG) { + log("handleConnect: E newNetType=" + newNetType + " thisIface=" + thisIface + + " isFailover" + isFailover); + } + // if this is a default net and other default is running // kill the one not preferred if (mNetConfigs[newNetType].isDefault()) { @@ -2355,6 +2412,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleConnectivityChange(int netType, boolean doReset) { int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType); + if (VDBG) { + log("handleConnectivityChange: netType=" + netType + " doReset=" + doReset + + " resetMask=" + resetMask); + } /* * If a non-default network is enabled, add the host routes that @@ -2422,7 +2483,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt); if (resetMask != 0 || resetDns) { + if (VDBG) log("handleConnectivityChange: resetting"); if (curLp != null) { + if (VDBG) log("handleConnectivityChange: resetting curLp=" + curLp); for (String iface : curLp.getAllInterfaceNames()) { if (TextUtils.isEmpty(iface) == false) { if (resetMask != 0) { @@ -2459,6 +2522,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Update 464xlat state. NetworkStateTracker tracker = mNetTrackers[netType]; if (mClat.requiresClat(netType, tracker)) { + // If the connection was previously using clat, but is not using it now, stop the clat // daemon. Normally, this happens automatically when the connection disconnects, but if // the disconnect is not reported, or if the connection's LinkProperties changed for @@ -2512,6 +2576,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { + if (VDBG) log("updateRoutes: default remove route r=" + r); removeRoute(curLp, r, TO_DEFAULT_TABLE); } if (isLinkDefault == false) { @@ -2849,9 +2914,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { - case NetworkStateTracker.EVENT_STATE_CHANGED: + case NetworkStateTracker.EVENT_STATE_CHANGED: { info = (NetworkInfo) msg.obj; - int type = info.getType(); NetworkInfo.State state = info.getState(); if (VDBG || (state == NetworkInfo.State.CONNECTED) || @@ -2861,15 +2925,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { state + "/" + info.getDetailedState()); } - // After booting we'll check once for mobile provisioning - // if we've provisioned by and connected. - if (!mFirstProvisioningCheckStarted + // Since mobile has the notion of a network/apn that can be used for + // provisioning we need to check every time we're connected as + // CaptiveProtalTracker won't detected it because DCT doesn't report it + // as connected as ACTION_ANY_DATA_CONNECTION_STATE_CHANGED instead its + // reported as ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN. Which + // is received by MDST and sent here as EVENT_STATE_CHANGED. + if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) && (state == NetworkInfo.State.CONNECTED)) { - log("check provisioning after booting"); - mFirstProvisioningCheckStarted = true; - checkMobileProvisioning(true, CheckMp.MAX_TIMEOUT_MS, null); + checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } EventLogTags.writeConnectivityStateChanged( @@ -2881,6 +2947,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (info.getDetailedState() == DetailedState.CAPTIVE_PORTAL_CHECK) { handleCaptivePortalTrackerCheck(info); + } else if (info.getDetailedState() == + DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + /** + * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING + * for now its an in between network, its a network that + * is actually a default network but we don't want it to be + * announced as such to keep background applications from + * trying to use it. It turns out that some still try so we + * take the additional step of clearing any default routes + * to the link that may have incorrectly setup by the lower + * levels. + */ + LinkProperties lp = getLinkProperties(info.getType()); + if (DBG) { + log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp); + } + + // Clear any default routes setup by the radio so + // any activity by applications trying to use this + // connection will fail until the provisioning network + // is enabled. + for (RouteInfo r : lp.getRoutes()) { + removeRoute(lp, r, TO_DEFAULT_TABLE); + } } else if (state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) { @@ -2899,18 +2989,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { mLockdownTracker.onNetworkInfoChanged(info); } break; - case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: + } + case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: { info = (NetworkInfo) msg.obj; // TODO: Temporary allowing network configuration // change not resetting sockets. // @see bug/4455071 handleConnectivityChange(info.getType(), false); break; - case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: + } + case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { info = (NetworkInfo) msg.obj; - type = info.getType(); + int type = info.getType(); updateNetworkSettings(mNetTrackers[type]); break; + } } } } @@ -3806,76 +3899,153 @@ public class ConnectivityService extends IConnectivityManager.Stub { enabled)); } + private boolean isMobileDataStateTrackerReady() { + MobileDataStateTracker mdst = + (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + return (mdst != null) && (mdst.isReady()); + } + + /** + * The ResultReceiver resultCode for checkMobileProvisioning (CMP_RESULT_CODE) + */ + + /** + * No connection was possible to the network. + */ + public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; + + /** + * A connection was made to the internet, all is well. + */ + public static final int CMP_RESULT_CODE_CONNECTABLE = 1; + + /** + * A connection was made but there was a redirection, we appear to be in walled garden. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_REDIRECTED = 2; + + /** + * A connection was made but no dns server was available to resolve a name to address. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_NO_DNS = 3; + + /** + * A connection was made but could not open a TCP connection. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; + + /** + * The mobile network is a provisioning network. + * This is an indication of a warm sim on a mobile network. + */ + public static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + + AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); + @Override - public int checkMobileProvisioning(final boolean sendNotification, int suggestedTimeOutMs, - final ResultReceiver resultReceiver) { - log("checkMobileProvisioning: E sendNotification=" + sendNotification - + " suggestedTimeOutMs=" + suggestedTimeOutMs - + " resultReceiver=" + resultReceiver); - enforceChangePermission(); - - mFirstProvisioningCheckStarted = true; - - int timeOutMs = suggestedTimeOutMs; - if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { - timeOutMs = CheckMp.MAX_TIMEOUT_MS; - } - - // Check that mobile networks are supported - if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) - || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { - log("checkMobileProvisioning: X no mobile network"); - if (resultReceiver != null) { - resultReceiver.send(ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION, null); - } - return timeOutMs; - } + public int checkMobileProvisioning(int suggestedTimeOutMs) { + int timeOutMs = -1; + if (DBG) log("checkMobileProvisioning: E suggestedTimeOutMs=" + suggestedTimeOutMs); + enforceConnectivityInternalPermission(); final long token = Binder.clearCallingIdentity(); try { + timeOutMs = suggestedTimeOutMs; + if (suggestedTimeOutMs > CheckMp.MAX_TIMEOUT_MS) { + timeOutMs = CheckMp.MAX_TIMEOUT_MS; + } + + // Check that mobile networks are supported + if (!isNetworkSupported(ConnectivityManager.TYPE_MOBILE) + || !isNetworkSupported(ConnectivityManager.TYPE_MOBILE_HIPRI)) { + if (DBG) log("checkMobileProvisioning: X no mobile network"); + return timeOutMs; + } + + // If we're already checking don't do it again + // TODO: Add a queue of results... + if (mIsCheckingMobileProvisioning.getAndSet(true)) { + if (DBG) log("checkMobileProvisioning: X already checking ignore for the moment"); + return timeOutMs; + } + + // Start off with notification off + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // See if we've alreadying determined if we've got a provsioning connection + // if so we don't need to do anything active + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + + if (isDefaultProvisioning || isHipriProvisioning) { + if (mIsNotificationVisible) { + if (DBG) { + log("checkMobileProvisioning: provisioning-ignore notification is visible"); + } + } else { + NetworkInfo ni = null; + if (isDefaultProvisioning) { + ni = mdstDefault.getNetworkInfo(); + } + if (isHipriProvisioning) { + ni = mdstHipri.getNetworkInfo(); + } + String url = getMobileProvisioningUrl(); + if ((ni != null) && (!TextUtils.isEmpty(url))) { + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); + } else { + if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); + } + } + mIsCheckingMobileProvisioning.set(false); + return timeOutMs; + } + CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override void onComplete(Integer result) { - log("CheckMp.onComplete: result=" + result); - if (resultReceiver != null) { - log("CheckMp.onComplete: send result"); - resultReceiver.send(result, null); - } - if (!sendNotification) { - log("CheckMp.onComplete: done, not sending notification"); - return; - } + if (DBG) log("CheckMp.onComplete: result=" + result); NetworkInfo ni = mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { - case ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE: - case ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION: { - log("CheckMp.onComplete: ignore, connected or no connection"); + case CMP_RESULT_CODE_CONNECTABLE: + case CMP_RESULT_CODE_NO_CONNECTION: { + if (DBG) log("CheckMp.onComplete: ignore, connected or no connection"); break; } - case ConnectivityManager.CMP_RESULT_CODE_REDIRECTED: { - log("CheckMp.onComplete: warm sim"); + case CMP_RESULT_CODE_REDIRECTED: { + if (DBG) log("CheckMp.onComplete: warm sim"); String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url)) { url = getMobileRedirectedProvisioningUrl(); } if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (redirected), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (redirected), no url"); + if (DBG) log("CheckMp.onComplete: warm (redirected), no url"); } break; } - case ConnectivityManager.CMP_RESULT_CODE_NO_DNS: - case ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION: { + case CMP_RESULT_CODE_NO_DNS: + case CMP_RESULT_CODE_NO_TCP_CONNECTION: { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { - log("CheckMp.onComplete: warm sim (no dns/tcp), url=" + url); - setNotificationVisible(true, ni, url); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); + setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + url); } else { - log("CheckMp.onComplete: warm sim (no dns/tcp), no url"); + if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); } break; } @@ -3884,16 +4054,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } } + mIsCheckingMobileProvisioning.set(false); } }; CheckMp.Params params = new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); - log("checkMobileProvisioning: params=" + params); - setNotificationVisible(false, null, null); + if (DBG) log("checkMobileProvisioning: params=" + params); checkMp.execute(params); } finally { Binder.restoreCallingIdentity(token); - log("checkMobileProvisioning: X"); + if (DBG) log("checkMobileProvisioning: X"); } return timeOutMs; } @@ -3965,26 +4135,38 @@ public class ConnectivityService extends IConnectivityManager.Stub { * a known address that fetches the data we expect. */ private synchronized Integer isMobileOk(Params params) { - Integer result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + Integer result = CMP_RESULT_CODE_NO_CONNECTION; Uri orgUri = Uri.parse(params.mUrl); Random rand = new Random(); mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { log("isMobileOk: not mobile capable"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; return result; } try { - // Enable fail fast as we'll do retries here and use a - // hipri connection so the default connection stays active. - log("isMobileOk: start hipri url=" + params.mUrl); - mCs.setEnableFailFastMobileData(DctConstants.ENABLED); - // Continue trying to connect until time has run out long endTime = SystemClock.elapsedRealtime() + params.mTimeOutMs; + if (!mCs.isMobileDataStateTrackerReady()) { + // Wait for MobileDataStateTracker to be ready. + if (DBG) log("isMobileOk: mdst is not ready"); + while(SystemClock.elapsedRealtime() < endTime) { + if (mCs.isMobileDataStateTrackerReady()) { + // Enable fail fast as we'll do retries here and use a + // hipri connection so the default connection stays active. + if (DBG) log("isMobileOk: mdst ready, enable fail fast of mobile data"); + mCs.setEnableFailFastMobileData(DctConstants.ENABLED); + break; + } + sleep(1); + } + } + + log("isMobileOk: start hipri url=" + params.mUrl); + // First wait until we can start using hipri Binder binder = new Binder(); while(SystemClock.elapsedRealtime() < endTime) { @@ -3996,7 +4178,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } if (VDBG) log("isMobileOk: hipri not started yet"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; sleep(1); } @@ -4009,15 +4191,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = mCs .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); if (state != NetworkInfo.State.CONNECTED) { - if (VDBG) { + if (true/*VDBG*/) { log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } sleep(1); - result = ConnectivityManager.CMP_RESULT_CODE_NO_CONNECTION; + result = CMP_RESULT_CODE_NO_CONNECTION; continue; } + // Hipri has started check if this is a provisioning url + MobileDataStateTracker mdst = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + if (mdst.isProvisioningNetwork()) { + if (DBG) log("isMobileOk: isProvisioningNetwork is true, no TCP conn"); + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; + return result; + } else { + if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); + } + // Get of the addresses associated with the url host. We need to use the // address otherwise HttpURLConnection object will use the name to get // the addresses and is will try every address but that will bypass the @@ -4028,7 +4221,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { log("isMobileOk: UnknownHostException"); - result = ConnectivityManager.CMP_RESULT_CODE_NO_DNS; + result = CMP_RESULT_CODE_NO_DNS; return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -4093,9 +4286,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); if (responseCode == 204) { - result = ConnectivityManager.CMP_RESULT_CODE_CONNECTABLE; + result = CMP_RESULT_CODE_CONNECTABLE; } else { - result = ConnectivityManager.CMP_RESULT_CODE_REDIRECTED; + result = CMP_RESULT_CODE_REDIRECTED; } log("isMobileOk: connected responseCode=" + responseCode); urlConn.disconnect(); @@ -4109,7 +4302,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - result = ConnectivityManager.CMP_RESULT_CODE_NO_TCP_CONNECTION; + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; log("isMobileOk: loops|timed out"); return result; } catch (Exception e) { @@ -4123,6 +4316,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCs.setEnableFailFastMobileData(DctConstants.DISABLED); mCs.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE, Phone.FEATURE_ENABLE_HIPRI); + + // Wait for hipri to disconnect. + long endTime = SystemClock.elapsedRealtime() + 5000; + + while(SystemClock.elapsedRealtime() < endTime) { + NetworkInfo.State state = mCs + .getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI).getState(); + if (state != NetworkInfo.State.DISCONNECTED) { + if (VDBG) { + log("isMobileOk: connected ni=" + + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); + } + sleep(1); + continue; + } + } + log("isMobileOk: X result=" + result); } return result; @@ -4188,10 +4398,55 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + // TODO: Move to ConnectivityManager and make public? + private static final String CONNECTED_TO_PROVISIONING_NETWORK_ACTION = + "com.android.server.connectivityservice.CONNECTED_TO_PROVISIONING_NETWORK_ACTION"; - private void setNotificationVisible(boolean visible, NetworkInfo networkInfo, String url) { - log("setNotificationVisible: E visible=" + visible + " ni=" + networkInfo + " url=" + url); + private BroadcastReceiver mProvisioningReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(CONNECTED_TO_PROVISIONING_NETWORK_ACTION)) { + handleMobileProvisioningAction(intent.getStringExtra("EXTRA_URL")); + } + } + }; + + private void handleMobileProvisioningAction(String url) { + // Notication mark notification as not visible + setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + + // If provisioning network handle as a special case, + // otherwise launch browser with the intent directly. + NetworkInfo ni = getProvisioningNetworkInfo(); + if ((ni != null) && ni.getDetailedState() == + NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if (DBG) log("handleMobileProvisioningAction: on provisioning network"); + MobileDataStateTracker mdst = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.enableMobileProvisioning(url); + } else { + if (DBG) log("handleMobileProvisioningAction: on default network"); + Intent newIntent = + new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(newIntent); + } catch (ActivityNotFoundException e) { + loge("handleMobileProvisioningAction: startActivity failed" + e); + } + } + } + + private static final String NOTIFICATION_ID = "CaptivePortal.Notification"; + private volatile boolean mIsNotificationVisible = false; + + private void setProvNotificationVisible(boolean visible, int networkType, String extraInfo, + String url) { + if (DBG) { + log("setProvNotificationVisible: E visible=" + visible + " networkType=" + networkType + + " extraInfo=" + extraInfo + " url=" + url); + } Resources r = Resources.getSystem(); NotificationManager notificationManager = (NotificationManager) mContext @@ -4201,50 +4456,64 @@ public class ConnectivityService extends IConnectivityManager.Stub { CharSequence title; CharSequence details; int icon; - switch (networkInfo.getType()) { + Intent intent; + Notification notification = new Notification(); + switch (networkType) { case ConnectivityManager.TYPE_WIFI: - log("setNotificationVisible: TYPE_WIFI"); title = r.getString(R.string.wifi_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_wifi_in_range; + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); break; case ConnectivityManager.TYPE_MOBILE: case ConnectivityManager.TYPE_MOBILE_HIPRI: - log("setNotificationVisible: TYPE_MOBILE|HIPRI"); title = r.getString(R.string.network_available_sign_in, 0); // TODO: Change this to pull from NetworkInfo once a printable // name has been added to it details = mTelephonyManager.getNetworkOperatorName(); icon = R.drawable.stat_notify_rssi_in_range; + intent = new Intent(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); + intent.putExtra("EXTRA_URL", url); + intent.setFlags(0); + notification.contentIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); break; default: - log("setNotificationVisible: other type=" + networkInfo.getType()); title = r.getString(R.string.network_available_sign_in, 0); details = r.getString(R.string.network_available_sign_in_detailed, - networkInfo.getExtraInfo()); + extraInfo); icon = R.drawable.stat_notify_rssi_in_range; + intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); break; } - Notification notification = new Notification(); notification.when = 0; notification.icon = icon; notification.flags = Notification.FLAG_AUTO_CANCEL; - Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); - intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | - Intent.FLAG_ACTIVITY_NEW_TASK); - notification.contentIntent = PendingIntent.getActivity(mContext, 0, intent, 0); notification.tickerText = title; notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); - log("setNotificaitionVisible: notify notificaiton=" + notification); - notificationManager.notify(NOTIFICATION_ID, 1, notification); + try { + notificationManager.notify(NOTIFICATION_ID, 1, notification); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: visible notificationManager npe=" + npe); + npe.printStackTrace(); + } } else { - log("setNotificaitionVisible: cancel"); - notificationManager.cancel(NOTIFICATION_ID, 1); + try { + notificationManager.cancel(NOTIFICATION_ID, 1); + } catch (NullPointerException npe) { + loge("setNotificaitionVisible: cancel notificationManager npe=" + npe); + npe.printStackTrace(); + } } - log("setNotificationVisible: X visible=" + visible + " ni=" + networkInfo + " url=" + url); + mIsNotificationVisible = visible; } /** Location to an updatable file listing carrier provisioning urls. @@ -4373,6 +4642,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { return url; } + @Override + public void setProvisioningNotificationVisible(boolean visible, int networkType, + String extraInfo, String url) { + enforceConnectivityInternalPermission(); + setProvNotificationVisible(visible, networkType, extraInfo, url); + } + private void onUserStart(int userId) { synchronized(mVpns) { Vpn userVpn = mVpns.get(userId); From 00d4b8a98723f0e1ed5cebe5292e48666f8da3af Mon Sep 17 00:00:00 2001 From: Vinit Deshapnde Date: Wed, 4 Sep 2013 14:11:24 -0700 Subject: [PATCH 132/296] Rename LinkInfo to LinkQualityInfo This change renames the LinkInfo objects to LinkQuailtyInfo. The API is still hidden; but it can be accessed via reflection. Bug: 10342372 Change-Id: Ieccea87c467ceae5d7f76298b137573f67396cd6 --- core/java/android/net/ConnectivityManager.java | 12 ++++++------ .../java/android/net/IConnectivityManager.aidl | 8 ++++---- .../android/server/ConnectivityService.java | 18 +++++++++--------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index f6a3a4a772..c3ff857240 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1447,9 +1447,9 @@ public class ConnectivityManager { * get the information about a specific network link * @hide */ - public LinkInfo getLinkInfo(int networkType) { + public LinkQualityInfo getLinkQualityInfo(int networkType) { try { - LinkInfo li = mService.getLinkInfo(networkType); + LinkQualityInfo li = mService.getLinkQualityInfo(networkType); return li; } catch (RemoteException e) { return null; @@ -1460,9 +1460,9 @@ public class ConnectivityManager { * get the information of currently active network link * @hide */ - public LinkInfo getActiveLinkInfo() { + public LinkQualityInfo getActiveLinkQualityInfo() { try { - LinkInfo li = mService.getActiveLinkInfo(); + LinkQualityInfo li = mService.getActiveLinkQualityInfo(); return li; } catch (RemoteException e) { return null; @@ -1473,9 +1473,9 @@ public class ConnectivityManager { * get the information of all network links * @hide */ - public LinkInfo[] getAllLinkInfo() { + public LinkQualityInfo[] getAllLinkQualityInfo() { try { - LinkInfo[] li = mService.getAllLinkInfo(); + LinkQualityInfo[] li = mService.getAllLinkQualityInfo(); return li; } catch (RemoteException e) { return null; diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index bf2dade3bc..1c383146b1 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -16,7 +16,7 @@ package android.net; -import android.net.LinkInfo; +import android.net.LinkQualityInfo; import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; @@ -147,10 +147,10 @@ interface IConnectivityManager String getMobileRedirectedProvisioningUrl(); - LinkInfo getLinkInfo(int networkType); + LinkQualityInfo getLinkQualityInfo(int networkType); - LinkInfo getActiveLinkInfo(); + LinkQualityInfo getActiveLinkQualityInfo(); - LinkInfo[] getAllLinkInfo(); + LinkQualityInfo[] getAllLinkQualityInfo(); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 136a85e0af..c3fa41712b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -57,7 +57,7 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.LinkInfo; +import android.net.LinkQualityInfo; import android.net.LinkProperties.CompareResult; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; @@ -4413,39 +4413,39 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; @Override - public LinkInfo getLinkInfo(int networkType) { + public LinkQualityInfo getLinkQualityInfo(int networkType) { enforceAccessPermission(); if (isNetworkTypeValid(networkType)) { - return mNetTrackers[networkType].getLinkInfo(); + return mNetTrackers[networkType].getLinkQualityInfo(); } else { return null; } } @Override - public LinkInfo getActiveLinkInfo() { + public LinkQualityInfo getActiveLinkQualityInfo() { enforceAccessPermission(); if (isNetworkTypeValid(mActiveDefaultNetwork)) { - return mNetTrackers[mActiveDefaultNetwork].getLinkInfo(); + return mNetTrackers[mActiveDefaultNetwork].getLinkQualityInfo(); } else { return null; } } @Override - public LinkInfo[] getAllLinkInfo() { + public LinkQualityInfo[] getAllLinkQualityInfo() { enforceAccessPermission(); - final ArrayList result = Lists.newArrayList(); + final ArrayList result = Lists.newArrayList(); for (NetworkStateTracker tracker : mNetTrackers) { if (tracker != null) { - LinkInfo li = tracker.getLinkInfo(); + LinkQualityInfo li = tracker.getLinkQualityInfo(); if (li != null) { result.add(li); } } } - return result.toArray(new LinkInfo[result.size()]); + return result.toArray(new LinkQualityInfo[result.size()]); } /* Infrastructure for network sampling */ From 174782b0fccf5685f8ed0fb93305cf623e508518 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 23 Aug 2013 20:54:49 +0900 Subject: [PATCH 133/296] Add a function to replace all the link addresses. Bug: 10232006 Change-Id: I689ce4735999dac2ab5e1fae09d80b1f734292a1 --- core/java/android/net/LinkProperties.java | 10 ++++++++++ .../src/android/net/LinkPropertiesTest.java | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 1f73c4ad71..43d6b71598 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -197,6 +197,16 @@ public class LinkProperties implements Parcelable { return addresses; } + /** + * Replaces the LinkAddresses on this link with the given collection of addresses. + */ + public void setLinkAddresses(Collection addresses) { + mLinkAddresses.clear(); + for (LinkAddress address: addresses) { + addLinkAddress(address); + } + } + public void addDns(InetAddress dns) { if (dns != null) mDnses.add(dns); } diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index a570802d29..7e70c6b046 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -363,4 +363,19 @@ public class LinkPropertiesTest extends TestCase { assertFalse(lp.hasIPv4Address()); assertFalse(lp.removeLinkAddress(LINKADDRV4)); } + + @SmallTest + public void testSetLinkAddresses() { + LinkProperties lp = new LinkProperties(); + lp.addLinkAddress(LINKADDRV4); + lp.addLinkAddress(LINKADDRV6); + + LinkProperties lp2 = new LinkProperties(); + lp2.addLinkAddress(LINKADDRV6); + + assertFalse(lp.equals(lp2)); + + lp2.setLinkAddresses(lp.getLinkAddresses()); + assertTrue(lp.equals(lp)); + } } From b1a3202e79f1e13f6b4ddd43155e71cbf4a61dd9 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 5 Sep 2013 12:02:25 -0700 Subject: [PATCH 134/296] Do not change NetworkInfo.DetailedState. I'd changed DetailedState to force ConnectivityService to treat provisioning apn's specially. In particular so that they wouldn't be identified they were fully connected until the provisioning actually started. The problem is that DetailedState is a public enum that has a CTS test and just changing the CTS to allow for the new state (CONNECTED_TO_PROVISIONING_NETWORK) was inappropriate. Instead I've added a new mIsConnectedToProvisioningNetwork variable and used the DetailedState.SUSPENDED as the intermediate state. Bug: 10620248 Change-Id: Id4a842398cad67455541ce629959351c27d83639 --- core/java/android/net/NetworkInfo.java | 35 ++++++++++++++----- .../android/server/ConnectivityService.java | 15 ++++---- 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index dabc73a716..4d2a70ddf1 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -83,13 +83,7 @@ public class NetworkInfo implements Parcelable { /** Link has poor connectivity. */ VERIFYING_POOR_LINK, /** Checking if network is a captive portal */ - CAPTIVE_PORTAL_CHECK, - /** - * Network is connected to provisioning network - * TODO: Probably not needed when we add TYPE_PROVISIONING_NETWORK - * @hide - */ - CONNECTED_TO_PROVISIONING_NETWORK + CAPTIVE_PORTAL_CHECK } /** @@ -114,7 +108,6 @@ public class NetworkInfo implements Parcelable { stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); stateMap.put(DetailedState.FAILED, State.DISCONNECTED); stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); - stateMap.put(DetailedState.CONNECTED_TO_PROVISIONING_NETWORK, State.CONNECTED); } private int mNetworkType; @@ -127,6 +120,8 @@ public class NetworkInfo implements Parcelable { private String mExtraInfo; private boolean mIsFailover; private boolean mIsRoaming; + private boolean mIsConnectedToProvisioningNetwork; + /** * Indicates whether network connectivity is possible: */ @@ -155,6 +150,7 @@ public class NetworkInfo implements Parcelable { mState = State.UNKNOWN; mIsAvailable = false; // until we're told otherwise, assume unavailable mIsRoaming = false; + mIsConnectedToProvisioningNetwork = false; } /** {@hide} */ @@ -171,6 +167,7 @@ public class NetworkInfo implements Parcelable { mIsFailover = source.mIsFailover; mIsRoaming = source.mIsRoaming; mIsAvailable = source.mIsAvailable; + mIsConnectedToProvisioningNetwork = source.mIsConnectedToProvisioningNetwork; } } @@ -329,6 +326,22 @@ public class NetworkInfo implements Parcelable { } } + /** {@hide} */ + @VisibleForTesting + public boolean isConnectedToProvisioningNetwork() { + synchronized (this) { + return mIsConnectedToProvisioningNetwork; + } + } + + /** {@hide} */ + @VisibleForTesting + public void setIsConnectedToProvisioningNetwork(boolean val) { + synchronized (this) { + mIsConnectedToProvisioningNetwork = val; + } + } + /** * Reports the current coarse-grained state of the network. * @return the coarse-grained state @@ -412,7 +425,9 @@ public class NetworkInfo implements Parcelable { append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo). append(", roaming: ").append(mIsRoaming). append(", failover: ").append(mIsFailover). - append(", isAvailable: ").append(mIsAvailable); + append(", isAvailable: ").append(mIsAvailable). + append(", isConnectedToProvisioningNetwork: "). + append(mIsConnectedToProvisioningNetwork); return builder.toString(); } } @@ -440,6 +455,7 @@ public class NetworkInfo implements Parcelable { dest.writeInt(mIsFailover ? 1 : 0); dest.writeInt(mIsAvailable ? 1 : 0); dest.writeInt(mIsRoaming ? 1 : 0); + dest.writeInt(mIsConnectedToProvisioningNetwork ? 1 : 0); dest.writeString(mReason); dest.writeString(mExtraInfo); } @@ -462,6 +478,7 @@ public class NetworkInfo implements Parcelable { netInfo.mIsFailover = in.readInt() != 0; netInfo.mIsAvailable = in.readInt() != 0; netInfo.mIsRoaming = in.readInt() != 0; + netInfo.mIsConnectedToProvisioningNetwork = in.readInt() != 0; netInfo.mReason = in.readString(); netInfo.mExtraInfo = in.readString(); return netInfo; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index ee23b13d3f..a022fb1d87 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -890,8 +890,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Find the first Provisioning Network NetworkInfo provNi = null; for (NetworkInfo ni : getAllNetworkInfo()) { - if (ni.getDetailedState() - == NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if (ni.isConnectedToProvisioningNetwork()) { provNi = ni; break; } @@ -2805,7 +2804,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo.State state = info.getState(); if (VDBG || (state == NetworkInfo.State.CONNECTED) || - (state == NetworkInfo.State.DISCONNECTED)) { + (state == NetworkInfo.State.DISCONNECTED) || + (state == NetworkInfo.State.SUSPENDED)) { log("ConnectivityChange for " + info.getTypeName() + ": " + state + "/" + info.getDetailedState()); @@ -2820,7 +2820,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) - && (state == NetworkInfo.State.CONNECTED)) { + && ((state == NetworkInfo.State.CONNECTED) + || info.isConnectedToProvisioningNetwork())) { checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } @@ -2833,8 +2834,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (info.getDetailedState() == DetailedState.CAPTIVE_PORTAL_CHECK) { handleCaptivePortalTrackerCheck(info); - } else if (info.getDetailedState() == - DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + } else if (info.isConnectedToProvisioningNetwork()) { /** * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING * for now its an in between network, its a network that @@ -4197,8 +4197,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // If provisioning network handle as a special case, // otherwise launch browser with the intent directly. NetworkInfo ni = getProvisioningNetworkInfo(); - if ((ni != null) && ni.getDetailedState() == - NetworkInfo.DetailedState.CONNECTED_TO_PROVISIONING_NETWORK) { + if ((ni != null) && ni.isConnectedToProvisioningNetwork()) { if (DBG) log("handleMobileProvisioningAction: on provisioning network"); MobileDataStateTracker mdst = (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; From 9685cd1d1759b418f8adf6c89c1d7f848b1334cc Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 6 Sep 2013 09:53:08 -0700 Subject: [PATCH 135/296] Tighten test for warm sim and add more debug. - Require a non-204 response multiple times before declaring a redirected error and hence a warm sim. - If there is no connection or dns don't declare its a warm-sim. - Add printing of the http headers to try to get more information if we still get a false positive result. Bug: 9972012 Change-Id: Ic115685cdbbe39c2b4de88b128eaf8d2ea96b45c --- .../android/server/ConnectivityService.java | 73 +++++++++++-------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 7f9dc26fe3..759dce79cf 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3911,39 +3911,41 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * No connection was possible to the network. + * This is NOT a warm sim. */ - public static final int CMP_RESULT_CODE_NO_CONNECTION = 0; + private static final int CMP_RESULT_CODE_NO_CONNECTION = 0; /** * A connection was made to the internet, all is well. + * This is NOT a warm sim. */ - public static final int CMP_RESULT_CODE_CONNECTABLE = 1; - - /** - * A connection was made but there was a redirection, we appear to be in walled garden. - * This is an indication of a warm sim on a mobile network. - */ - public static final int CMP_RESULT_CODE_REDIRECTED = 2; + private static final int CMP_RESULT_CODE_CONNECTABLE = 1; /** * A connection was made but no dns server was available to resolve a name to address. - * This is an indication of a warm sim on a mobile network. + * This is NOT a warm sim since provisioning network is supported. */ - public static final int CMP_RESULT_CODE_NO_DNS = 3; + private static final int CMP_RESULT_CODE_NO_DNS = 2; /** * A connection was made but could not open a TCP connection. - * This is an indication of a warm sim on a mobile network. + * This is NOT a warm sim since provisioning network is supported. */ - public static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 4; + private static final int CMP_RESULT_CODE_NO_TCP_CONNECTION = 3; + + /** + * A connection was made but there was a redirection, we appear to be in walled garden. + * This is an indication of a warm sim on a mobile network such as T-Mobile. + */ + private static final int CMP_RESULT_CODE_REDIRECTED = 4; /** * The mobile network is a provisioning network. - * This is an indication of a warm sim on a mobile network. + * This is an indication of a warm sim on a mobile network such as AT&T. */ - public static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + private static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; - AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); + private AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); @Override public int checkMobileProvisioning(int suggestedTimeOutMs) { @@ -4018,7 +4020,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); switch(result) { case CMP_RESULT_CODE_CONNECTABLE: - case CMP_RESULT_CODE_NO_CONNECTION: { + case CMP_RESULT_CODE_NO_CONNECTION: + case CMP_RESULT_CODE_NO_DNS: + case CMP_RESULT_CODE_NO_TCP_CONNECTION: { if (DBG) log("CheckMp.onComplete: ignore, connected or no connection"); break; } @@ -4037,8 +4041,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } break; } - case CMP_RESULT_CODE_NO_DNS: - case CMP_RESULT_CODE_NO_TCP_CONNECTION: { + case CMP_RESULT_CODE_PROVISIONING_NETWORK: { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); @@ -4204,8 +4207,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { MobileDataStateTracker mdst = (MobileDataStateTracker) mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; if (mdst.isProvisioningNetwork()) { - if (DBG) log("isMobileOk: isProvisioningNetwork is true, no TCP conn"); - result = CMP_RESULT_CODE_NO_TCP_CONNECTION; + if (DBG) log("isMobileOk: isProvisioningNetwork is true"); + result = CMP_RESULT_CODE_PROVISIONING_NETWORK; return result; } else { if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); @@ -4285,25 +4288,37 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setAllowUserInteraction(false); urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); - if (responseCode == 204) { - result = CMP_RESULT_CODE_CONNECTABLE; - } else { - result = CMP_RESULT_CODE_REDIRECTED; - } - log("isMobileOk: connected responseCode=" + responseCode); + + // For debug display the headers + Map> headers = urlConn.getHeaderFields(); + log("isMobileOk: headers=" + headers); + + // Close the connection urlConn.disconnect(); urlConn = null; - return result; + + if (responseCode == 204) { + // Return + log("isMobileOk: expected responseCode=" + responseCode); + result = CMP_RESULT_CODE_CONNECTABLE; + return result; + } else { + // Retry to be sure this was redirected, we've gotten + // occasions where a server returned 200 even though + // the device didn't have a "warm" sim. + log("isMobileOk: not expected responseCode=" + responseCode); + result = CMP_RESULT_CODE_REDIRECTED; + } } catch (Exception e) { log("isMobileOk: HttpURLConnection Exception e=" + e); + result = CMP_RESULT_CODE_NO_TCP_CONNECTION; if (urlConn != null) { urlConn.disconnect(); urlConn = null; } } } - result = CMP_RESULT_CODE_NO_TCP_CONNECTION; - log("isMobileOk: loops|timed out"); + log("isMobileOk: loops|timed out result=" + result); return result; } catch (Exception e) { log("isMobileOk: Exception e=" + e); From 4aa73924fd6e3770bc463648e7860d7387fda96d Mon Sep 17 00:00:00 2001 From: "sy.yun" Date: Mon, 2 Sep 2013 05:24:09 +0900 Subject: [PATCH 136/296] Setting MTU size for specific network. Able to config network specific MTU size. Normally, the default size of MTU is 1500. US - ATT 1410, TMUS 1440, SPRINT 1422 KR - SKT 1440, KT 1450, LGU+ 1428 JP - KDDI 1420, SoftBank 1340 CA - RGS 1430, FIDO 1430, MTS 1430, BELL 1358, SaskTel 1358 AU - TEL 1400 Bug: 10195070 Change-Id: Ie18650b37a3d44af944f2dae4aa97c04fb12cd5e --- core/java/android/net/LinkProperties.java | 35 ++++++++++++++++--- .../src/android/net/LinkPropertiesTest.java | 24 +++++++++++++ .../android/server/ConnectivityService.java | 22 +++++++++++- 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 43d6b71598..284e1a7f28 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -66,6 +66,7 @@ public class LinkProperties implements Parcelable { private String mDomains; private Collection mRoutes = new ArrayList(); private ProxyProperties mHttpProxy; + private int mMtu; // Stores the properties of links that are "stacked" above this link. // Indexed by interface name to allow modification and to prevent duplicates being added. @@ -104,6 +105,7 @@ public class LinkProperties implements Parcelable { for (LinkProperties l: source.mStackedLinks.values()) { addStackedLink(l); } + setMtu(source.getMtu()); } } @@ -223,6 +225,14 @@ public class LinkProperties implements Parcelable { mDomains = domains; } + public void setMtu(int mtu) { + mMtu = mtu; + } + + public int getMtu() { + return mMtu; + } + private RouteInfo routeWithInterface(RouteInfo route) { return new RouteInfo( route.getDestination(), @@ -322,6 +332,7 @@ public class LinkProperties implements Parcelable { mRoutes.clear(); mHttpProxy = null; mStackedLinks.clear(); + mMtu = 0; } /** @@ -346,6 +357,8 @@ public class LinkProperties implements Parcelable { String domainName = "Domains: " + mDomains; + String mtu = "MTU: " + mMtu; + String routes = " Routes: ["; for (RouteInfo route : mRoutes) routes += route.toString() + ","; routes += "] "; @@ -359,7 +372,8 @@ public class LinkProperties implements Parcelable { } stacked += "] "; } - return "{" + ifaceName + linkAddresses + routes + dns + domainName + proxy + stacked + "}"; + return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu + + proxy + stacked + "}"; } /** @@ -474,6 +488,16 @@ public class LinkProperties implements Parcelable { return true; } + /** + * Compares this {@code LinkProperties} MTU against the target + * + * @@param target LinkProperties to compare. + * @return {@code true} if both are identical, {@code false} otherwise. + */ + public boolean isIdenticalMtu(LinkProperties target) { + return getMtu() == target.getMtu(); + } + @Override /** * Compares this {@code LinkProperties} instance against the target @@ -505,7 +529,8 @@ public class LinkProperties implements Parcelable { isIdenticalDnses(target) && isIdenticalRoutes(target) && isIdenticalHttpProxy(target) && - isIdenticalStackedLinks(target); + isIdenticalStackedLinks(target) && + isIdenticalMtu(target); } /** @@ -607,7 +632,8 @@ public class LinkProperties implements Parcelable { + ((null == mDomains) ? 0 : mDomains.hashCode()) + mRoutes.size() * 41 + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()) - + mStackedLinks.hashCode() * 47); + + mStackedLinks.hashCode() * 47) + + mMtu * 51; } /** @@ -625,7 +651,7 @@ public class LinkProperties implements Parcelable { dest.writeByteArray(d.getAddress()); } dest.writeString(mDomains); - + dest.writeInt(mMtu); dest.writeInt(mRoutes.size()); for(RouteInfo route : mRoutes) { dest.writeParcelable(route, flags); @@ -664,6 +690,7 @@ public class LinkProperties implements Parcelable { } catch (UnknownHostException e) { } } netProp.setDomains(in.readString()); + netProp.setMtu(in.readInt()); addressCount = in.readInt(); for (int i=0; i 10000) { + loge("Unexpected mtu value: " + nt); + return; + } + + try { + if (VDBG) log("Setting MTU size: " + iface + ", " + mtu); + mNetd.setMtu(iface, mtu); + } catch (Exception e) { + Slog.e(TAG, "exception in setMtu()" + e); + } + } /** * Reads the network specific TCP buffer sizes from SystemProperties @@ -4774,4 +4795,3 @@ public class ConnectivityService extends IConnectivityManager.Stub { mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent); } } - From 39dd04c648ee81333a53133255dc62228db94ee9 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 6 Sep 2013 16:49:37 -0700 Subject: [PATCH 137/296] Fix the build. Change-Id: Ia5d29de9db7ea8fd467b3bde551a8cfb95877b41 --- core/tests/coretests/src/android/net/LinkPropertiesTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index 63dd86f997..e63f6b08f6 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -163,8 +163,8 @@ public class LinkPropertiesTest extends TestCase { target.addLinkAddress(LINKADDRV6); target.addDns(DNS1); target.addDns(DNS2); - target.addRoute(GATEWAY1); - target.addRoute(GATEWAY2); + target.addRoute(new RouteInfo(GATEWAY1)); + target.addRoute(new RouteInfo(GATEWAY2)); // change mtu target.setMtu(1440); assertFalse(source.equals(target)); From cb5620b2c4c99f75da6fbcea3c753f8d85a64381 Mon Sep 17 00:00:00 2001 From: Ying Wang Date: Fri, 6 Sep 2013 22:53:16 -0700 Subject: [PATCH 138/296] Fix docs build. Change-Id: I6fd0d711b2cc7726fdaa9119ee467ed6fab82de1 --- core/java/android/net/LinkProperties.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 284e1a7f28..b4d07a1ec2 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -491,7 +491,7 @@ public class LinkProperties implements Parcelable { /** * Compares this {@code LinkProperties} MTU against the target * - * @@param target LinkProperties to compare. + * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. */ public boolean isIdenticalMtu(LinkProperties target) { From b77f15d90b2f99f65cd6b31b18584954eb834e5c Mon Sep 17 00:00:00 2001 From: Yuhao Zheng Date: Mon, 9 Sep 2013 17:00:04 -0700 Subject: [PATCH 139/296] Add a hidden API to toggle airplane mode. Added a hidden API under ConnectivityManager to toggle airplane mode. This may be a temp solution for b/10653570. bug:10653570 Change-Id: I0b2b42230073289eb8dc6891317d62b84e26c133 --- core/java/android/net/ConnectivityManager.java | 16 ++++++++++++++++ core/java/android/net/IConnectivityManager.aidl | 2 ++ .../com/android/server/ConnectivityService.java | 15 +++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4cf38b6b39..c78a973cee 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1476,4 +1476,20 @@ public class ConnectivityManager { } catch (RemoteException e) { } } + + /** + * Set the value for enabling/disabling airplane mode + * + * @param enable whether to enable airplane mode or not + * + *

This method requires the call to hold the permission + * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * @hide + */ + public void setAirplaneMode(boolean enable) { + try { + mService.setAirplaneMode(enable); + } catch (RemoteException e) { + } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index a6f10ecbe4..b3fa79fc50 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -156,4 +156,6 @@ interface IConnectivityManager LinkQualityInfo[] getAllLinkQualityInfo(); void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); + + void setAirplaneMode(boolean enable); } diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 02a78dea33..4e3faca51a 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4681,6 +4681,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { setProvNotificationVisible(visible, networkType, extraInfo, url); } + @Override + public void setAirplaneMode(boolean enable) { + enforceConnectivityInternalPermission(); + final ContentResolver cr = mContext.getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", enable); + final long ident = Binder.clearCallingIdentity(); + try { + mContext.sendBroadcast(intent); + } finally { + Binder.restoreCallingIdentity(ident); + } + } + private void onUserStart(int userId) { synchronized(mVpns) { Vpn userVpn = mVpns.get(userId); From 168cd72f764254d79cc0b716235408f79bf0302e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 10 Sep 2013 21:03:27 -0700 Subject: [PATCH 140/296] Request all tethering interfaces, fix corruption. netd now tracks statistics for tethered interfaces across tethering sessions, so switch to asking for all tethering stats. (Currently we're double-counting all tethering data, ever since it started tracking across sessions.) Also catch OOME to handle corrupt stats files, which we then dump to DropBox and then start over. Bug: 5868832, 9796109 Change-Id: I2eb2a1bf01b993dd198597d770fe0e022466c6b9 --- core/java/android/net/IConnectivityManager.aidl | 6 ------ .../java/com/android/server/ConnectivityService.java | 10 +--------- .../com/android/server/NetworkStatsServiceTest.java | 8 +++----- 3 files changed, 4 insertions(+), 20 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index a6f10ecbe4..826f90ce42 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -93,12 +93,6 @@ interface IConnectivityManager String[] getTetheredIfaces(); - /** - * Return list of interface pairs that are actively tethered. Even indexes are - * remote interface, and odd indexes are corresponding local interfaces. - */ - String[] getTetheredIfacePairs(); - String[] getTetheringErroredIfaces(); String[] getTetherableUsbRegexs(); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 02a78dea33..eca7af7dce 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -58,8 +58,8 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.LinkQualityInfo; import android.net.LinkProperties.CompareResult; +import android.net.LinkQualityInfo; import android.net.MobileDataStateTracker; import android.net.NetworkConfig; import android.net.NetworkInfo; @@ -89,7 +89,6 @@ import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; -import android.os.ResultReceiver; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; @@ -114,7 +113,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; -import com.android.net.IProxyService; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; @@ -3209,12 +3207,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return mTethering.getTetheredIfaces(); } - @Override - public String[] getTetheredIfacePairs() { - enforceTetherAccessPermission(); - return mTethering.getTetheredIfacePairs(); - } - public String[] getTetheringErroredIfaces() { enforceTetherAccessPermission(); return mTethering.getErroredIfaces(); diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index a9909b2ecf..a1af8cb79f 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -40,7 +40,6 @@ import static android.text.format.DateUtils.MINUTE_IN_MILLIS; import static android.text.format.DateUtils.WEEK_IN_MILLIS; import static com.android.server.net.NetworkStatsService.ACTION_NETWORK_STATS_POLL; import static org.easymock.EasyMock.anyLong; -import static org.easymock.EasyMock.aryEq; import static org.easymock.EasyMock.capture; import static org.easymock.EasyMock.createMock; import static org.easymock.EasyMock.eq; @@ -74,13 +73,13 @@ import com.android.server.net.NetworkStatsService; import com.android.server.net.NetworkStatsService.NetworkStatsSettings; import com.android.server.net.NetworkStatsService.NetworkStatsSettings.Config; +import libcore.io.IoUtils; + import org.easymock.Capture; import org.easymock.EasyMock; import java.io.File; -import libcore.io.IoUtils; - /** * Tests for {@link NetworkStatsService}. */ @@ -919,8 +918,7 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce(); // also include tethering details, since they are folded into UID - expect(mConnManager.getTetheredIfacePairs()).andReturn(tetherIfacePairs).atLeastOnce(); - expect(mNetManager.getNetworkStatsTethering(aryEq(tetherIfacePairs))) + expect(mNetManager.getNetworkStatsTethering()) .andReturn(tetherStats).atLeastOnce(); } From 239a3b22f1dd5cb253042e899c3bd268691933da Mon Sep 17 00:00:00 2001 From: Yuhao Zheng Date: Wed, 11 Sep 2013 09:36:41 -0700 Subject: [PATCH 141/296] Fix for the toggle airplane mode hidden API Fix to https://googleplex-android-review.git.corp.google.com/#/c/356900/ Previous implementation throws SecurityException when the API is called from apps. bug:10653570 Change-Id: I95ae6f07db74d881f1a8d3d40a6486105a068e90 --- services/java/com/android/server/ConnectivityService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4e3faca51a..1af7cc89a9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4684,12 +4684,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public void setAirplaneMode(boolean enable) { enforceConnectivityInternalPermission(); - final ContentResolver cr = mContext.getContentResolver(); - Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", enable); final long ident = Binder.clearCallingIdentity(); try { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", enable); mContext.sendBroadcast(intent); } finally { Binder.restoreCallingIdentity(ident); From 0e1e5c93a246a62f32dbe6be5db901855d4229e1 Mon Sep 17 00:00:00 2001 From: Yuhao Zheng Date: Wed, 11 Sep 2013 09:36:41 -0700 Subject: [PATCH 142/296] Fix for the toggle airplane mode hidden API Fix to https://googleplex-android-review.git.corp.google.com/#/c/356900/ Previous implementation throws SecurityException when the API is called from apps. bug:10653570 Change-Id: I95ae6f07db74d881f1a8d3d40a6486105a068e90 --- services/java/com/android/server/ConnectivityService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4e3faca51a..1af7cc89a9 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4684,12 +4684,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public void setAirplaneMode(boolean enable) { enforceConnectivityInternalPermission(); - final ContentResolver cr = mContext.getContentResolver(); - Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - intent.putExtra("state", enable); final long ident = Binder.clearCallingIdentity(); try { + final ContentResolver cr = mContext.getContentResolver(); + Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", enable); mContext.sendBroadcast(intent); } finally { Binder.restoreCallingIdentity(ident); From 0a9cc50662217d2204d880c2a4b1df8650af31b5 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 23 Aug 2013 19:21:25 -0400 Subject: [PATCH 143/296] Guarantee that PAC Local Proxy owns Port This changes the PAC support to not broadcast the Proxy information until the Local Proxy has started up and successfully bound to a port so that the local proxy information can be guaranteed to be owned by the proxy. Bug: 10459877 Change-Id: I175cd3388c758c55e341115e4a8241884b90d633 --- core/java/android/net/ProxyProperties.java | 10 +++++++++- .../java/com/android/server/ConnectivityService.java | 3 +-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 76aea9f58e..648a4b37eb 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -38,7 +38,7 @@ public class ProxyProperties implements Parcelable { private String mPacFileUrl; public static final String LOCAL_EXCL_LIST = ""; - public static final int LOCAL_PORT = 8182; + public static final int LOCAL_PORT = -1; public static final String LOCAL_HOST = "localhost"; public ProxyProperties(String host, int port, String exclList) { @@ -54,6 +54,14 @@ public class ProxyProperties implements Parcelable { mPacFileUrl = pacFileUrl; } + // Only used in PacManager after Local Proxy is bound. + public ProxyProperties(String pacFileUrl, int localProxyPort) { + mHost = LOCAL_HOST; + mPort = localProxyPort; + setExclusionList(LOCAL_EXCL_LIST); + mPacFileUrl = pacFileUrl; + } + private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) { mHost = host; mPort = port; diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4e3faca51a..47f18e7335 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -114,7 +114,6 @@ import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; -import com.android.net.IProxyService; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; @@ -3471,7 +3470,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendProxyBroadcast(ProxyProperties proxy) { if (proxy == null) proxy = new ProxyProperties("", 0, ""); - mPacManager.setCurrentProxyScriptUrl(proxy); + if (mPacManager.setCurrentProxyScriptUrl(proxy)) return; if (DBG) log("sending Proxy Broadcast for " + proxy); Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | From e14346f8f42f03477bd168a2d4bd33dc6c665983 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 13 Sep 2013 12:40:11 -0700 Subject: [PATCH 144/296] checkMobileProvisioning should not block. In checkMobileProvisioning the call to mdst.isProvisioningNetwork() is a blocking call and during monkey testing without SIM this is causing ANR's. Move the initial test for provisioning into isMobileOk so checkMobileProvisioning doesn't block. If mobile is not supported return CMP_RESULT_NO_CONNECTION. Cleaned up some debug. Bug: 10674404 Change-Id: I10a0e922cd6ea9790f66e2083f37e68cb0a8861f --- .../android/server/ConnectivityService.java | 63 +++++++------------ 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3f8d7ebcca..cecb35b843 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3987,40 +3987,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Start off with notification off setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); - // See if we've alreadying determined if we've got a provsioning connection - // if so we don't need to do anything active - MobileDataStateTracker mdstDefault = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE]; - boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); - - MobileDataStateTracker mdstHipri = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; - boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); - - if (isDefaultProvisioning || isHipriProvisioning) { - if (mIsNotificationVisible) { - if (DBG) { - log("checkMobileProvisioning: provisioning-ignore notification is visible"); - } - } else { - NetworkInfo ni = null; - if (isDefaultProvisioning) { - ni = mdstDefault.getNetworkInfo(); - } - if (isHipriProvisioning) { - ni = mdstHipri.getNetworkInfo(); - } - String url = getMobileProvisioningUrl(); - if ((ni != null) && (!TextUtils.isEmpty(url))) { - setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); - } else { - if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); - } - } - mIsCheckingMobileProvisioning.set(false); - return timeOutMs; - } - CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override @@ -4154,8 +4120,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); result = CMP_RESULT_CODE_NO_CONNECTION; + log("isMobileOk: X not mobile capable result=" + result); + return result; + } + + // See if we've already determined we've got a provisioning connection, + // if so we don't need to do anything active. + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + log("isMobileOk: isDefaultProvisioning=" + isDefaultProvisioning); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + log("isMobileOk: isHipriProvisioning=" + isHipriProvisioning); + + if (isDefaultProvisioning || isHipriProvisioning) { + result = CMP_RESULT_CODE_PROVISIONING_NETWORK; + log("isMobileOk: X default || hipri is provisioning result=" + result); return result; } @@ -4217,8 +4201,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { MobileDataStateTracker mdst = (MobileDataStateTracker) mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; if (mdst.isProvisioningNetwork()) { - if (DBG) log("isMobileOk: isProvisioningNetwork is true"); result = CMP_RESULT_CODE_PROVISIONING_NETWORK; + if (DBG) log("isMobileOk: X isProvisioningNetwork result=" + result); return result; } else { if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); @@ -4233,8 +4217,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { - log("isMobileOk: UnknownHostException"); result = CMP_RESULT_CODE_NO_DNS; + log("isMobileOk: X UnknownHostException result=" + result); return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -4309,8 +4293,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (responseCode == 204) { // Return - log("isMobileOk: expected responseCode=" + responseCode); result = CMP_RESULT_CODE_CONNECTABLE; + log("isMobileOk: X expected responseCode=" + responseCode + + " result=" + result); return result; } else { // Retry to be sure this was redirected, we've gotten @@ -4328,7 +4313,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - log("isMobileOk: loops|timed out result=" + result); + log("isMobileOk: X loops|timed out result=" + result); return result; } catch (Exception e) { log("isMobileOk: Exception e=" + e); From e6d205263f2cd629ea6d77d07c642c818bfbcfa4 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Fri, 13 Sep 2013 12:40:11 -0700 Subject: [PATCH 145/296] checkMobileProvisioning should not block. In checkMobileProvisioning the call to mdst.isProvisioningNetwork() is a blocking call and during monkey testing without SIM this is causing ANR's. Move the initial test for provisioning into isMobileOk so checkMobileProvisioning doesn't block. If mobile is not supported return CMP_RESULT_NO_CONNECTION. Cleaned up some debug. Bug: 10674404 Change-Id: I10a0e922cd6ea9790f66e2083f37e68cb0a8861f --- .../android/server/ConnectivityService.java | 63 +++++++------------ 1 file changed, 24 insertions(+), 39 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3f8d7ebcca..cecb35b843 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3987,40 +3987,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Start off with notification off setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); - // See if we've alreadying determined if we've got a provsioning connection - // if so we don't need to do anything active - MobileDataStateTracker mdstDefault = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE]; - boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); - - MobileDataStateTracker mdstHipri = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; - boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); - - if (isDefaultProvisioning || isHipriProvisioning) { - if (mIsNotificationVisible) { - if (DBG) { - log("checkMobileProvisioning: provisioning-ignore notification is visible"); - } - } else { - NetworkInfo ni = null; - if (isDefaultProvisioning) { - ni = mdstDefault.getNetworkInfo(); - } - if (isHipriProvisioning) { - ni = mdstHipri.getNetworkInfo(); - } - String url = getMobileProvisioningUrl(); - if ((ni != null) && (!TextUtils.isEmpty(url))) { - setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), url); - } else { - if (DBG) log("checkMobileProvisioning: provisioning but no url, ignore"); - } - } - mIsCheckingMobileProvisioning.set(false); - return timeOutMs; - } - CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @Override @@ -4154,8 +4120,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { mParams = params; if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - log("isMobileOk: not mobile capable"); result = CMP_RESULT_CODE_NO_CONNECTION; + log("isMobileOk: X not mobile capable result=" + result); + return result; + } + + // See if we've already determined we've got a provisioning connection, + // if so we don't need to do anything active. + MobileDataStateTracker mdstDefault = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + boolean isDefaultProvisioning = mdstDefault.isProvisioningNetwork(); + log("isMobileOk: isDefaultProvisioning=" + isDefaultProvisioning); + + MobileDataStateTracker mdstHipri = (MobileDataStateTracker) + mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; + boolean isHipriProvisioning = mdstHipri.isProvisioningNetwork(); + log("isMobileOk: isHipriProvisioning=" + isHipriProvisioning); + + if (isDefaultProvisioning || isHipriProvisioning) { + result = CMP_RESULT_CODE_PROVISIONING_NETWORK; + log("isMobileOk: X default || hipri is provisioning result=" + result); return result; } @@ -4217,8 +4201,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { MobileDataStateTracker mdst = (MobileDataStateTracker) mCs.mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI]; if (mdst.isProvisioningNetwork()) { - if (DBG) log("isMobileOk: isProvisioningNetwork is true"); result = CMP_RESULT_CODE_PROVISIONING_NETWORK; + if (DBG) log("isMobileOk: X isProvisioningNetwork result=" + result); return result; } else { if (DBG) log("isMobileOk: isProvisioningNetwork is false, continue"); @@ -4233,8 +4217,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { addresses = InetAddress.getAllByName(orgUri.getHost()); } catch (UnknownHostException e) { - log("isMobileOk: UnknownHostException"); result = CMP_RESULT_CODE_NO_DNS; + log("isMobileOk: X UnknownHostException result=" + result); return result; } log("isMobileOk: addresses=" + inetAddressesToString(addresses)); @@ -4309,8 +4293,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (responseCode == 204) { // Return - log("isMobileOk: expected responseCode=" + responseCode); result = CMP_RESULT_CODE_CONNECTABLE; + log("isMobileOk: X expected responseCode=" + responseCode + + " result=" + result); return result; } else { // Retry to be sure this was redirected, we've gotten @@ -4328,7 +4313,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - log("isMobileOk: loops|timed out result=" + result); + log("isMobileOk: X loops|timed out result=" + result); return result; } catch (Exception e) { log("isMobileOk: Exception e=" + e); From 11fa47227d02ee75839573206eb29d401eafb1a7 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 14 Sep 2013 09:04:53 -0700 Subject: [PATCH 146/296] Tighten condition for calling checkMobileProvisioning. Add the condition that the connected network needs to be TYPE_MOBILE. This eliminates checking on connecting to secondary networks like FOTA, MMS, SUPL ... This reduces unnecessary attempts to bring up multiple connections at the same time. Especially in the light of the trouble we're having with HFA on Sprint, where we don't want to connect to any other network until HFA has completed. Bug: 10758001 Change-Id: Id294536b70304a51de4752bc1a4ffac734f10f1a --- services/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 19b762d39c..3f13f3acf5 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2953,8 +2953,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) - && ((state == NetworkInfo.State.CONNECTED) - || info.isConnectedToProvisioningNetwork())) { + && (((state == NetworkInfo.State.CONNECTED) + && (info.getType() == ConnectivityManager.TYPE_MOBILE)) + || info.isConnectedToProvisioningNetwork())) { + log("ConnectivityChange checkMobileProvisioning for" + + " TYPE_MOBILE or ProvisioningNetwork"); checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } From 06c96d07ad5858ce4ebb1d69a31607d8c438029a Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Sat, 14 Sep 2013 09:04:53 -0700 Subject: [PATCH 147/296] Tighten condition for calling checkMobileProvisioning. Add the condition that the connected network needs to be TYPE_MOBILE. This eliminates checking on connecting to secondary networks like FOTA, MMS, SUPL ... This reduces unnecessary attempts to bring up multiple connections at the same time. Especially in the light of the trouble we're having with HFA on Sprint, where we don't want to connect to any other network until HFA has completed. Bug: 10758001 Change-Id: Id294536b70304a51de4752bc1a4ffac734f10f1a --- services/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cecb35b843..7560d090c3 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2953,8 +2953,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (ConnectivityManager.isNetworkTypeMobile(info.getType()) && (0 != Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DEVICE_PROVISIONED, 0)) - && ((state == NetworkInfo.State.CONNECTED) - || info.isConnectedToProvisioningNetwork())) { + && (((state == NetworkInfo.State.CONNECTED) + && (info.getType() == ConnectivityManager.TYPE_MOBILE)) + || info.isConnectedToProvisioningNetwork())) { + log("ConnectivityChange checkMobileProvisioning for" + + " TYPE_MOBILE or ProvisioningNetwork"); checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); } From b87ab962952486458fd6297f1c349b6f24ce8040 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 24 Sep 2013 11:05:57 -0700 Subject: [PATCH 148/296] Don't redirect dns to an iface without dns servers bug:10115444 Change-Id: Ide42072bb3aae21f8e99c11c2de263e9a765b911 --- .../android/server/ConnectivityService.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3f13f3acf5..56d50103a5 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2794,7 +2794,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mNumDnsEntries = last; } catch (Exception e) { - if (DBG) loge("exception setting default dns interface: " + e); + loge("exception setting default dns interface: " + e); } } @@ -3779,31 +3779,33 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - public void addUserForwarding(String interfaze, int uid) { + public void addUserForwarding(String interfaze, int uid, boolean forwardDns) { int uidStart = uid * UserHandle.PER_USER_RANGE; int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1; - addUidForwarding(interfaze, uidStart, uidEnd); + addUidForwarding(interfaze, uidStart, uidEnd, forwardDns); } - public void clearUserForwarding(String interfaze, int uid) { + public void clearUserForwarding(String interfaze, int uid, boolean forwardDns) { int uidStart = uid * UserHandle.PER_USER_RANGE; int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1; - clearUidForwarding(interfaze, uidStart, uidEnd); + clearUidForwarding(interfaze, uidStart, uidEnd, forwardDns); } - public void addUidForwarding(String interfaze, int uidStart, int uidEnd) { + public void addUidForwarding(String interfaze, int uidStart, int uidEnd, + boolean forwardDns) { try { mNetd.setUidRangeRoute(interfaze,uidStart, uidEnd); - mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); + if (forwardDns) mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); } catch (RemoteException e) { } } - public void clearUidForwarding(String interfaze, int uidStart, int uidEnd) { + public void clearUidForwarding(String interfaze, int uidStart, int uidEnd, + boolean forwardDns) { try { mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd); - mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd); + if (forwardDns) mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd); } catch (RemoteException e) { } From 76f49d3ceeb76b1f7e5d0e73d62f44c8e23561cc Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 3 Oct 2013 08:34:46 -0700 Subject: [PATCH 149/296] Use networkType to display wifi and mobile notification separately. There are two bugs one is I was clearing the notification in CaptivePortalTracker when entering the ActivateState. (double check according to bug 5021626 we should be calling enter) Second is we could have the need to display both icons but can't because we only allow one. The solution I'm proposing here is to allow two notifications and have then controlled separately. Bug: 10886908 Change-Id: I30e7130bc542535492d175640a4990c592f32806 --- .../com/android/server/ConnectivityService.java | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 3f13f3acf5..f005f5ff9c 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3987,8 +3987,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { return timeOutMs; } - // Start off with notification off - setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + // Start off with mobile notification off + setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); CheckMp checkMp = new CheckMp(mContext, this); CheckMp.CallBack cb = new CheckMp.CallBack() { @@ -4013,7 +4013,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (TextUtils.isEmpty(url) == false) { if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url); - setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + setProvNotificationVisible(true, + ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(), url); } else { if (DBG) log("CheckMp.onComplete: warm (redirected), no url"); @@ -4024,7 +4025,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { String url = getMobileProvisioningUrl(); if (TextUtils.isEmpty(url) == false) { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), url=" + url); - setProvNotificationVisible(true, ni.getType(), ni.getExtraInfo(), + setProvNotificationVisible(true, + ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(), url); } else { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); @@ -4426,7 +4428,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleMobileProvisioningAction(String url) { // Notication mark notification as not visible - setProvNotificationVisible(false, ConnectivityManager.TYPE_NONE, null, null); + setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); // If provisioning network handle as a special case, // otherwise launch browser with the intent directly. @@ -4512,14 +4514,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); try { - notificationManager.notify(NOTIFICATION_ID, 1, notification); + notificationManager.notify(NOTIFICATION_ID, networkType, notification); } catch (NullPointerException npe) { loge("setNotificaitionVisible: visible notificationManager npe=" + npe); npe.printStackTrace(); } } else { try { - notificationManager.cancel(NOTIFICATION_ID, 1); + notificationManager.cancel(NOTIFICATION_ID, networkType); } catch (NullPointerException npe) { loge("setNotificaitionVisible: cancel notificationManager npe=" + npe); npe.printStackTrace(); From 88a69fc2c0b1334cfd430c2947ff6534b85f3359 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 3 Oct 2013 16:59:05 -0700 Subject: [PATCH 150/296] DO NOT MERGE Un-deprecate getDhcpInfo Replacement api isn't available. bug:10003785 Change-Id: I0c91716d9aae61dc1db4d015a78b729157ea99a9 --- core/java/android/net/DhcpInfo.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index ab4cd9b9ef..3bede5da50 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,7 +22,6 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. - * @deprecated - use LinkProperties - To be removed 11/2014 */ public class DhcpInfo implements Parcelable { public int ipAddress; From 5b1ce8a83580d683d687367862054295020bd07f Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 4 Oct 2013 09:53:39 -0700 Subject: [PATCH 151/296] Un-deprecate getDhcpInfo Replacement api isn't available. bug:10003785 Change-Id: Ibe981ae90e1c6c2f1b65fa225443ae4cc92c2a3a --- core/java/android/net/DhcpInfo.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index ab4cd9b9ef..3bede5da50 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,7 +22,6 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. - * @deprecated - use LinkProperties - To be removed 11/2014 */ public class DhcpInfo implements Parcelable { public int ipAddress; From f725b93f4855f5a2bf4a9e7428d03ca91a2e7b22 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 3 Oct 2013 16:59:05 -0700 Subject: [PATCH 152/296] DO NOT MERGE Un-deprecate getDhcpInfo Replacement api isn't available. bug:10003785 Change-Id: I0c91716d9aae61dc1db4d015a78b729157ea99a9 --- core/java/android/net/DhcpInfo.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index ab4cd9b9ef..3bede5da50 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -22,7 +22,6 @@ import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. - * @deprecated - use LinkProperties - To be removed 11/2014 */ public class DhcpInfo implements Parcelable { public int ipAddress; From 9405beeea0855b2b76834049a3a8eb4a445242ae Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Tue, 8 Oct 2013 10:41:25 +0900 Subject: [PATCH 153/296] Fix captive portal detection on IPv6 networks. Currently the captive portal check URL is generated by concatenating scheme, "://", IP address, and port. This breaks for IPv6 because IPv6 addresses in URLs must be enclosed in square brackets (e.g., http://2001:db8::1/generate_204 is invalid; should he http://[2001:db8::1]/generate_204 instead). The resulting MalformedURLException causes isMobileOk to report that there is no captive portal, even if there is one. Fortunately the three-arg URL constructor already knows how to construct URLs with IPv6 addresses. Use that instead of generating the URL ourselves. Bug: 10801896 Change-Id: I02605ef62f493a34f25bb405ef02b111543a76fd --- .../java/com/android/server/ConnectivityService.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 59b559e0de..5695ee510d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4247,6 +4247,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { addrTried ++) { // Choose the address at random but make sure its type is supported + // TODO: This doesn't work 100% of the time, because we may end up + // trying the same invalid address more than once and ignoring one + // of the valid addresses. InetAddress hostAddr = addresses[rand.nextInt(addresses.length)]; if (((hostAddr instanceof Inet4Address) && linkHasIpv4) || ((hostAddr instanceof Inet6Address) && linkHasIpv6)) { @@ -4271,10 +4274,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Rewrite the url to have numeric address to use the specific route. - // I also set the "Connection" to "Close" as by default "Keep-Alive" - // is used which is useless in this case. - URL newUrl = new URL(orgUri.getScheme() + "://" - + hostAddr.getHostAddress() + orgUri.getPath()); + URL newUrl = new URL(orgUri.getScheme(), + hostAddr.getHostAddress(), orgUri.getPath()); log("isMobileOk: newUrl=" + newUrl); HttpURLConnection urlConn = null; @@ -4287,6 +4288,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.setReadTimeout(SOCKET_TIMEOUT_MS); urlConn.setUseCaches(false); urlConn.setAllowUserInteraction(false); + // Set the "Connection" to "Close" as by default "Keep-Alive" + // is used which is useless in this case. urlConn.setRequestProperty("Connection", "close"); int responseCode = urlConn.getResponseCode(); From 75d9bcddea5f43fc9ca37199674c2cbb3c659e2c Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Mon, 7 Oct 2013 14:32:00 -0700 Subject: [PATCH 154/296] Fix issue #11113111: `dumpsys activity service` is broken Change-Id: Ie02d27b377c562085ef7eb5dea144ce2f382c11d From a69f1b06de333a97a99c317d72357f1f2373c636 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Thu, 10 Oct 2013 14:02:51 -0400 Subject: [PATCH 155/296] getProxy in ConnectivityService returns port w/PAC Changes the PacManager to report message back to ConnectivityService to send a broadcast once the download has completed. This allows the ConnectivityService to store the correct proxy info for getProxy(). This made the problem arise that ProxyProperties was not handling port while it had PAC. Added small fix for equals() and parcelization. The combination of these fixes seems to resolve Bug: 11028616. Bug: 11168706 Change-Id: I92d1343a8e804391ab77596b8167a2ef8d76b378 --- core/java/android/net/ProxyProperties.java | 7 +++++-- .../java/com/android/server/ConnectivityService.java | 11 ++++++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 648a4b37eb..78ac75f22c 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -178,7 +178,7 @@ public class ProxyProperties implements Parcelable { // If PAC URL is present in either then they must be equal. // Other parameters will only be for fall back. if (!TextUtils.isEmpty(mPacFileUrl)) { - return mPacFileUrl.equals(p.getPacFileUrl()); + return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; } if (!TextUtils.isEmpty(p.getPacFileUrl())) { return false; @@ -219,6 +219,7 @@ public class ProxyProperties implements Parcelable { if (mPacFileUrl != null) { dest.writeByte((byte)1); dest.writeString(mPacFileUrl); + dest.writeInt(mPort); return; } else { dest.writeByte((byte)0); @@ -244,7 +245,9 @@ public class ProxyProperties implements Parcelable { String host = null; int port = 0; if (in.readByte() != 0) { - return new ProxyProperties(in.readString()); + String url = in.readString(); + int localPort = in.readInt(); + return new ProxyProperties(url, localPort); } if (in.readByte() != 0) { host = in.readString(); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 5695ee510d..70418e8d04 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -353,6 +353,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15; + /** + * PAC manager has received new port. + */ + private static final int EVENT_PROXY_HAS_CHANGED = 16; + /** Handler used for internal events. */ private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -679,7 +684,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { }, new IntentFilter(filter)); - mPacManager = new PacManager(mContext); + mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED); filter = new IntentFilter(); filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); @@ -3124,6 +3129,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleNetworkSamplingTimeout(); break; } + case EVENT_PROXY_HAS_CHANGED: { + handleApplyDefaultProxy((ProxyProperties)msg.obj); + break; + } } } } From b82bc07c9db3eb221884247024c75e21447e97f2 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Fri, 11 Oct 2013 13:43:30 +0100 Subject: [PATCH 156/296] Fix minor thread corectness issue in NetworkInfo Hold the right lock while copying info from another NetworkInfo object to prevent changes being made to it while the copy is in progress. Change-Id: I1aa2c29e81e045b0359f957352c438e79e692823 --- core/java/android/net/NetworkInfo.java | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 4d2a70ddf1..53b1308db6 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -156,18 +156,20 @@ public class NetworkInfo implements Parcelable { /** {@hide} */ public NetworkInfo(NetworkInfo source) { if (source != null) { - mNetworkType = source.mNetworkType; - mSubtype = source.mSubtype; - mTypeName = source.mTypeName; - mSubtypeName = source.mSubtypeName; - mState = source.mState; - mDetailedState = source.mDetailedState; - mReason = source.mReason; - mExtraInfo = source.mExtraInfo; - mIsFailover = source.mIsFailover; - mIsRoaming = source.mIsRoaming; - mIsAvailable = source.mIsAvailable; - mIsConnectedToProvisioningNetwork = source.mIsConnectedToProvisioningNetwork; + synchronized (source) { + mNetworkType = source.mNetworkType; + mSubtype = source.mSubtype; + mTypeName = source.mTypeName; + mSubtypeName = source.mSubtypeName; + mState = source.mState; + mDetailedState = source.mDetailedState; + mReason = source.mReason; + mExtraInfo = source.mExtraInfo; + mIsFailover = source.mIsFailover; + mIsRoaming = source.mIsRoaming; + mIsAvailable = source.mIsAvailable; + mIsConnectedToProvisioningNetwork = source.mIsConnectedToProvisioningNetwork; + } } } From af2f34adfd71401c6cc8c827e0e509263c2a72d9 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 14 Oct 2013 18:03:02 -0700 Subject: [PATCH 157/296] Retry captiveportal check even if only one addr We're getting some false positive results on this check and while it was coded to try 3 times given sufficient independent addrs the default url resolves to a single address so we'd just try once. Rework to try again even with fewer urls to try to reduce the false positives. Also adds a random query param to fool proxies into not caching. bug:9972012 Change-Id: Ib719f40ec612065ca6bcd919549fc1164506d35a --- .../android/server/ConnectivityService.java | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 70418e8d04..b5f0697472 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4247,27 +4247,35 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("isMobileOk: linkHasIpv4=" + linkHasIpv4 + " linkHasIpv6=" + linkHasIpv6); - // Loop through at most 3 valid addresses or all of the address or until - // we run out of time - int loops = Math.min(3, addresses.length); - for(int validAddr=0, addrTried=0; - (validAddr < loops) && (addrTried < addresses.length) - && (SystemClock.elapsedRealtime() < endTime); - addrTried ++) { + final ArrayList validAddresses = + new ArrayList(addresses.length); - // Choose the address at random but make sure its type is supported - // TODO: This doesn't work 100% of the time, because we may end up - // trying the same invalid address more than once and ignoring one - // of the valid addresses. - InetAddress hostAddr = addresses[rand.nextInt(addresses.length)]; - if (((hostAddr instanceof Inet4Address) && linkHasIpv4) - || ((hostAddr instanceof Inet6Address) && linkHasIpv6)) { - // Valid address, so use it - validAddr += 1; - } else { - // Invalid address so try next address - continue; + for (InetAddress addr : addresses) { + if (((addr instanceof Inet4Address) && linkHasIpv4) || + ((addr instanceof Inet6Address) && linkHasIpv6)) { + validAddresses.add(addr); } + } + + if (validAddresses.size() == 0) { + return CMP_RESULT_CODE_NO_CONNECTION; + } + + int addrTried = 0; + while (true) { + // Loop through at most 3 valid addresses or until + // we run out of time + if (addrTried++ >= 3) { + log("too many loops tried - giving up"); + break; + } + if (SystemClock.elapsedRealtime() >= endTime) { + log("spend too much time - giving up"); + break; + } + + InetAddress hostAddr = validAddresses.get(rand.nextInt( + validAddresses.size())); // Make a route to host so we check the specific interface. if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI, @@ -4283,8 +4291,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Rewrite the url to have numeric address to use the specific route. + // Add a pointless random query param to fool proxies into not caching. URL newUrl = new URL(orgUri.getScheme(), - hostAddr.getHostAddress(), orgUri.getPath()); + hostAddr.getHostAddress(), + orgUri.getPath() + "?q=" + rand.nextInt(Integer.MAX_VALUE)); log("isMobileOk: newUrl=" + newUrl); HttpURLConnection urlConn = null; @@ -4321,6 +4331,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { // occasions where a server returned 200 even though // the device didn't have a "warm" sim. log("isMobileOk: not expected responseCode=" + responseCode); + // TODO - it would be nice in the single-address case to do + // another DNS resolve here, but flushing the cache is a bit + // heavy-handed. result = CMP_RESULT_CODE_REDIRECTED; } } catch (Exception e) { From ab035433236fe1788cbdcaa5213becae5b593867 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Thu, 29 Aug 2013 13:40:43 +0100 Subject: [PATCH 158/296] Remove captive portal code that has no effect. Note that this CL does not change any behaviour. At the center of this change is CaptivePortalTracker#detectCaptivePortal(), which does nothing except call back into ConnectivityService. Removing it allows us to simplify code in ConnectivityService. It also allows us to remove ConnectivityService#captivePortalCheckComplete which was only ever called in response to this method. While this does not change any behaviour, it preserves existing bad behaviour, i.e, that the CAPTIVE_PORTAL_CHECK NetworkInfo state does not correspond to actual captive portal detection. We transition into that state and immediately (and unconditionally) out of it and into CONNECTED. Change-Id: Ib3797f956d2db5e3cacaaa53e899d81aa8e958af --- .../java/android/net/ConnectivityManager.java | 18 ---------- .../android/net/IConnectivityManager.aidl | 2 -- .../android/server/ConnectivityService.java | 33 ------------------- 3 files changed, 53 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index c78a973cee..0f8dc7aa07 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1328,24 +1328,6 @@ public class ConnectivityManager { } } - /** - * Signal that the captive portal check on the indicated network - * is complete and we can turn the network on for general use. - * - * @param info the {@link NetworkInfo} object for the networkType - * in question. - * - *

This method requires the call to hold the permission - * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. - * {@hide} - */ - public void captivePortalCheckComplete(NetworkInfo info) { - try { - mService.captivePortalCheckComplete(info); - } catch (RemoteException e) { - } - } - /** * Signal that the captive portal check on the indicated network * is complete and whether its a captive portal or not. diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index c1da2e32aa..b3217eb907 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -129,8 +129,6 @@ interface IConnectivityManager boolean updateLockdownVpn(); - void captivePortalCheckComplete(in NetworkInfo info); - void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); void supplyMessenger(int networkType, in Messenger messenger); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index b5f0697472..5418b3b03d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2316,36 +2316,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void handleCaptivePortalTrackerCheck(NetworkInfo info) { - if (DBG) log("Captive portal check " + info); - int type = info.getType(); - final NetworkStateTracker thisNet = mNetTrackers[type]; - if (mNetConfigs[type].isDefault()) { - if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { - if (isNewNetTypePreferredOverCurrentNetType(type)) { - if (DBG) log("Captive check on " + info.getTypeName()); - mCaptivePortalTracker.detectCaptivePortal(new NetworkInfo(info)); - return; - } else { - if (DBG) log("Tear down low priority net " + info.getTypeName()); - teardown(thisNet); - return; - } - } - } - - if (DBG) log("handleCaptivePortalTrackerCheck: call captivePortalCheckComplete ni=" + info); - thisNet.captivePortalCheckComplete(); - } - - /** @hide */ - @Override - public void captivePortalCheckComplete(NetworkInfo info) { - enforceConnectivityInternalPermission(); - if (DBG) log("captivePortalCheckComplete: ni=" + info); - mNetTrackers[info.getType()].captivePortalCheckComplete(); - } - /** @hide */ @Override public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { @@ -2972,9 +2942,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (info.getDetailedState() == NetworkInfo.DetailedState.FAILED) { handleConnectionFailure(info); - } else if (info.getDetailedState() == - DetailedState.CAPTIVE_PORTAL_CHECK) { - handleCaptivePortalTrackerCheck(info); } else if (info.isConnectedToProvisioningNetwork()) { /** * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING From 411dcf66c4f550416d0efb074199fbdafb1d0ee7 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 17 Oct 2013 12:46:52 -0700 Subject: [PATCH 159/296] Change how we use provisioning url so post works Needed to do an http post instead of a get for one carrier. Do this by putting an auto-submitting form in the data to be interpreted as a html doc by the browser. The ACTION_VIEW intent only works on http uri, but by specifying ACTION_MAIN/ CATEGORY_APP_BROWSER we could use data:text/html. bug:11168810 Change-Id: Ifd33e1c3c7f9f40b6add39e446e6a7d7cde22549 --- services/java/com/android/server/ConnectivityService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 70418e8d04..a92ceec27f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4454,8 +4454,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mdst.enableMobileProvisioning(url); } else { if (DBG) log("handleMobileProvisioningAction: on default network"); - Intent newIntent = - new Intent(Intent.ACTION_VIEW, Uri.parse(url)); + Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, + Intent.CATEGORY_APP_BROWSER); + newIntent.setData(Uri.parse(url)); newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK); try { From 5294eb3389a3717375da3d06898cf49d971ebe52 Mon Sep 17 00:00:00 2001 From: Andrew Flynn Date: Fri, 11 Oct 2013 10:16:31 -0700 Subject: [PATCH 160/296] Check for presence of carrier app in data notification. When ConnectivityService checks the mobile data connection and notices that there is no connectivity, first do a check to see if a valid carrier app for the current MCC/MNC exists. If so, launch that app instead of checking for a provisioning URL or hoping for a DNS redirect in the browser. If no such app exists, continue on as normal. Bug: 9622645 Change-Id: Ic88b06250af89825d8eee7e4945fb8d7c28d16e1 --- .../android/server/ConnectivityService.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index cb059ffb78..4cba6149d7 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -111,6 +111,7 @@ import com.android.internal.net.VpnProfile; import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; +import com.android.internal.telephony.TelephonyIntents; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; @@ -4434,15 +4435,27 @@ public class ConnectivityService extends IConnectivityManager.Stub { mdst.enableMobileProvisioning(url); } else { if (DBG) log("handleMobileProvisioningAction: on default network"); - Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, - Intent.CATEGORY_APP_BROWSER); - newIntent.setData(Uri.parse(url)); - newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | - Intent.FLAG_ACTIVITY_NEW_TASK); - try { - mContext.startActivity(newIntent); - } catch (ActivityNotFoundException e) { - loge("handleMobileProvisioningAction: startActivity failed" + e); + // Check for apps that can handle provisioning first + Intent provisioningIntent = new Intent(TelephonyIntents.ACTION_CARRIER_SETUP); + provisioningIntent.addCategory(TelephonyIntents.CATEGORY_MCCMNC_PREFIX + + mTelephonyManager.getSimOperator()); + if (mContext.getPackageManager().resolveActivity(provisioningIntent, 0 /* flags */) + != null) { + provisioningIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(provisioningIntent); + } else { + // If no apps exist, use standard URL ACTION_VIEW method + Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, + Intent.CATEGORY_APP_BROWSER); + newIntent.setData(Uri.parse(url)); + newIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | + Intent.FLAG_ACTIVITY_NEW_TASK); + try { + mContext.startActivity(newIntent); + } catch (ActivityNotFoundException e) { + loge("handleMobileProvisioningAction: startActivity failed" + e); + } } } } From 4df83f573425afe792883ea28fb3a0615ca56a00 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 31 Oct 2013 06:35:22 -0700 Subject: [PATCH 161/296] Use HttpsURLConnection to by pass proxies. In isMobileOk attempting to connect to clients3.google.com/generate_204 we sometimes see a proxy server will not let the connection go to our server and instead returns 200 instead of 204. By using Https we by pass proxy servers and we will always connected to our server. The number of loops is increased from 3 to 4 and half the the retires will use Http and half will use Https. I also, added mTestingFailures which can be set to true by setting persist.checkmp.testfailures to 1. This will cause checkMobileProvisiong to always fail so we can test https & http. Bug: 9972012 Change-Id: I870606037dcffe5250843980517ac52218266e02 --- .../android/server/ConnectivityService.java | 119 +++++++++++++++--- 1 file changed, 99 insertions(+), 20 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 7c61c44001..594f6831be 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -77,6 +77,7 @@ import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; import android.os.AsyncTask; import android.os.Binder; +import android.os.Build; import android.os.FileUtils; import android.os.Handler; import android.os.HandlerThread; @@ -141,6 +142,7 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.URL; +import java.net.URLConnection; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; @@ -154,6 +156,10 @@ import java.util.Random; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.HttpsURLConnection; +import javax.net.ssl.SSLSession; + /** * @hide */ @@ -4066,8 +4072,28 @@ public class ConnectivityService extends IConnectivityManager.Stub { static class CheckMp extends AsyncTask { private static final String CHECKMP_TAG = "CheckMp"; + + // adb shell setprop persist.checkmp.testfailures 1 to enable testing failures + private static boolean mTestingFailures; + + // Choosing 4 loops as half of them will use HTTPS and the other half HTTP + private static final int MAX_LOOPS = 4; + + // Number of milli-seconds to complete all of the retires public static final int MAX_TIMEOUT_MS = 60000; + + // The socket should retry only 5 seconds, the default is longer private static final int SOCKET_TIMEOUT_MS = 5000; + + // Sleep time for network errors + private static final int NET_ERROR_SLEEP_SEC = 3; + + // Sleep time for network route establishment + private static final int NET_ROUTE_ESTABLISHMENT_SLEEP_SEC = 3; + + // Short sleep time for polling :( + private static final int POLLING_SLEEP_SEC = 1; + private Context mContext; private ConnectivityService mCs; private TelephonyManager mTm; @@ -4093,6 +4119,31 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + // As explained to me by Brian Carlstrom and Kenny Root, Certificates can be + // issued by name or ip address, for Google its by name so when we construct + // this HostnameVerifier we'll pass the original Uri and use it to verify + // the host. If the host name in the original uril fails we'll test the + // hostname parameter just incase things change. + static class CheckMpHostnameVerifier implements HostnameVerifier { + Uri mOrgUri; + + CheckMpHostnameVerifier(Uri orgUri) { + mOrgUri = orgUri; + } + + @Override + public boolean verify(String hostname, SSLSession session) { + HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier(); + String orgUriHost = mOrgUri.getHost(); + boolean retVal = hv.verify(orgUriHost, session) || hv.verify(hostname, session); + if (DBG) { + log("isMobileOk: hostnameVerify retVal=" + retVal + " hostname=" + hostname + + " orgUriHost=" + orgUriHost); + } + return retVal; + } + } + /** * The call back object passed in Params. onComplete will be called * on the main thread. @@ -4103,6 +4154,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } public CheckMp(Context context, ConnectivityService cs) { + if (Build.IS_DEBUGGABLE) { + mTestingFailures = + SystemProperties.getInt("persist.checkmp.testfailures", 0) == 1; + } else { + mTestingFailures = false; + } + mContext = context; mCs = cs; @@ -4174,7 +4232,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mCs.setEnableFailFastMobileData(DctConstants.ENABLED); break; } - sleep(1); + sleep(POLLING_SLEEP_SEC); } } @@ -4192,7 +4250,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (VDBG) log("isMobileOk: hipri not started yet"); result = CMP_RESULT_CODE_NO_CONNECTION; - sleep(1); + sleep(POLLING_SLEEP_SEC); } // Continue trying to connect until time has run out @@ -4208,7 +4266,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("isMobileOk: not connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } - sleep(1); + sleep(POLLING_SLEEP_SEC); result = CMP_RESULT_CODE_NO_CONNECTION; continue; } @@ -4226,7 +4284,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Get of the addresses associated with the url host. We need to use the // address otherwise HttpURLConnection object will use the name to get - // the addresses and is will try every address but that will bypass the + // the addresses and will try every address but that will bypass the // route to host we setup and the connection could succeed as the default // interface might be connected to the internet via wifi or other interface. InetAddress[] addresses; @@ -4263,14 +4321,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { int addrTried = 0; while (true) { - // Loop through at most 3 valid addresses or until + // Loop through at most MAX_LOOPS valid addresses or until // we run out of time - if (addrTried++ >= 3) { - log("too many loops tried - giving up"); + if (addrTried++ >= MAX_LOOPS) { + log("isMobileOk: too many loops tried - giving up"); break; } if (SystemClock.elapsedRealtime() >= endTime) { - log("spend too much time - giving up"); + log("isMobileOk: spend too much time - giving up"); break; } @@ -4283,25 +4341,37 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Wait a short time to be sure the route is established ?? log("isMobileOk:" + " wait to establish route to hostAddr=" + hostAddr); - sleep(3); + sleep(NET_ROUTE_ESTABLISHMENT_SLEEP_SEC); } else { log("isMobileOk:" + " could not establish route to hostAddr=" + hostAddr); + // Wait a short time before the next attempt + sleep(NET_ERROR_SLEEP_SEC); continue; } - // Rewrite the url to have numeric address to use the specific route. - // Add a pointless random query param to fool proxies into not caching. - URL newUrl = new URL(orgUri.getScheme(), - hostAddr.getHostAddress(), - orgUri.getPath() + "?q=" + rand.nextInt(Integer.MAX_VALUE)); + // Rewrite the url to have numeric address to use the specific route + // using http for half the attempts and https for the other half. + // Doing https first and http second as on a redirected walled garden + // such as t-mobile uses we get a SocketTimeoutException: "SSL + // handshake timed out" which we declare as + // CMP_RESULT_CODE_NO_TCP_CONNECTION. We could change this, but by + // having http second we will be using logic used for some time. + URL newUrl; + String scheme = (addrTried <= (MAX_LOOPS/2)) ? "https" : "http"; + newUrl = new URL(scheme, hostAddr.getHostAddress(), + orgUri.getPath()); log("isMobileOk: newUrl=" + newUrl); HttpURLConnection urlConn = null; try { - // Open the connection set the request header and get the response - urlConn = (HttpURLConnection) newUrl.openConnection( + // Open the connection set the request headers and get the response + urlConn = (HttpURLConnection)newUrl.openConnection( java.net.Proxy.NO_PROXY); + if (scheme.equals("https")) { + ((HttpsURLConnection)urlConn).setHostnameVerifier( + new CheckMpHostnameVerifier(orgUri)); + } urlConn.setInstanceFollowRedirects(false); urlConn.setConnectTimeout(SOCKET_TIMEOUT_MS); urlConn.setReadTimeout(SOCKET_TIMEOUT_MS); @@ -4320,10 +4390,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { urlConn.disconnect(); urlConn = null; + if (mTestingFailures) { + // Pretend no connection, this tests using http and https + result = CMP_RESULT_CODE_NO_CONNECTION; + log("isMobileOk: TESTING_FAILURES, pretend no connction"); + continue; + } + if (responseCode == 204) { // Return result = CMP_RESULT_CODE_CONNECTABLE; - log("isMobileOk: X expected responseCode=" + responseCode + log("isMobileOk: X got expected responseCode=" + responseCode + " result=" + result); return result; } else { @@ -4337,12 +4414,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { result = CMP_RESULT_CODE_REDIRECTED; } } catch (Exception e) { - log("isMobileOk: HttpURLConnection Exception e=" + e); + log("isMobileOk: HttpURLConnection Exception" + e); result = CMP_RESULT_CODE_NO_TCP_CONNECTION; if (urlConn != null) { urlConn.disconnect(); urlConn = null; } + sleep(NET_ERROR_SLEEP_SEC); + continue; } } log("isMobileOk: X loops|timed out result=" + result); @@ -4370,7 +4449,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("isMobileOk: connected ni=" + mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); } - sleep(1); + sleep(POLLING_SLEEP_SEC); continue; } } @@ -4435,7 +4514,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void log(String s) { + private static void log(String s) { Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s); } } From 49fa751ec6f7e21cd29161f4126507e2284b5509 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 4 Nov 2013 17:44:09 +0900 Subject: [PATCH 162/296] Minor cleanups to NetdCallbackReceiver.onEvent. - Clean up identical error messages. - Fix the array length check for InterfaceAddressChange. Bug: 9180552 Change-Id: Id871f481445b530c3ad749725f1548df0e3a1228 --- .../src/com/android/server/NetworkManagementServiceTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index 56dd7c40df..30d4eff3db 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -166,6 +166,9 @@ public class NetworkManagementServiceTest extends AndroidTestCase { sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0"); expectSoon(observer).addressRemoved("2001:db8::1/64", "wlan0", 1, 0); + sendMessage("614 Address removed 2001:db8::1/64 wlan0 1"); + // Not enough arguments. + sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); // Invalid code. From 97eba6ba41c86125a740f909b8ab9fd52407a691 Mon Sep 17 00:00:00 2001 From: Raj Mamadgi Date: Mon, 11 Nov 2013 13:52:58 -0800 Subject: [PATCH 163/296] Fix for the invalid Global Proxy Setting b/11598568 Adding validation for Global Proxy setting before it is being set. Proxy is validated at the boot time also to make sure the value set is valid. Change-Id: Ib93d24a80af1a329694f07c47bd81dfcc1e1b874 Signed-off-by: Raj Mamadgi --- core/java/android/net/ProxyProperties.java | 10 ++++++++++ .../com/android/server/ConnectivityService.java | 14 ++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 9c4772b90f..a4157c9225 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -115,6 +115,16 @@ public class ProxyProperties implements Parcelable { return false; } + public boolean isValid() { + try { + Proxy.validate(mHost == null ? "" : mHost, mPort == 0 ? "" : Integer.toString(mPort), + mExclusionList == null ? "" : mExclusionList); + } catch (IllegalArgumentException e) { + return false; + } + return true; + } + public java.net.Proxy makeProxy() { java.net.Proxy proxy = java.net.Proxy.NO_PROXY; if (mHost != null) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 29c546e197..b2fb2bb515 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3114,6 +3114,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { int port = 0; String exclList = ""; if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) { + if (!proxyProperties.isValid()) { + if (DBG) + log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); + return; + } mGlobalProxy = new ProxyProperties(proxyProperties); host = mGlobalProxy.getHost(); port = mGlobalProxy.getPort(); @@ -3147,6 +3152,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); if (!TextUtils.isEmpty(host)) { ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList); + if (!proxyProperties.isValid()) { + if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); + return; + } + synchronized (mProxyLock) { mGlobalProxy = proxyProperties; } @@ -3170,6 +3180,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { synchronized (mProxyLock) { if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return; if (mDefaultProxy == proxy) return; // catches repeated nulls + if (!proxy.isValid()) { + if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString()); + return; + } mDefaultProxy = proxy; if (mGlobalProxy != null) return; From 0c6544bd73ef922cf8d1ed26dc5a1c5f988dfa0c Mon Sep 17 00:00:00 2001 From: Ken Mixter Date: Thu, 7 Nov 2013 22:08:24 -0800 Subject: [PATCH 164/296] Fix NPE in ConnectivityService Could occur when requestRouteToHostAddress is called on a network with no associated tracker. Code later in the method handles this case gracefully but code introduced in JB throws an exception. Change-Id: I6c8a0e313ecbcca120aeb5dd0802a72114749aa1 --- services/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 29c546e197..10b1befdc5 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1432,9 +1432,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } NetworkStateTracker tracker = mNetTrackers[networkType]; - DetailedState netState = tracker.getNetworkInfo().getDetailedState(); + DetailedState netState = DetailedState.DISCONNECTED; + if (tracker != null) { + netState = tracker.getNetworkInfo().getDetailedState(); + } - if (tracker == null || (netState != DetailedState.CONNECTED && + if ((netState != DetailedState.CONNECTED && netState != DetailedState.CAPTIVE_PORTAL_CHECK) || tracker.isTeardownRequested()) { if (VDBG) { From f3df16221a7e5970dd2ece9220b2346622533864 Mon Sep 17 00:00:00 2001 From: Raj Mamadgi Date: Mon, 11 Nov 2013 13:52:58 -0800 Subject: [PATCH 165/296] Fix for the invalid Global Proxy Setting Adding validation for Global Proxy setting before it is being set. Proxy is validated at the boot time also to make sure the value set is valid. Signed-off-by: Raj Mamadgi bug:11598568 Change-Id: Idff5ae81119d8143da096b5291ecbfbc5875cbd4 --- core/java/android/net/ProxyProperties.java | 11 +++++++++++ .../com/android/server/ConnectivityService.java | 14 ++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 78ac75f22c..010e527707 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -139,6 +139,17 @@ public class ProxyProperties implements Parcelable { return false; } + public boolean isValid() { + if (!TextUtils.isEmpty(mPacFileUrl)) return true; + try { + Proxy.validate(mHost == null ? "" : mHost, mPort == 0 ? "" : Integer.toString(mPort), + mExclusionList == null ? "" : mExclusionList); + } catch (IllegalArgumentException e) { + return false; + } + return true; + } + public java.net.Proxy makeProxy() { java.net.Proxy proxy = java.net.Proxy.NO_PROXY; if (mHost != null) { diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 594f6831be..478f8c7676 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3380,6 +3380,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { String pacFileUrl = ""; if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) || !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) { + if (!proxyProperties.isValid()) { + if (DBG) + log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); + return; + } mGlobalProxy = new ProxyProperties(proxyProperties); host = mGlobalProxy.getHost(); port = mGlobalProxy.getPort(); @@ -3423,6 +3428,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { proxyProperties = new ProxyProperties(host, port, exclList); } + if (!proxyProperties.isValid()) { + if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); + return; + } + synchronized (mProxyLock) { mGlobalProxy = proxyProperties; } @@ -3447,6 +3457,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { synchronized (mProxyLock) { if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return; if (mDefaultProxy == proxy) return; // catches repeated nulls + if (!proxy.isValid()) { + if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString()); + return; + } mDefaultProxy = proxy; if (mGlobalProxy != null) return; From af70f6c614e28a65f0355446e4917393c6b93703 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 31 Oct 2013 11:59:46 +0900 Subject: [PATCH 166/296] Pass DNS server info notifications to observers. These are sent if the device receives IPv6 Router Advertisements with DNS server configuration options. Currently, nothing listens to them; in a future change we will use them as IPv6 DNS servers. Bug: 9180552 Change-Id: I05000c0cd3867a68ab390102e8470b6912a9d3aa --- .../server/NetworkManagementServiceTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index 30d4eff3db..4385dcd51b 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -172,6 +172,46 @@ public class NetworkManagementServiceTest extends AndroidTestCase { sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); // Invalid code. + + /** + * DNS information broadcasts. + */ + sendMessage("615 DnsInfo servers rmnet_usb0 3600 2001:db8::1"); + expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600, + new String[]{"2001:db8::1"}); + + sendMessage("615 DnsInfo servers wlan0 14400 2001:db8::1,2001:db8::2"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400, + new String[]{"2001:db8::1", "2001:db8::2"}); + + // We don't check for negative lifetimes, only for parse errors. + sendMessage("615 DnsInfo servers wlan0 -3600 ::1"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600, + new String[]{"::1"}); + + sendMessage("615 DnsInfo servers wlan0 SIXHUNDRED ::1"); + // Non-numeric lifetime. + + sendMessage("615 DnsInfo servers wlan0 2001:db8::1"); + // Missing lifetime. + + sendMessage("615 DnsInfo servers wlan0 3600"); + // No servers. + + sendMessage("615 DnsInfo servers 3600 wlan0 2001:db8::1,2001:db8::2"); + // Non-numeric lifetime. + + sendMessage("615 DnsInfo wlan0 7200 2001:db8::1,2001:db8::2"); + // Invalid tokens. + + sendMessage("666 DnsInfo servers wlan0 5400 2001:db8::1"); + // Invalid code. + + // No syntax checking on the addresses. + sendMessage("615 DnsInfo servers wlan0 600 ,::,,foo,::1,"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", 600, + new String[]{"", "::", "", "foo", "::1"}); + // Make sure nothing else was called. verifyNoMoreInteractions(observer); } From 5654cd271f8911c9f5c63c116bde666ae316d072 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 18 Nov 2013 09:43:59 -0800 Subject: [PATCH 167/296] Fix NPE in ConnectivityService bug:11727708 Change-Id: Ia8ca9d1e23f021feaf4b772ec38d1d0e89b0cd2a --- services/java/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 478f8c7676..baff661170 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3457,7 +3457,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { synchronized (mProxyLock) { if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return; if (mDefaultProxy == proxy) return; // catches repeated nulls - if (!proxy.isValid()) { + if (proxy != null && !proxy.isValid()) { if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString()); return; } From c1455d3014f1e3e1a596fde632af2d4e78c37426 Mon Sep 17 00:00:00 2001 From: John Spurlock Date: Tue, 19 Nov 2013 16:54:46 -0500 Subject: [PATCH 168/296] Remove unused imports from frameworks/base. Change-Id: Ia1f99bd2c1105b0b0f70aa614f1f4a67b2840906 --- core/java/android/net/ConnectivityManager.java | 1 - core/java/android/net/DhcpInfo.java | 1 - core/java/android/net/NetworkConfig.java | 1 - core/java/android/net/ProxyProperties.java | 1 - services/java/com/android/server/ConnectivityService.java | 1 - 5 files changed, 5 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 0f8dc7aa07..a9b2533a38 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -25,7 +25,6 @@ import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Messenger; import android.os.RemoteException; -import android.os.ResultReceiver; import android.provider.Settings; import java.net.InetAddress; diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java index 3bede5da50..788d7d94f6 100644 --- a/core/java/android/net/DhcpInfo.java +++ b/core/java/android/net/DhcpInfo.java @@ -18,7 +18,6 @@ package android.net; import android.os.Parcelable; import android.os.Parcel; -import java.net.InetAddress; /** * A simple object for retrieving the results of a DHCP request. diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java index 5d95f41c6c..32a2cda003 100644 --- a/core/java/android/net/NetworkConfig.java +++ b/core/java/android/net/NetworkConfig.java @@ -16,7 +16,6 @@ package android.net; -import android.util.Log; import java.util.Locale; /** diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 010e527707..54fc01d736 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -22,7 +22,6 @@ import android.os.Parcelable; import android.text.TextUtils; import java.net.InetSocketAddress; -import java.net.UnknownHostException; import java.util.Locale; /** diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 4bdf992127..6574898028 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -143,7 +143,6 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.URL; -import java.net.URLConnection; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; From 8f8e9983d9c3c684800f20758188f29f217c9453 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 4 Nov 2013 17:44:09 +0900 Subject: [PATCH 169/296] Minor cleanups to NetdCallbackReceiver.onEvent. - Clean up identical error messages. - Fix the array length check for InterfaceAddressChange. [Cherry-pick of 49fa751ec6f7e21cd29161f4126507e2284b5509] Bug: 9180552 Change-Id: Id871f481445b530c3ad749725f1548df0e3a1228 --- .../src/com/android/server/NetworkManagementServiceTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index 56dd7c40df..30d4eff3db 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -166,6 +166,9 @@ public class NetworkManagementServiceTest extends AndroidTestCase { sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0"); expectSoon(observer).addressRemoved("2001:db8::1/64", "wlan0", 1, 0); + sendMessage("614 Address removed 2001:db8::1/64 wlan0 1"); + // Not enough arguments. + sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); // Invalid code. From 7d0a830d80540c9b1f40ee7d53f87bd7833bbfcc Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 31 Oct 2013 11:59:46 +0900 Subject: [PATCH 170/296] Pass DNS server info notifications to observers. These are sent if the device receives IPv6 Router Advertisements with DNS server configuration options. Currently, nothing listens to them; in a future change we will use them as IPv6 DNS servers. [Cherry-pick of af70f6c614e28a65f0355446e4917393c6b93703] Bug: 9180552 Change-Id: I05000c0cd3867a68ab390102e8470b6912a9d3aa --- .../server/NetworkManagementServiceTest.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index 30d4eff3db..4385dcd51b 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -172,6 +172,46 @@ public class NetworkManagementServiceTest extends AndroidTestCase { sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); // Invalid code. + + /** + * DNS information broadcasts. + */ + sendMessage("615 DnsInfo servers rmnet_usb0 3600 2001:db8::1"); + expectSoon(observer).interfaceDnsServerInfo("rmnet_usb0", 3600, + new String[]{"2001:db8::1"}); + + sendMessage("615 DnsInfo servers wlan0 14400 2001:db8::1,2001:db8::2"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", 14400, + new String[]{"2001:db8::1", "2001:db8::2"}); + + // We don't check for negative lifetimes, only for parse errors. + sendMessage("615 DnsInfo servers wlan0 -3600 ::1"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", -3600, + new String[]{"::1"}); + + sendMessage("615 DnsInfo servers wlan0 SIXHUNDRED ::1"); + // Non-numeric lifetime. + + sendMessage("615 DnsInfo servers wlan0 2001:db8::1"); + // Missing lifetime. + + sendMessage("615 DnsInfo servers wlan0 3600"); + // No servers. + + sendMessage("615 DnsInfo servers 3600 wlan0 2001:db8::1,2001:db8::2"); + // Non-numeric lifetime. + + sendMessage("615 DnsInfo wlan0 7200 2001:db8::1,2001:db8::2"); + // Invalid tokens. + + sendMessage("666 DnsInfo servers wlan0 5400 2001:db8::1"); + // Invalid code. + + // No syntax checking on the addresses. + sendMessage("615 DnsInfo servers wlan0 600 ,::,,foo,::1,"); + expectSoon(observer).interfaceDnsServerInfo("wlan0", 600, + new String[]{"", "::", "", "foo", "::1"}); + // Make sure nothing else was called. verifyNoMoreInteractions(observer); } From eb91fd778c9878e3c470332fe55f41b70b23d3d2 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sun, 17 Nov 2013 15:05:02 +0900 Subject: [PATCH 171/296] Use LinkAddress in address notifications. Currently address{Updated,Removed} pass in the address as a string such as "fe80::1/64". Use LinkAddresses instead, since that's what it is. This makes the code more robust in the unlikely case that netd passes in an invalid string. In the future we can move flags and scope into the LinkAddress itself and simplify the code further. Bug: 9180552 Change-Id: I66599f9529cf421caa7676fdd0141bb110b8589e --- .../server/NetworkManagementServiceTest.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index 4385dcd51b..a78e7b6d51 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -17,6 +17,7 @@ package com.android.server; import android.content.Context; +import android.net.LinkAddress; import android.net.LocalSocket; import android.net.LocalServerSocket; import android.os.Binder; @@ -157,19 +158,22 @@ public class NetworkManagementServiceTest extends AndroidTestCase { * IP address changes. */ sendMessage("614 Address updated fe80::1/64 wlan0 128 253"); - expectSoon(observer).addressUpdated("fe80::1/64", "wlan0", 128, 253); + expectSoon(observer).addressUpdated( + new LinkAddress("fe80::1/64"), "wlan0", 128, 253); - // There is no "added". + // There is no "added", so we take this as "removed". sendMessage("614 Address added fe80::1/64 wlan0 128 253"); - expectSoon(observer).addressRemoved("fe80::1/64", "wlan0", 128, 253); + expectSoon(observer).addressRemoved( + new LinkAddress("fe80::1/64"), "wlan0", 128, 253); sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0"); - expectSoon(observer).addressRemoved("2001:db8::1/64", "wlan0", 1, 0); + expectSoon(observer).addressRemoved( + new LinkAddress("2001:db8::1/64"), "wlan0", 1, 0); sendMessage("614 Address removed 2001:db8::1/64 wlan0 1"); // Not enough arguments. - sendMessage("666 Address added 2001:db8::1/64 wlan0 1 0"); + sendMessage("666 Address removed 2001:db8::1/64 wlan0 1 0"); // Invalid code. From ee3f442711fc8eba21f865f7d7bd5ee025deafdd Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 27 Nov 2013 15:03:10 +0900 Subject: [PATCH 172/296] Minor changes to LinkAddress. 1. Simplify the parceling code. Since the InetAddress inside a LinkAddress can never be null, we don't need to special-case the case where it is. 2. Add / update method documentation. 3. Write a unit test. Change-Id: Iba0a8cecc683d55d736419965e72ee33dd66dc22 --- core/java/android/net/LinkAddress.java | 53 +++-- .../src/android/net/LinkAddressTest.java | 213 ++++++++++++++++++ 2 files changed, 242 insertions(+), 24 deletions(-) create mode 100644 core/tests/coretests/src/android/net/LinkAddressTest.java diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index a390add89e..570b6fe5be 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -25,7 +25,7 @@ import java.net.InterfaceAddress; import java.net.UnknownHostException; /** - * Identifies an address of a network link + * Identifies an IP address on a network link. * @hide */ public class LinkAddress implements Parcelable { @@ -35,7 +35,7 @@ public class LinkAddress implements Parcelable { private InetAddress address; /** - * Network prefix length + * Prefix length. */ private int prefixLength; @@ -50,10 +50,19 @@ public class LinkAddress implements Parcelable { this.prefixLength = prefixLength; } + /** + * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length. + * @param address The IP address. + * @param prefixLength The prefix length. + */ public LinkAddress(InetAddress address, int prefixLength) { init(address, prefixLength); } + /** + * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}. + * @param interfaceAddress The interface address. + */ public LinkAddress(InterfaceAddress interfaceAddress) { init(interfaceAddress.getAddress(), interfaceAddress.getNetworkPrefixLength()); @@ -86,13 +95,13 @@ public class LinkAddress implements Parcelable { @Override public String toString() { - return (address == null ? "" : (address.getHostAddress() + "/" + prefixLength)); + return address.getHostAddress() + "/" + prefixLength; } /** * Compares this {@code LinkAddress} instance against the specified address * in {@code obj}. Two addresses are equal if their InetAddress and prefixLength - * are equal + * are equal. * * @param obj the object to be tested for equality. * @return {@code true} if both objects are equal, {@code false} otherwise. @@ -107,30 +116,30 @@ public class LinkAddress implements Parcelable { this.prefixLength == linkAddress.prefixLength; } - @Override - /* - * generate hashcode based on significant fields + /** + * Returns a hashcode for this address. */ + @Override public int hashCode() { - return ((null == address) ? 0 : address.hashCode()) + prefixLength; + return address.hashCode() + 11 * prefixLength; } /** - * Returns the InetAddress for this address. + * Returns the InetAddress of this address. */ public InetAddress getAddress() { return address; } /** - * Get network prefix length + * Returns the prefix length of this address. */ public int getNetworkPrefixLength() { return prefixLength; } /** - * Implement the Parcelable interface + * Implement the Parcelable interface. * @hide */ public int describeContents() { @@ -142,13 +151,8 @@ public class LinkAddress implements Parcelable { * @hide */ public void writeToParcel(Parcel dest, int flags) { - if (address != null) { - dest.writeByte((byte)1); - dest.writeByteArray(address.getAddress()); - dest.writeInt(prefixLength); - } else { - dest.writeByte((byte)0); - } + dest.writeByteArray(address.getAddress()); + dest.writeInt(prefixLength); } /** @@ -159,13 +163,14 @@ public class LinkAddress implements Parcelable { new Creator() { public LinkAddress createFromParcel(Parcel in) { InetAddress address = null; - int prefixLength = 0; - if (in.readByte() == 1) { - try { - address = InetAddress.getByAddress(in.createByteArray()); - prefixLength = in.readInt(); - } catch (UnknownHostException e) { } + try { + address = InetAddress.getByAddress(in.createByteArray()); + } catch (UnknownHostException e) { + // Nothing we can do here. When we call the constructor, we'll throw an + // IllegalArgumentException, because a LinkAddress can't have a null + // InetAddress. } + int prefixLength = in.readInt(); return new LinkAddress(address, prefixLength); } diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java new file mode 100644 index 0000000000..389ff4dead --- /dev/null +++ b/core/tests/coretests/src/android/net/LinkAddressTest.java @@ -0,0 +1,213 @@ +/* + * Copyright (C) 2013 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 java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import android.net.LinkAddress; +import android.os.Parcel; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +/** + * Tests for {@link LinkAddress}. + */ +public class LinkAddressTest extends AndroidTestCase { + + private static final String V4 = "192.0.2.1"; + private static final String V6 = "2001:db8::1"; + private static final InetAddress V4_ADDRESS = NetworkUtils.numericToInetAddress(V4); + private static final InetAddress V6_ADDRESS = NetworkUtils.numericToInetAddress(V6); + + public void testConstructors() throws SocketException { + LinkAddress address; + + // Valid addresses work as expected. + address = new LinkAddress(V4_ADDRESS, 25); + assertEquals(V4_ADDRESS, address.getAddress()); + assertEquals(25, address.getNetworkPrefixLength()); + + address = new LinkAddress(V6_ADDRESS, 127); + assertEquals(V6_ADDRESS, address.getAddress()); + assertEquals(127, address.getNetworkPrefixLength()); + + address = new LinkAddress(V6 + "/64"); + assertEquals(V6_ADDRESS, address.getAddress()); + assertEquals(64, address.getNetworkPrefixLength()); + + address = new LinkAddress(V4 + "/23"); + assertEquals(V4_ADDRESS, address.getAddress()); + assertEquals(23, address.getNetworkPrefixLength()); + + // InterfaceAddress doesn't have a constructor. Fetch some from an interface. + List addrs = NetworkInterface.getByName("lo").getInterfaceAddresses(); + + // We expect to find 127.0.0.1/8 and ::1/128, in any order. + LinkAddress ipv4Loopback, ipv6Loopback; + assertEquals(2, addrs.size()); + if (addrs.get(0).getAddress() instanceof Inet4Address) { + ipv4Loopback = new LinkAddress(addrs.get(0)); + ipv6Loopback = new LinkAddress(addrs.get(1)); + } else { + ipv4Loopback = new LinkAddress(addrs.get(1)); + ipv6Loopback = new LinkAddress(addrs.get(0)); + } + + assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress()); + assertEquals(8, ipv4Loopback.getNetworkPrefixLength()); + + assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress()); + assertEquals(128, ipv6Loopback.getNetworkPrefixLength()); + + // Null addresses are rejected. + try { + address = new LinkAddress(null, 24); + fail("Null InetAddress should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + + try { + address = new LinkAddress((String) null); + fail("Null string should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + + try { + address = new LinkAddress((InterfaceAddress) null); + fail("Null string should cause NullPointerException"); + } catch(NullPointerException expected) {} + + // Invalid prefix lengths are rejected. + try { + address = new LinkAddress(V4 + "/-1"); + fail("Negative IPv4 prefix length should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + + try { + address = new LinkAddress(V6 + "/-1"); + fail("Negative IPv6 prefix length should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + + try { + address = new LinkAddress(V4 + "/33"); + fail("/35 IPv4 prefix length should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + + try { + address = new LinkAddress(V6 + "/129"); + fail("/129 IPv6 prefix length should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + } + + private void assertLinkAddressesEqual(LinkAddress l1, LinkAddress l2) { + assertTrue(l1 + " unexpectedly not equal to " + l2, l1.equals(l2)); + assertTrue(l2 + " unexpectedly not equal to " + l1, l2.equals(l1)); + assertEquals(l1.hashCode(), l2.hashCode()); + } + + private void assertLinkAddressesNotEqual(LinkAddress l1, LinkAddress l2) { + assertFalse(l1 + " unexpectedly equal to " + l2, l1.equals(l2)); + assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1)); + } + + public void testEquals() { + LinkAddress l1, l2; + + l1 = new LinkAddress("2001:db8::1/64"); + l2 = new LinkAddress("2001:db8::1/64"); + assertLinkAddressesEqual(l1, l2); + + l2 = new LinkAddress("2001:db8::1/65"); + assertLinkAddressesNotEqual(l1, l2); + l2 = new LinkAddress("2001:db8::2/64"); + assertLinkAddressesNotEqual(l1, l2); + + l1 = new LinkAddress("192.0.2.1/24"); + l2 = new LinkAddress("192.0.2.1/24"); + assertLinkAddressesEqual(l1, l2); + + l2 = new LinkAddress("192.0.2.1/23"); + assertLinkAddressesNotEqual(l1, l2); + l2 = new LinkAddress("192.0.2.2/24"); + assertLinkAddressesNotEqual(l1, l2); + + // Addresses with the same start or end bytes aren't equal between families. + l1 = new LinkAddress("255.255.255.255/24"); + l2 = new LinkAddress("ffff:ffff::/24"); + assertLinkAddressesNotEqual(l1, l2); + l2 = new LinkAddress("::ffff:ffff/24"); + assertLinkAddressesNotEqual(l1, l2); + + // Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address. + // TODO: Investigate fixing this. + String addressString = V4 + "/24"; + l1 = new LinkAddress(addressString); + l2 = new LinkAddress("::ffff:" + addressString); + assertLinkAddressesEqual(l1, l2); + } + + public void testHashCode() { + LinkAddress l; + + l = new LinkAddress(V4_ADDRESS, 23); + assertEquals(-982787, l.hashCode()); + + l = new LinkAddress(V4_ADDRESS, 27); + assertEquals(-982743, l.hashCode()); + + l = new LinkAddress(V6_ADDRESS, 64); + assertEquals(1076522926, l.hashCode()); + + l = new LinkAddress(V6_ADDRESS, 128); + assertEquals(1076523630, l.hashCode()); + } + + private LinkAddress passThroughParcel(LinkAddress l) { + Parcel p = Parcel.obtain(); + LinkAddress l2 = null; + try { + l.writeToParcel(p, 0); + p.setDataPosition(0); + l2 = LinkAddress.CREATOR.createFromParcel(p); + } finally { + p.recycle(); + } + assertNotNull(l2); + return l2; + } + + private void assertParcelingIsLossless(LinkAddress l) { + LinkAddress l2 = passThroughParcel(l); + assertEquals(l, l2); + } + + public void testParceling() { + LinkAddress l; + + l = new LinkAddress(V6_ADDRESS, 64); + assertParcelingIsLossless(l); + + l = new LinkAddress(V4 + "/28"); + assertParcelingIsLossless(l); + } +} From 61b6582970aa4df996a24d202ebd43b36711bc32 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 15 Nov 2013 18:43:52 +0900 Subject: [PATCH 173/296] Add address flags and scope to LinkAddress. This is necessary so that the framework can know whether an IPv6 address is likely to be usable (i.e., if it's global scope and preferred). Also, it will simplify the address notification methods in INetworkManagementEventObserver, which currently take the address, the flags, and the scope as separate arguments. 1. Add flags and scope to the class and update the unit test. Use the IFA_F_* and RT_SCOPE_* constants defined by libcore. Since most callers don't know about flags and scope, provide constructors that default the flags to zero and determine the scope from the address. Addresses notified by the kernel will have these properly set. Make multicast addresses invalid. Update the class documentation. 2. Provide an isSameAddressAs() method that compares only the address and prefix information between two LinkAddress objects. This is necessary because an interface can't have two addresses with the same address/prefix but different flags. 3. Update LinkProperties's addLinkAddress and removeLinkAddress to identify existing addresses to add/remove using isSameAddressAs instead of implicit equals(). Specifically: - If addLinkAddress is called with an address that is already present, the existing address's flags and scope are updated. This allows, for example, an address on an interface to go from preferred to deprecated when it expires, without it having to be removed and re-added. - If removeLinkAddress is called with an address that is present but with different flags, it deletes that address instead of failing to find a match. 4. Update the INetworkManagementEventObserver address notification methods to take just a LinkAddress instead of LinkAddress, flags, and scope. While I'm at it, change the order of the arguments for consistency with the other functions in the interface. Change-Id: Id8fe0f09a7e8f6bee1ea3b52102178b689a9336e --- core/java/android/net/LinkAddress.java | 158 ++++++++++++++++-- core/java/android/net/LinkProperties.java | 60 +++++-- .../src/android/net/LinkAddressTest.java | 150 +++++++++++++++-- .../src/android/net/LinkPropertiesTest.java | 36 ++++ .../server/NetworkManagementServiceTest.java | 9 +- 5 files changed, 361 insertions(+), 52 deletions(-) diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 570b6fe5be..22543e3ef1 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -24,8 +24,32 @@ import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.UnknownHostException; +import static libcore.io.OsConstants.IFA_F_DADFAILED; +import static libcore.io.OsConstants.IFA_F_DEPRECATED; +import static libcore.io.OsConstants.IFA_F_TENTATIVE; +import static libcore.io.OsConstants.RT_SCOPE_HOST; +import static libcore.io.OsConstants.RT_SCOPE_LINK; +import static libcore.io.OsConstants.RT_SCOPE_SITE; +import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE; + /** * Identifies an IP address on a network link. + * + * A {@code LinkAddress} consists of: + *

    + *
  • An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}). + * The address must be unicast, as multicast addresses cannot be assigned to interfaces. + *
  • Address flags: A bitmask of {@code IFA_F_*} values representing properties of the address. + *
  • Address scope: An integer defining the scope in which the address is unique (e.g., + * {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}). + *
      + *

      + * When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and + * scope are optional. If they are not specified, the flags are set to zero, and the scope will be + * determined based on the IP address (e.g., link-local addresses will be created with a scope of + * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, etc.) If they are + * specified, they are not checked for validity. + * * @hide */ public class LinkAddress implements Parcelable { @@ -39,8 +63,46 @@ public class LinkAddress implements Parcelable { */ private int prefixLength; - private void init(InetAddress address, int prefixLength) { - if (address == null || prefixLength < 0 || + /** + * Address flags. A bitmask of IFA_F_* values. + */ + private int flags; + + /** + * Address scope. One of the RT_SCOPE_* constants. + */ + private int scope; + + /** + * Utility function to determines the scope of a unicast address. Per RFC 4291 section 2.5 and + * RFC 6724 section 3.2. + * @hide + */ + static int scopeForUnicastAddress(InetAddress addr) { + if (addr.isAnyLocalAddress()) { + return RT_SCOPE_HOST; + } + + if (addr.isLoopbackAddress() || addr.isLinkLocalAddress()) { + return RT_SCOPE_LINK; + } + + // isSiteLocalAddress() returns true for private IPv4 addresses, but RFC 6724 section 3.2 + // says that they are assigned global scope. + if (!(addr instanceof Inet4Address) && addr.isSiteLocalAddress()) { + return RT_SCOPE_SITE; + } + + return RT_SCOPE_UNIVERSE; + } + + /** + * Utility function for the constructors. + */ + private void init(InetAddress address, int prefixLength, int flags, int scope) { + if (address == null || + address.isMulticastAddress() || + prefixLength < 0 || ((address instanceof Inet4Address) && prefixLength > 32) || (prefixLength > 128)) { throw new IllegalArgumentException("Bad LinkAddress params " + address + @@ -48,32 +110,59 @@ public class LinkAddress implements Parcelable { } this.address = address; this.prefixLength = prefixLength; + this.flags = flags; + this.scope = scope; + } + + /** + * Constructs a new {@code LinkAddress} from an {@code InetAddress} and prefix length, with + * the specified flags and scope. Flags and scope are not checked for validity. + * @param address The IP address. + * @param prefixLength The prefix length. + */ + public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) { + init(address, prefixLength, flags, scope); } /** * Constructs a new {@code LinkAddress} from an {@code InetAddress} and a prefix length. + * The flags are set to zero and the scope is determined from the address. * @param address The IP address. * @param prefixLength The prefix length. */ public LinkAddress(InetAddress address, int prefixLength) { - init(address, prefixLength); + this(address, prefixLength, 0, 0); + this.scope = scopeForUnicastAddress(address); } /** * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}. + * The flags are set to zero and the scope is determined from the address. * @param interfaceAddress The interface address. */ public LinkAddress(InterfaceAddress interfaceAddress) { - init(interfaceAddress.getAddress(), + this(interfaceAddress.getAddress(), interfaceAddress.getNetworkPrefixLength()); } /** * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or - * "2001:db8::1/64". + * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address. * @param string The string to parse. */ public LinkAddress(String address) { + this(address, 0, 0); + this.scope = scopeForUnicastAddress(this.address); + } + + /** + * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or + * "2001:db8::1/64", with the specified flags and scope. + * @param string The string to parse. + * @param flags The address flags. + * @param scope The address scope. + */ + public LinkAddress(String address, int flags, int scope) { InetAddress inetAddress = null; int prefixLength = -1; try { @@ -90,18 +179,22 @@ public class LinkAddress implements Parcelable { throw new IllegalArgumentException("Bad LinkAddress params " + address); } - init(inetAddress, prefixLength); + init(inetAddress, prefixLength, flags, scope); } + /** + * Returns a string representation of this address, such as "192.0.2.1/24" or "2001:db8::1/64". + * The string representation does not contain the flags and scope, just the address and prefix + * length. + */ @Override public String toString() { return address.getHostAddress() + "/" + prefixLength; } /** - * Compares this {@code LinkAddress} instance against the specified address - * in {@code obj}. Two addresses are equal if their InetAddress and prefixLength - * are equal. + * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if + * their address, prefix length, flags and scope are equal. * * @param obj the object to be tested for equality. * @return {@code true} if both objects are equal, {@code false} otherwise. @@ -113,7 +206,9 @@ public class LinkAddress implements Parcelable { } LinkAddress linkAddress = (LinkAddress) obj; return this.address.equals(linkAddress.address) && - this.prefixLength == linkAddress.prefixLength; + this.prefixLength == linkAddress.prefixLength && + this.flags == linkAddress.flags && + this.scope == linkAddress.scope; } /** @@ -121,7 +216,20 @@ public class LinkAddress implements Parcelable { */ @Override public int hashCode() { - return address.hashCode() + 11 * prefixLength; + return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope; + } + + /** + * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} represent + * the same address. Two LinkAddresses represent the same address if they have the same IP + * address and prefix length, even if their properties are different. + * + * @param other the {@code LinkAddress} to compare to. + * @return {@code true} if both objects have the same address and prefix length, {@code false} + * otherwise. + */ + public boolean isSameAddressAs(LinkAddress other) { + return address.equals(other.address) && prefixLength == other.prefixLength; } /** @@ -138,6 +246,28 @@ public class LinkAddress implements Parcelable { return prefixLength; } + /** + * Returns the flags of this address. + */ + public int getFlags() { + return flags; + } + + /** + * Returns the scope of this address. + */ + public int getScope() { + return scope; + } + + /** + * Returns true if this {@code LinkAddress} is global scope and preferred. + */ + public boolean isGlobalPreferred() { + return (scope == RT_SCOPE_UNIVERSE && + (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0L); + } + /** * Implement the Parcelable interface. * @hide @@ -153,6 +283,8 @@ public class LinkAddress implements Parcelable { public void writeToParcel(Parcel dest, int flags) { dest.writeByteArray(address.getAddress()); dest.writeInt(prefixLength); + dest.writeInt(this.flags); + dest.writeInt(scope); } /** @@ -171,7 +303,9 @@ public class LinkAddress implements Parcelable { // InetAddress. } int prefixLength = in.readInt(); - return new LinkAddress(address, prefixLength); + int flags = in.readInt(); + int scope = in.readInt(); + return new LinkAddress(address, prefixLength, flags, scope); } public LinkAddress[] newArray(int size) { diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index b4d07a1ec2..4dfd3d9586 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -61,10 +61,10 @@ import java.util.Hashtable; public class LinkProperties implements Parcelable { // The interface described by the network link. private String mIfaceName; - private Collection mLinkAddresses = new ArrayList(); - private Collection mDnses = new ArrayList(); + private ArrayList mLinkAddresses = new ArrayList(); + private ArrayList mDnses = new ArrayList(); private String mDomains; - private Collection mRoutes = new ArrayList(); + private ArrayList mRoutes = new ArrayList(); private ProxyProperties mHttpProxy; private int mMtu; @@ -156,28 +156,52 @@ public class LinkProperties implements Parcelable { return addresses; } - /** - * Adds a link address if it does not exist, or update it if it does. - * @param address The {@code LinkAddress} to add. - * @return true if the address was added, false if it already existed. - */ - public boolean addLinkAddress(LinkAddress address) { - // TODO: when the LinkAddress has other attributes beyond the - // address and the prefix length, update them here. - if (address != null && !mLinkAddresses.contains(address)) { - mLinkAddresses.add(address); - return true; + private int findLinkAddressIndex(LinkAddress address) { + for (int i = 0; i < mLinkAddresses.size(); i++) { + if (mLinkAddresses.get(i).isSameAddressAs(address)) { + return i; + } } - return false; + return -1; } /** - * Removes a link address. - * @param address The {@code LinkAddress} to remove. + * Adds a link address if it does not exist, or updates it if it does. + * @param address The {@code LinkAddress} to add. + * @return true if {@code address} was added or updated, false otherwise. + */ + public boolean addLinkAddress(LinkAddress address) { + if (address == null) { + return false; + } + int i = findLinkAddressIndex(address); + if (i < 0) { + // Address was not present. Add it. + mLinkAddresses.add(address); + return true; + } else if (mLinkAddresses.get(i).equals(address)) { + // Address was present and has same properties. Do nothing. + return false; + } else { + // Address was present and has different properties. Update it. + mLinkAddresses.set(i, address); + return true; + } + } + + /** + * Removes a link address. Specifically, removes the link address, if any, for which + * {@code isSameAddressAs(toRemove)} returns true. + * @param address A {@code LinkAddress} specifying the address to remove. * @return true if the address was removed, false if it did not exist. */ public boolean removeLinkAddress(LinkAddress toRemove) { - return mLinkAddresses.remove(toRemove); + int i = findLinkAddressIndex(toRemove); + if (i >= 0) { + mLinkAddresses.remove(i); + return true; + } + return false; } /** diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java index 389ff4dead..17423be65f 100644 --- a/core/tests/coretests/src/android/net/LinkAddressTest.java +++ b/core/tests/coretests/src/android/net/LinkAddressTest.java @@ -22,6 +22,7 @@ import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.NetworkInterface; import java.net.SocketException; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -31,6 +32,14 @@ import android.os.Parcel; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; +import static libcore.io.OsConstants.IFA_F_DEPRECATED; +import static libcore.io.OsConstants.IFA_F_PERMANENT; +import static libcore.io.OsConstants.IFA_F_TENTATIVE; +import static libcore.io.OsConstants.RT_SCOPE_HOST; +import static libcore.io.OsConstants.RT_SCOPE_LINK; +import static libcore.io.OsConstants.RT_SCOPE_SITE; +import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE; + /** * Tests for {@link LinkAddress}. */ @@ -48,18 +57,27 @@ public class LinkAddressTest extends AndroidTestCase { address = new LinkAddress(V4_ADDRESS, 25); assertEquals(V4_ADDRESS, address.getAddress()); assertEquals(25, address.getNetworkPrefixLength()); + assertEquals(0, address.getFlags()); + assertEquals(RT_SCOPE_UNIVERSE, address.getScope()); address = new LinkAddress(V6_ADDRESS, 127); assertEquals(V6_ADDRESS, address.getAddress()); assertEquals(127, address.getNetworkPrefixLength()); + assertEquals(0, address.getFlags()); + assertEquals(RT_SCOPE_UNIVERSE, address.getScope()); - address = new LinkAddress(V6 + "/64"); + // Nonsensical flags/scopes or combinations thereof are acceptable. + address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK); assertEquals(V6_ADDRESS, address.getAddress()); assertEquals(64, address.getNetworkPrefixLength()); + assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags()); + assertEquals(RT_SCOPE_LINK, address.getScope()); - address = new LinkAddress(V4 + "/23"); + address = new LinkAddress(V4 + "/23", 123, 456); assertEquals(V4_ADDRESS, address.getAddress()); assertEquals(23, address.getNetworkPrefixLength()); + assertEquals(123, address.getFlags()); + assertEquals(456, address.getScope()); // InterfaceAddress doesn't have a constructor. Fetch some from an interface. List addrs = NetworkInterface.getByName("lo").getInterfaceAddresses(); @@ -88,7 +106,7 @@ public class LinkAddressTest extends AndroidTestCase { } catch(IllegalArgumentException expected) {} try { - address = new LinkAddress((String) null); + address = new LinkAddress((String) null, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); fail("Null string should cause IllegalArgumentException"); } catch(IllegalArgumentException expected) {} @@ -99,24 +117,77 @@ public class LinkAddressTest extends AndroidTestCase { // Invalid prefix lengths are rejected. try { - address = new LinkAddress(V4 + "/-1"); + address = new LinkAddress(V4_ADDRESS, -1); fail("Negative IPv4 prefix length should cause IllegalArgumentException"); } catch(IllegalArgumentException expected) {} try { - address = new LinkAddress(V6 + "/-1"); + address = new LinkAddress(V6_ADDRESS, -1); fail("Negative IPv6 prefix length should cause IllegalArgumentException"); } catch(IllegalArgumentException expected) {} try { - address = new LinkAddress(V4 + "/33"); - fail("/35 IPv4 prefix length should cause IllegalArgumentException"); + address = new LinkAddress(V4_ADDRESS, 33); + fail("/33 IPv4 prefix length should cause IllegalArgumentException"); } catch(IllegalArgumentException expected) {} try { - address = new LinkAddress(V6 + "/129"); + address = new LinkAddress(V4 + "/33", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); + fail("/33 IPv4 prefix length should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + + + try { + address = new LinkAddress(V6_ADDRESS, 129, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); fail("/129 IPv6 prefix length should cause IllegalArgumentException"); } catch(IllegalArgumentException expected) {} + + try { + address = new LinkAddress(V6 + "/129", IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); + fail("/129 IPv6 prefix length should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + + // Multicast addresses are rejected. + try { + address = new LinkAddress("224.0.0.2/32"); + fail("IPv4 multicast address should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + + try { + address = new LinkAddress("ff02::1/128"); + fail("IPv6 multicast address should cause IllegalArgumentException"); + } catch(IllegalArgumentException expected) {} + } + + public void testAddressScopes() { + assertEquals(RT_SCOPE_HOST, new LinkAddress("::/128").getScope()); + assertEquals(RT_SCOPE_HOST, new LinkAddress("0.0.0.0/32").getScope()); + + assertEquals(RT_SCOPE_LINK, new LinkAddress("::1/128").getScope()); + assertEquals(RT_SCOPE_LINK, new LinkAddress("127.0.0.5/8").getScope()); + assertEquals(RT_SCOPE_LINK, new LinkAddress("fe80::ace:d00d/64").getScope()); + assertEquals(RT_SCOPE_LINK, new LinkAddress("169.254.5.12/16").getScope()); + + assertEquals(RT_SCOPE_SITE, new LinkAddress("fec0::dead/64").getScope()); + + assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("10.1.2.3/21").getScope()); + assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("192.0.2.1/25").getScope()); + assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("2001:db8::/64").getScope()); + assertEquals(RT_SCOPE_UNIVERSE, new LinkAddress("5000::/127").getScope()); + } + + private void assertIsSameAddressAs(LinkAddress l1, LinkAddress l2) { + assertTrue(l1 + " unexpectedly does not have same address as " + l2, + l1.isSameAddressAs(l2)); + assertTrue(l2 + " unexpectedly does not have same address as " + l1, + l2.isSameAddressAs(l1)); + } + + private void assertIsNotSameAddressAs(LinkAddress l1, LinkAddress l2) { + assertFalse(l1 + " unexpectedly has same address as " + l2, + l1.isSameAddressAs(l2)); + assertFalse(l2 + " unexpectedly has same address as " + l1, + l1.isSameAddressAs(l2)); } private void assertLinkAddressesEqual(LinkAddress l1, LinkAddress l2) { @@ -130,33 +201,73 @@ public class LinkAddressTest extends AndroidTestCase { assertFalse(l2 + " unexpectedly equal to " + l1, l2.equals(l1)); } - public void testEquals() { - LinkAddress l1, l2; + public void testEqualsAndSameAddressAs() { + LinkAddress l1, l2, l3; l1 = new LinkAddress("2001:db8::1/64"); l2 = new LinkAddress("2001:db8::1/64"); assertLinkAddressesEqual(l1, l2); + assertIsSameAddressAs(l1, l2); l2 = new LinkAddress("2001:db8::1/65"); assertLinkAddressesNotEqual(l1, l2); + assertIsNotSameAddressAs(l1, l2); + l2 = new LinkAddress("2001:db8::2/64"); assertLinkAddressesNotEqual(l1, l2); + assertIsNotSameAddressAs(l1, l2); + l1 = new LinkAddress("192.0.2.1/24"); l2 = new LinkAddress("192.0.2.1/24"); assertLinkAddressesEqual(l1, l2); + assertIsSameAddressAs(l1, l2); l2 = new LinkAddress("192.0.2.1/23"); assertLinkAddressesNotEqual(l1, l2); + assertIsNotSameAddressAs(l1, l2); + l2 = new LinkAddress("192.0.2.2/24"); assertLinkAddressesNotEqual(l1, l2); + assertIsNotSameAddressAs(l1, l2); + + + // Check equals() and isSameAddressAs() on identical addresses with different flags. + l1 = new LinkAddress(V6_ADDRESS, 64); + l2 = new LinkAddress(V6_ADDRESS, 64, 0, RT_SCOPE_UNIVERSE); + assertLinkAddressesEqual(l1, l2); + assertIsSameAddressAs(l1, l2); + + l2 = new LinkAddress(V6_ADDRESS, 64, IFA_F_DEPRECATED, RT_SCOPE_UNIVERSE); + assertLinkAddressesNotEqual(l1, l2); + assertIsSameAddressAs(l1, l2); + + // Check equals() and isSameAddressAs() on identical addresses with different scope. + l1 = new LinkAddress(V4_ADDRESS, 24); + l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_UNIVERSE); + assertLinkAddressesEqual(l1, l2); + assertIsSameAddressAs(l1, l2); + + l2 = new LinkAddress(V4_ADDRESS, 24, 0, RT_SCOPE_HOST); + assertLinkAddressesNotEqual(l1, l2); + assertIsSameAddressAs(l1, l2); // Addresses with the same start or end bytes aren't equal between families. - l1 = new LinkAddress("255.255.255.255/24"); - l2 = new LinkAddress("ffff:ffff::/24"); - assertLinkAddressesNotEqual(l1, l2); - l2 = new LinkAddress("::ffff:ffff/24"); + l1 = new LinkAddress("32.1.13.184/24"); + l2 = new LinkAddress("2001:db8::1/24"); + l3 = new LinkAddress("::2001:db8/24"); + + byte[] ipv4Bytes = l1.getAddress().getAddress(); + byte[] l2FirstIPv6Bytes = Arrays.copyOf(l2.getAddress().getAddress(), 4); + byte[] l3LastIPv6Bytes = Arrays.copyOfRange(l3.getAddress().getAddress(), 12, 16); + assertTrue(Arrays.equals(ipv4Bytes, l2FirstIPv6Bytes)); + assertTrue(Arrays.equals(ipv4Bytes, l3LastIPv6Bytes)); + assertLinkAddressesNotEqual(l1, l2); + assertIsNotSameAddressAs(l1, l2); + + assertLinkAddressesNotEqual(l1, l3); + assertIsNotSameAddressAs(l1, l3); // Because we use InetAddress, an IPv4 address is equal to its IPv4-mapped address. // TODO: Investigate fixing this. @@ -164,6 +275,7 @@ public class LinkAddressTest extends AndroidTestCase { l1 = new LinkAddress(addressString); l2 = new LinkAddress("::ffff:" + addressString); assertLinkAddressesEqual(l1, l2); + assertIsSameAddressAs(l1, l2); } public void testHashCode() { @@ -172,6 +284,9 @@ public class LinkAddressTest extends AndroidTestCase { l = new LinkAddress(V4_ADDRESS, 23); assertEquals(-982787, l.hashCode()); + l = new LinkAddress(V4_ADDRESS, 23, 0, RT_SCOPE_HOST); + assertEquals(-971865, l.hashCode()); + l = new LinkAddress(V4_ADDRESS, 27); assertEquals(-982743, l.hashCode()); @@ -180,6 +295,9 @@ public class LinkAddressTest extends AndroidTestCase { l = new LinkAddress(V6_ADDRESS, 128); assertEquals(1076523630, l.hashCode()); + + l = new LinkAddress(V6_ADDRESS, 128, IFA_F_TENTATIVE, RT_SCOPE_UNIVERSE); + assertEquals(1076524846, l.hashCode()); } private LinkAddress passThroughParcel(LinkAddress l) { @@ -204,10 +322,10 @@ public class LinkAddressTest extends AndroidTestCase { public void testParceling() { LinkAddress l; - l = new LinkAddress(V6_ADDRESS, 64); + l = new LinkAddress(V6_ADDRESS, 64, 123, 456); assertParcelingIsLossless(l); - l = new LinkAddress(V4 + "/28"); + l = new LinkAddress(V4 + "/28", IFA_F_PERMANENT, RT_SCOPE_LINK); assertParcelingIsLossless(l); } } diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index e63f6b08f6..a602e07d9b 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -24,6 +24,8 @@ import junit.framework.TestCase; import java.net.InetAddress; import java.util.ArrayList; +import libcore.io.OsConstants; + public class LinkPropertiesTest extends TestCase { private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1"); private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress( @@ -341,6 +343,10 @@ public class LinkPropertiesTest extends TestCase { assertFalse(rmnet0.removeStackedLink(clat4)); } + private LinkAddress getFirstLinkAddress(LinkProperties lp) { + return lp.getLinkAddresses().iterator().next(); + } + @SmallTest public void testAddressMethods() { LinkProperties lp = new LinkProperties(); @@ -366,26 +372,56 @@ public class LinkPropertiesTest extends TestCase { // Addresses on the base link. // Check the return values of hasIPvXAddress and ensure the add/remove methods return true // iff something changes. + assertEquals(0, lp.getLinkAddresses().size()); assertTrue(lp.addLinkAddress(LINKADDRV6)); + assertEquals(1, lp.getLinkAddresses().size()); assertFalse(lp.hasIPv4Address()); assertTrue(lp.hasIPv6Address()); assertTrue(lp.removeLinkAddress(LINKADDRV6)); + assertEquals(0, lp.getLinkAddresses().size()); assertTrue(lp.addLinkAddress(LINKADDRV4)); + assertEquals(1, lp.getLinkAddresses().size()); assertTrue(lp.hasIPv4Address()); assertFalse(lp.hasIPv6Address()); assertTrue(lp.addLinkAddress(LINKADDRV6)); + assertEquals(2, lp.getLinkAddresses().size()); assertTrue(lp.hasIPv4Address()); assertTrue(lp.hasIPv6Address()); // Adding an address twice has no effect. // Removing an address that's not present has no effect. assertFalse(lp.addLinkAddress(LINKADDRV4)); + assertEquals(2, lp.getLinkAddresses().size()); assertTrue(lp.hasIPv4Address()); assertTrue(lp.removeLinkAddress(LINKADDRV4)); + assertEquals(1, lp.getLinkAddresses().size()); assertFalse(lp.hasIPv4Address()); assertFalse(lp.removeLinkAddress(LINKADDRV4)); + assertEquals(1, lp.getLinkAddresses().size()); + + // Adding an address that's already present but with different properties causes the + // existing address to be updated and returns true. + // Start with only LINKADDRV6. + assertEquals(1, lp.getLinkAddresses().size()); + assertEquals(LINKADDRV6, getFirstLinkAddress(lp)); + + // Create a LinkAddress object for the same address, but with different flags. + LinkAddress deprecated = new LinkAddress(ADDRV6, 128, + OsConstants.IFA_F_DEPRECATED, OsConstants.RT_SCOPE_UNIVERSE); + assertTrue(deprecated.isSameAddressAs(LINKADDRV6)); + assertFalse(deprecated.equals(LINKADDRV6)); + + // Check that adding it updates the existing address instead of adding a new one. + assertTrue(lp.addLinkAddress(deprecated)); + assertEquals(1, lp.getLinkAddresses().size()); + assertEquals(deprecated, getFirstLinkAddress(lp)); + assertFalse(LINKADDRV6.equals(getFirstLinkAddress(lp))); + + // Removing LINKADDRV6 removes deprecated, because removing addresses ignores properties. + assertTrue(lp.removeLinkAddress(LINKADDRV6)); + assertEquals(0, lp.getLinkAddresses().size()); } @SmallTest diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index a78e7b6d51..7a30d31daa 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -158,17 +158,14 @@ public class NetworkManagementServiceTest extends AndroidTestCase { * IP address changes. */ sendMessage("614 Address updated fe80::1/64 wlan0 128 253"); - expectSoon(observer).addressUpdated( - new LinkAddress("fe80::1/64"), "wlan0", 128, 253); + expectSoon(observer).addressUpdated("wlan0", new LinkAddress("fe80::1/64", 128, 253)); // There is no "added", so we take this as "removed". sendMessage("614 Address added fe80::1/64 wlan0 128 253"); - expectSoon(observer).addressRemoved( - new LinkAddress("fe80::1/64"), "wlan0", 128, 253); + expectSoon(observer).addressRemoved("wlan0", new LinkAddress("fe80::1/64", 128, 253)); sendMessage("614 Address removed 2001:db8::1/64 wlan0 1 0"); - expectSoon(observer).addressRemoved( - new LinkAddress("2001:db8::1/64"), "wlan0", 1, 0); + expectSoon(observer).addressRemoved("wlan0", new LinkAddress("2001:db8::1/64", 1, 0)); sendMessage("614 Address removed 2001:db8::1/64 wlan0 1"); // Not enough arguments. From 5215517c3acad4f6ae3bdb56d268b4f23aa83022 Mon Sep 17 00:00:00 2001 From: Amith Yamasani Date: Fri, 22 Nov 2013 08:25:26 -0800 Subject: [PATCH 174/296] Move some system services to separate directories Refactored the directory structure so that services can be optionally excluded. This is step 1. Will be followed by another change that makes it possible to remove services from the build. Change-Id: Ideacedfd34b5e213217ad3ff4ebb21c4a8e73f85 --- .../{ => core}/java/com/android/server/ConnectivityService.java | 0 .../java/com/android/server/connectivity/Nat464Xlat.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename services/{ => core}/java/com/android/server/ConnectivityService.java (100%) rename services/{ => core}/java/com/android/server/connectivity/Nat464Xlat.java (100%) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java similarity index 100% rename from services/java/com/android/server/ConnectivityService.java rename to services/core/java/com/android/server/ConnectivityService.java diff --git a/services/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java similarity index 100% rename from services/java/com/android/server/connectivity/Nat464Xlat.java rename to services/core/java/com/android/server/connectivity/Nat464Xlat.java From f7ec405b4dda68dbd8e80e2bf56132d76f8fd077 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 23 Jan 2014 16:03:04 -0800 Subject: [PATCH 175/296] Clean up dhcp no-op logging bug:10553167 Change-Id: I1f6feb9a44e17d45ffc9f28b37bf5690230a3ade --- .../core/java/com/android/server/ConnectivityService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6574898028..64ab3e414b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2435,9 +2435,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { "\n car=" + car); } } else { - if (DBG) { - log("handleConnectivityChange: address are the same reset per doReset" + - " linkProperty[" + netType + "]:" + + if (VDBG) { + log("handleConnectivityChange: addresses are the same reset per" + + " doReset linkProperty[" + netType + "]:" + " resetMask=" + resetMask); } } From 865b70dfcf2ae944cbe4695b7112799db1ff38a7 Mon Sep 17 00:00:00 2001 From: Hui Lu Date: Wed, 15 Jan 2014 11:05:36 -0500 Subject: [PATCH 176/296] Add proxy as another network. Change-Id: I70cb6ac5604c4f0d6a752a291c40de2445ae98bb --- core/java/android/net/ConnectivityManager.java | 14 +++++++++++--- .../com/android/server/ConnectivityService.java | 4 ++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index c78a973cee..9ae4fa2f9d 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -361,11 +361,17 @@ public class ConnectivityManager { */ public static final int TYPE_MOBILE_IA = 14; - /** {@hide} */ - public static final int MAX_RADIO_TYPE = TYPE_MOBILE_IA; + /** + * The network that uses proxy to achieve connectivity. + * {@hide} + */ + public static final int TYPE_PROXY = 16; /** {@hide} */ - public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_IA; + public static final int MAX_RADIO_TYPE = TYPE_PROXY; + + /** {@hide} */ + public static final int MAX_NETWORK_TYPE = TYPE_PROXY; /** * If you want to set the default network preference,you can directly @@ -444,6 +450,8 @@ public class ConnectivityManager { return "WIFI_P2P"; case TYPE_MOBILE_IA: return "MOBILE_IA"; + case TYPE_PROXY: + return "PROXY"; default: return Integer.toString(type); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d42ae3a945..8d158cfd8f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -26,6 +26,7 @@ import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; +import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; @@ -69,6 +70,7 @@ import android.net.NetworkState; import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; +import android.net.ProxyDataTracker; import android.net.ProxyProperties; import android.net.RouteInfo; import android.net.SamplingDataTracker; @@ -729,6 +731,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { return makeWimaxStateTracker(mContext, mTrackerHandler); case TYPE_ETHERNET: return EthernetDataTracker.getInstance(); + case TYPE_PROXY: + return new ProxyDataTracker(); default: throw new IllegalArgumentException( "Trying to create a NetworkStateTracker for an unknown radio type: " From 4deacc24200a7abc999cbdbc50e62de718bb1889 Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Wed, 15 Jan 2014 13:08:03 -0800 Subject: [PATCH 177/296] Add new RIL commands to read/write NV items and reset NV config. Add new RIL commands and generic code cleanups. The only changes required for OMA DM support are the addition of five new methods in ITelephony.aidl for reading/writing NV items and performing NV config and radio resets (requires MODIFY_PHONE_STATE), along with the new RIL request IDs in RILConstants.java. Bug: 12864208 Change-Id: I958d2571580d98a49936ef2e6822e5ac086acbe2 --- core/java/android/net/ConnectivityManager.java | 2 ++ .../com/android/server/ConnectivityService.java | 17 +++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 6ac126efd4..3a35cb9537 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -800,6 +800,8 @@ public class ConnectivityManager { * Ensure that a network route exists to deliver traffic to the specified * host via the specified network interface. An attempt to add a route that * already exists is ignored, but treated as successful. + *

      This method requires the caller to hold the permission + * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * @param networkType the type of the network over which traffic to the specified * host is to be routed * @param hostAddress the IP address of the host to which the route is desired diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 015185f819..934973064a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -169,9 +169,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; - private static final boolean VDBG = false; + private static final boolean VDBG = true; - private static final boolean LOGD_RULES = false; + private static final boolean LOGD_RULES = true; // TODO: create better separation between radio types and network types @@ -4495,11 +4495,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { * @param seconds */ private static void sleep(int seconds) { - try { - Thread.sleep(seconds * 1000); - } catch (InterruptedException e) { - e.printStackTrace(); + log("XXXXX sleeping for " + seconds + " sec"); + long stopTime = System.nanoTime() + (seconds * 1000000000); + long sleepTime; + while ((sleepTime = stopTime - System.nanoTime()) > 0) { + try { + Thread.sleep(sleepTime / 1000000); + } catch (InterruptedException ignored) { + } } + log("XXXXX returning from sleep"); } private static void log(String s) { From 19cb7dc0b1b272f7a7a44bb3d9f781f8961ad385 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 11 Feb 2014 17:18:35 -0800 Subject: [PATCH 178/296] Start tracking radio up time. We now always turn on network state tracking for mobile, and push this information down to battery stats. In battery stats we use this to both log the changes in the history and keep track of the total time the mobile radio was active. Power computation is switched over to using this information to help determine power use, which will hopefully make it more accurate (not counting inaccuracies in knowing when it actually goes down). Note yet done is aggregating this data per-uid, to better emphasize which apps are causing the radio to be up. Right now we just spread the total time across all uids weighted by the total number of packets they have sent and received. Also put in the battery stats infrastructure for bluetooth to address issue #12973036: Improve power_profile.xml Change-Id: I39d11b7ff6ae4f336f253d1cba308d8569de7e0d --- services/core/java/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 934973064a..ba08a2e88f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2352,7 +2352,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (ConnectivityManager.isNetworkTypeMobile(type)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, - 0); + 5); // Canonicalize mobile network type type = ConnectivityManager.TYPE_MOBILE; } else if (ConnectivityManager.TYPE_WIFI == type) { From 74d117f048cfe11475a679cc0b441489a491bf2a Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 11 Feb 2014 14:18:56 -0800 Subject: [PATCH 179/296] Remove SO_BINDTODEVICE from VPN protect SO_BINDTODEVICE is not needed with policy routing. SO_BINDTODEVICE was also used on the default iface which causes problems when the default iface is IPv6 only and the socket tries to connect to a IPv4 address. Bug: 12940882 Change-Id: I5b2bde0ac5459433fc5749f509072a548532f730 --- services/core/java/com/android/server/ConnectivityService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 934973064a..7056191aa7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3567,8 +3567,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int user = UserHandle.getUserId(Binder.getCallingUid()); if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) { synchronized(mVpns) { - mVpns.get(user).protect(socket, - mNetTrackers[type].getLinkProperties().getInterfaceName()); + mVpns.get(user).protect(socket); } return true; } From 71e89531710b3b17943536335e8ee1ab14dedca6 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 14 Feb 2014 13:22:34 -0800 Subject: [PATCH 180/296] Add the calling package name to requestRouteToHost The calling package name will be used to check if an application is a system application when deciding if a route should be exempt from VPN routing rules. Bug: 12937545 Change-Id: I2c09c875fe9bb9685871a0a801ddcbb32fc17405 --- core/java/android/net/ConnectivityManager.java | 7 +++++-- core/java/android/net/IConnectivityManager.aidl | 4 ++-- .../java/com/android/server/ConnectivityService.java | 9 +++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3a35cb9537..e6b9d4cac4 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -400,6 +400,8 @@ public class ConnectivityManager { private final IConnectivityManager mService; + private final String mPackageName; + /** * Tests if a given integer represents a valid network type. * @param networkType the type to be tested @@ -811,7 +813,7 @@ public class ConnectivityManager { public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { byte[] address = hostAddress.getAddress(); try { - return mService.requestRouteToHostAddress(networkType, address); + return mService.requestRouteToHostAddress(networkType, address, mPackageName); } catch (RemoteException e) { return false; } @@ -907,8 +909,9 @@ public class ConnectivityManager { /** * {@hide} */ - public ConnectivityManager(IConnectivityManager service) { + public ConnectivityManager(IConnectivityManager service, String packageName) { mService = checkNotNull(service, "missing IConnectivityManager"); + mPackageName = checkNotNull(packageName, "missing package name"); } /** {@hide} */ diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b3217eb907..381a817cd2 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -71,9 +71,9 @@ interface IConnectivityManager int stopUsingNetworkFeature(int networkType, in String feature); - boolean requestRouteToHost(int networkType, int hostAddress); + boolean requestRouteToHost(int networkType, int hostAddress, String packageName); - boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); + boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName); boolean getMobileDataEnabled(); void setMobileDataEnabled(boolean enabled); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ba08a2e88f..0b25a2f08f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1541,14 +1541,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { * desired * @return {@code true} on success, {@code false} on failure */ - public boolean requestRouteToHost(int networkType, int hostAddress) { + public boolean requestRouteToHost(int networkType, int hostAddress, String packageName) { InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); if (inetAddress == null) { return false; } - return requestRouteToHostAddress(networkType, inetAddress.getAddress()); + return requestRouteToHostAddress(networkType, inetAddress.getAddress(), packageName); } /** @@ -1560,7 +1560,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { * desired * @return {@code true} on success, {@code false} on failure */ - public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) { + public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress, + String packageName) { enforceChangePermission(); if (mProtectedNetworks.contains(networkType)) { enforceConnectivityInternalPermission(); @@ -4325,7 +4326,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Make a route to host so we check the specific interface. if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI, - hostAddr.getAddress())) { + hostAddr.getAddress(), null)) { // Wait a short time to be sure the route is established ?? log("isMobileOk:" + " wait to establish route to hostAddr=" + hostAddr); From d67d197da0f0c91ec5b0bc4c509fa72bffb8828d Mon Sep 17 00:00:00 2001 From: Patrick Tjin Date: Wed, 19 Feb 2014 11:28:08 -0800 Subject: [PATCH 181/296] Modify unexpected mtu debug message to print mtu Change-Id: Iacc78582c5e3d6b156e8e2eda25e89e0e5be6eda --- services/core/java/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ba08a2e88f..b56923fd1e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2632,7 +2632,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { final int mtu = nt.getLinkProperties().getMtu(); if (mtu < 68 || mtu > 10000) { - loge("Unexpected mtu value: " + nt); + loge("Unexpected mtu value: " + mtu + ", " + nt); return; } From 3cf7d6c69d1cf93d5f820b6c21771ba7ef6e230e Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Fri, 21 Feb 2014 12:05:20 -0800 Subject: [PATCH 182/296] ConnectivityService: add support to set TCP initial rwnd The value for the TCP initial receive window comes from, in order, kernel /proc/sys/net/ipv4/tcp_default_init_rwnd init.rc (via properties) net.tcp.default_init_rwnd properties net.tcp.default_init_rwnd gservices Settings.Global.TCP_DEFAULT_INIT_RWND Bug: 12020135 Change-Id: I0e271be19472900fa9f3bab037d53383ec014a9e --- .../java/com/android/server/ConnectivityService.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b56923fd1e..342336e1d8 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2669,6 +2669,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { } setBufferSize(bufferSizes); } + + final String defaultRwndKey = "net.tcp.default_init_rwnd"; + int defaultRwndValue = SystemProperties.getInt(defaultRwndKey, 0); + Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.TCP_DEFAULT_INIT_RWND, defaultRwndValue); + final String sysctlKey = "sys.sysctl.tcp_def_init_rwnd"; + if (rwndValue != 0) { + SystemProperties.set(sysctlKey, rwndValue.toString()); + } } /** From 7965e0a452febabbca2e6a4378bfa5e44f19d16d Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 14 Feb 2014 13:24:29 -0800 Subject: [PATCH 183/296] Only allow System apps to make VPN exempt routes requestRouteToHost will only allow system applications to make routes exempt from the VPN's routing rules. If a VPN is currently running and a non-system app requests a route it will only succeed if that host is currently covered by a VPN exempt routing rule. Otherwise it will fail. For example, if a VPN is running and the MMS network is brought online those routes will be added as VPN exempt. If an application then tries to request a route to a MMS endpoint it will succeed because the routes already exist. If an application tries to request a route to a host covered by the VPN the call will fail. Bug: 12937545 Change-Id: If7bcec91bbb96c62c8fb69748c975847e6c00b6f --- .../android/server/ConnectivityService.java | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0b25a2f08f..2b69c75a99 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -33,6 +33,7 @@ import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import android.app.AlarmManager; +import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -44,7 +45,9 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; @@ -414,6 +417,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private SettingsObserver mSettingsObserver; + private AppOpsManager mAppOpsManager; + NetworkConfig[] mNetConfigs; int mNetworksDefined; @@ -697,6 +702,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { filter = new IntentFilter(); filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); mContext.registerReceiver(mProvisioningReceiver, filter); + + mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); } /** @@ -1530,6 +1537,40 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * Check if the address falls into any of currently running VPN's route's. + */ + private boolean isAddressUnderVpn(InetAddress address) { + synchronized (mVpns) { + synchronized (mRoutesLock) { + int uid = UserHandle.getCallingUserId(); + Vpn vpn = mVpns.get(uid); + if (vpn == null) { + return false; + } + + // Check if an exemption exists for this address. + for (LinkAddress destination : mExemptAddresses) { + if (!NetworkUtils.addressTypeMatches(address, destination.getAddress())) { + continue; + } + + int prefix = destination.getNetworkPrefixLength(); + InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix); + InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(), + prefix); + + if (addrMasked.equals(destMasked)) { + return false; + } + } + + // Finally check if the address is covered by the VPN. + return vpn.isAddressCovered(address); + } + } + } + /** * @deprecated use requestRouteToHostAddress instead * @@ -1566,6 +1607,34 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mProtectedNetworks.contains(networkType)) { enforceConnectivityInternalPermission(); } + boolean exempt; + InetAddress addr; + try { + addr = InetAddress.getByAddress(hostAddress); + } catch (UnknownHostException e) { + if (DBG) log("requestRouteToHostAddress got " + e.toString()); + return false; + } + // System apps may request routes bypassing the VPN to keep other networks working. + if (Binder.getCallingUid() == Process.SYSTEM_UID) { + exempt = true; + } else { + mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); + try { + ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName, + 0); + exempt = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } catch (NameNotFoundException e) { + throw new IllegalArgumentException("Failed to find calling package details", e); + } + } + + // Non-exempt routeToHost's can only be added if the host is not covered by the VPN. + // This can be either because the VPN's routes do not cover the destination or a + // system application added an exemption that covers this destination. + if (!exempt && isAddressUnderVpn(addr)) { + return false; + } if (!ConnectivityManager.isNetworkTypeValid(networkType)) { if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType); @@ -1592,18 +1661,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } final long token = Binder.clearCallingIdentity(); try { - InetAddress addr = InetAddress.getByAddress(hostAddress); LinkProperties lp = tracker.getLinkProperties(); - boolean ok = addRouteToAddress(lp, addr, EXEMPT); + boolean ok = addRouteToAddress(lp, addr, exempt); if (DBG) log("requestRouteToHostAddress ok=" + ok); return ok; - } catch (UnknownHostException e) { - if (DBG) log("requestRouteToHostAddress got " + e.toString()); } finally { Binder.restoreCallingIdentity(token); } - if (DBG) log("requestRouteToHostAddress X bottom return false"); - return false; } private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, From 5c874c7354815797c7c45cf2e0e55c05c14b1b2f Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Thu, 6 Feb 2014 14:43:50 -0800 Subject: [PATCH 184/296] Remove unneeded new RIL command. Remove the recently added RIL_REQUEST_SET_RADIO_MODE command and update the definition of the RIL_REQUEST_NV_RESET_CONFIG parameter. Also remove some accidentally added debug log lines. Bug: 12864208 Change-Id: I6f035d6900c9fcb1427bad62057d7b4a1d3cd99c --- .../core/java/com/android/server/ConnectivityService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 97b78e533b..36907edee6 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -172,9 +172,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; - private static final boolean VDBG = true; + private static final boolean VDBG = false; - private static final boolean LOGD_RULES = true; + private static final boolean LOGD_RULES = false; // TODO: create better separation between radio types and network types @@ -4569,7 +4569,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { * @param seconds */ private static void sleep(int seconds) { - log("XXXXX sleeping for " + seconds + " sec"); long stopTime = System.nanoTime() + (seconds * 1000000000); long sleepTime; while ((sleepTime = stopTime - System.nanoTime()) > 0) { @@ -4578,7 +4577,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (InterruptedException ignored) { } } - log("XXXXX returning from sleep"); } private static void log(String s) { From 19be149de78818771293b40bf2238886200b170f Mon Sep 17 00:00:00 2001 From: Jake Hamby Date: Thu, 6 Feb 2014 14:43:50 -0800 Subject: [PATCH 185/296] Remove unneeded new RIL command. Remove the recently added RIL_REQUEST_SET_RADIO_MODE command and update the definition of the RIL_REQUEST_NV_RESET_CONFIG parameter. Also remove some accidentally added debug log lines. Bug: 12864208 Change-Id: I6f035d6900c9fcb1427bad62057d7b4a1d3cd99c --- .../core/java/com/android/server/ConnectivityService.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 342336e1d8..2afb53d7b3 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -169,9 +169,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; - private static final boolean VDBG = true; + private static final boolean VDBG = false; - private static final boolean LOGD_RULES = true; + private static final boolean LOGD_RULES = false; // TODO: create better separation between radio types and network types @@ -4504,7 +4504,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { * @param seconds */ private static void sleep(int seconds) { - log("XXXXX sleeping for " + seconds + " sec"); long stopTime = System.nanoTime() + (seconds * 1000000000); long sleepTime; while ((sleepTime = stopTime - System.nanoTime()) > 0) { @@ -4513,7 +4512,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (InterruptedException ignored) { } } - log("XXXXX returning from sleep"); } private static void log(String s) { From 2d3f03d7fb5d955cd16d4152c8767c7974ebb54e Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 7 Feb 2014 03:52:12 -0800 Subject: [PATCH 186/296] DO NOT MERGE Sanitize WifiConfigs Do this both on input from apps (giving error) and between wifi and ConnectivityService (ignoring bad data). This means removing all addresses beyond the first and all routes but the first default and the implied direct-connect routes. We do this because the user can't monitor the others (no UI), their support wasn't intended, they allow redirection of all traffic without user knowledge and they allow circumvention of legacy VPNs. This should not move forward from JB as it breaks IPv6 and K has a more resilient VPN. Bug:12663469 Change-Id: I0d92db7efc30a1bb3e5b8c6e5595bdb9793a16f2 Conflicts: core/java/android/net/LinkProperties.java services/java/com/android/server/WifiService.java wifi/java/android/net/wifi/WifiStateMachine.java --- core/java/android/net/LinkProperties.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 75f8b5948b..dc9a54f8ea 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -144,6 +144,16 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(mLinkAddresses); } + /** + * Replaces the LinkAddresses on this link with the given collection of addresses + */ + public void setLinkAddresses(Collection addresses) { + mLinkAddresses.clear(); + for (LinkAddress address: addresses) { + addLinkAddress(address); + } + } + public void addDns(InetAddress dns) { if (dns != null) mDnses.add(dns); } @@ -198,6 +208,16 @@ public class LinkProperties implements Parcelable { return routes; } + /** + * Replaces the RouteInfos on this link with the given collection of RouteInfos. + */ + public void setRoutes(Collection routes) { + mRoutes.clear(); + for (RouteInfo route : routes) { + addRoute(route); + } + } + public void setHttpProxy(ProxyProperties proxy) { mHttpProxy = proxy; } From 5ac8816d557ce1078dfe75aa7c3fa21167849bfc Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 26 Feb 2014 16:20:52 -0800 Subject: [PATCH 187/296] Hold a wake lock while dispatching network activity events. Also add new API for determining whether the current data network is active, and thus better scheduling network operations. This API is designed to not be tied to a mobile network -- regardless of the network, apps can use it to determine whether they should initiate activity or wait. On non-mobile networks, it simply always reports as the network being active. This changed involved reworking how the idle timers are done so that we only register an idle timer with the current default network. This way, we can know whether we currently expect to get callbacks about the network being active, or should just always report that it is active. (Ultimately we need to be getting this radio active data from the radio itself.) Change-Id: Iaf6cc91a960d7542a70b72f87a7db26d12c4ea8e --- .../java/android/net/ConnectivityManager.java | 101 +++++++++++++++++- .../android/server/ConnectivityService.java | 14 ++- 2 files changed, 106 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index e6b9d4cac4..5b2a29ea0c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -23,9 +23,14 @@ import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; import android.os.Binder; import android.os.Build.VERSION_CODES; +import android.os.IBinder; +import android.os.INetworkActivityListener; +import android.os.INetworkManagementService; import android.os.Messenger; import android.os.RemoteException; +import android.os.ServiceManager; import android.provider.Settings; +import android.util.ArrayMap; import java.net.InetAddress; @@ -76,7 +81,7 @@ public class ConnectivityManager { /** * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any - * applicable {@link Settings.Secure#CONNECTIVITY_CHANGE_DELAY}. + * applicable {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}. * * @hide */ @@ -402,6 +407,8 @@ public class ConnectivityManager { private final String mPackageName; + private INetworkManagementService mNMService; + /** * Tests if a given integer represents a valid network type. * @param networkType the type to be tested @@ -906,6 +913,92 @@ public class ConnectivityManager { } } + /** + * Callback for use with {@link ConnectivityManager#registerNetworkActiveListener} to + * find out when the current network has gone in to a high power state. + */ + public interface OnNetworkActiveListener { + /** + * Called on the main thread of the process to report that the current data network + * has become active, and it is now a good time to perform any pending network + * operations. Note that this listener only tells you when the network becomes + * active; if at any other time you want to know whether it is active (and thus okay + * to initiate network traffic), you can retrieve its instantaneous state with + * {@link ConnectivityManager#isNetworkActive}. + */ + public void onNetworkActive(); + } + + private INetworkManagementService getNetworkManagementService() { + synchronized (this) { + if (mNMService != null) { + return mNMService; + } + IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); + mNMService = INetworkManagementService.Stub.asInterface(b); + return mNMService; + } + } + + private final ArrayMap + mNetworkActivityListeners + = new ArrayMap(); + + /** + * Start listening to reports when the data network is active, meaning it is + * a good time to perform network traffic. Use {@link #isNetworkActive()} + * to determine the current state of the network after registering the listener. + * + * @param l The listener to be told when the network is active. + */ + public void registerNetworkActiveListener(final OnNetworkActiveListener l) { + INetworkActivityListener rl = new INetworkActivityListener.Stub() { + @Override + public void onNetworkActive() throws RemoteException { + l.onNetworkActive(); + } + }; + + try { + getNetworkManagementService().registerNetworkActivityListener(rl); + mNetworkActivityListeners.put(l, rl); + } catch (RemoteException e) { + } + } + + /** + * Remove network active listener previously registered with + * {@link #registerNetworkActiveListener}. + * + * @param l Previously registered listener. + */ + public void unregisterNetworkActiveListener(OnNetworkActiveListener l) { + INetworkActivityListener rl = mNetworkActivityListeners.get(l); + if (rl == null) { + throw new IllegalArgumentException("Listener not registered: " + l); + } + try { + getNetworkManagementService().unregisterNetworkActivityListener(rl); + } catch (RemoteException e) { + } + } + + /** + * Return whether the data network is currently active. An active network means that + * it is currently in a high power state for performing data transmission. On some + * types of networks, it may be expensive to move and stay in such a state, so it is + * more power efficient to batch network traffic together when the radio is already in + * this state. This method tells you whether right now is currently a good time to + * initiate network traffic, as the network is already active. + */ + public boolean isNetworkActive() { + try { + return getNetworkManagementService().isNetworkActive(); + } catch (RemoteException e) { + } + return false; + } + /** * {@hide} */ @@ -1021,7 +1114,7 @@ public class ConnectivityManager { /** * Check if the device allows for tethering. It may be disabled via - * {@code ro.tether.denied} system property, {@link Settings#TETHER_SUPPORTED} or + * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or * due to device configuration. * * @return a boolean - {@code true} indicating Tethering is supported. @@ -1209,7 +1302,7 @@ public class ConnectivityManager { * doing something unusual like general internal filtering this may be useful. On * a private network where the proxy is not accessible, you may break HTTP using this. * - * @param proxyProperties The a {@link ProxyProperites} object defining the new global + * @param p The a {@link ProxyProperties} object defining the new global * HTTP proxy. A {@code null} value will clear the global HTTP proxy. * *

      This method requires the call to hold the permission @@ -1362,7 +1455,7 @@ public class ConnectivityManager { /** * Supply the backend messenger for a network tracker * - * @param type NetworkType to set + * @param networkType NetworkType to set * @param messenger {@link Messenger} * {@hide} */ diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index fc3801904a..d5c2a0f40f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1986,7 +1986,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[prevNetType].setTeardownRequested(false); // Remove idletimer previously setup in {@code handleConnect} - removeDataActivityTracking(prevNetType); + if (mNetConfigs[prevNetType].isDefault()) { + removeDataActivityTracking(prevNetType); + } /* * If the disconnected network is not the active one, then don't report @@ -2318,8 +2320,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleConnect(NetworkInfo info) { final int newNetType = info.getType(); - setupDataActivityTracking(newNetType); - // snapshot isFailover, because sendConnectedBroadcast() resets it boolean isFailover = info.isFailover(); final NetworkStateTracker thisNet = mNetTrackers[newNetType]; @@ -2357,6 +2357,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } } + setupDataActivityTracking(newNetType); synchronized (ConnectivityService.this) { // have a new default network, release the transition wakelock in a second // if it's held. The second pause is to allow apps to reconnect over the @@ -2406,7 +2407,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * Setup data activity tracking for the given network interface. * * Every {@code setupDataActivityTracking} should be paired with a - * {@link removeDataActivityTracking} for cleanup. + * {@link #removeDataActivityTracking} for cleanup. */ private void setupDataActivityTracking(int type) { final NetworkStateTracker thisNet = mNetTrackers[type]; @@ -2431,7 +2432,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (timeout > 0 && iface != null) { try { - mNetd.addIdleTimer(iface, timeout, Integer.toString(type)); + mNetd.addIdleTimer(iface, timeout, type); } catch (RemoteException e) { } } @@ -2944,6 +2945,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + pw.print("Active default network: "); pw.println(getNetworkTypeName(mActiveDefaultNetwork)); + pw.println(); + pw.println("Network Requester Pids:"); pw.increaseIndent(); for (int net : mPriorityList) { From d09401fb2e6dd99ab6c9f0aef65a7c279a17070c Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 28 Feb 2014 16:44:00 -0800 Subject: [PATCH 188/296] Only apply tcp buffer sizes for default net This may mean that secondary networks have bad network settings, but currently default settings are overriden by secondary nets which seems worse. bug:13211589 Change-Id: I3ef1a17ccde05306d786729c4369a31f78b2ebcf --- .../core/java/com/android/server/ConnectivityService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index fc3801904a..1f861e7011 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2377,9 +2377,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mInetConditionChangeInFlight = false; // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); + updateNetworkSettings(thisNet); } thisNet.setTeardownRequested(false); - updateNetworkSettings(thisNet); updateMtuSizeSettings(thisNet); handleConnectivityChange(newNetType, false); sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); @@ -3082,7 +3082,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { info = (NetworkInfo) msg.obj; int type = info.getType(); - updateNetworkSettings(mNetTrackers[type]); + if (mNetConfigs[type].isDefault()) updateNetworkSettings(mNetTrackers[type]); break; } } From 6b593934d320c8293643cc8992b6012c31f29f95 Mon Sep 17 00:00:00 2001 From: Yuhao Zheng Date: Fri, 28 Feb 2014 17:22:45 -0800 Subject: [PATCH 189/296] Return detailed reason of invalid proxy settings Make Proxy.validate() return valid/invalid int code, instead of throwing exceptions. If invalid, detailed reason code is returned (currently for Settings UI use). bug: 13248097 Change-Id: Ic68d03f666f1cd63667afc311de7dc370d233901 --- core/java/android/net/ProxyProperties.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java index 54fc01d736..50f45e8b5e 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyProperties.java @@ -140,13 +140,9 @@ public class ProxyProperties implements Parcelable { public boolean isValid() { if (!TextUtils.isEmpty(mPacFileUrl)) return true; - try { - Proxy.validate(mHost == null ? "" : mHost, mPort == 0 ? "" : Integer.toString(mPort), - mExclusionList == null ? "" : mExclusionList); - } catch (IllegalArgumentException e) { - return false; - } - return true; + return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, + mPort == 0 ? "" : Integer.toString(mPort), + mExclusionList == null ? "" : mExclusionList); } public java.net.Proxy makeProxy() { From eace8d566943ab09527ee6a2bfd2e31c60840403 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 28 Feb 2014 16:44:00 -0800 Subject: [PATCH 190/296] Only apply tcp buffer sizes for default net This may mean that secondary networks have bad network settings, but currently default settings are overriden by secondary nets which seems worse. bug:13211589 Change-Id: I08d56e618208781bf6b21a88663c2b8503a4f226 --- services/java/com/android/server/ConnectivityService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index baff661170..2d0c2856f8 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2305,9 +2305,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mInetConditionChangeInFlight = false; // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); + updateNetworkSettings(thisNet); } thisNet.setTeardownRequested(false); - updateNetworkSettings(thisNet); updateMtuSizeSettings(thisNet); handleConnectivityChange(newNetType, false); sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); @@ -3034,7 +3034,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { info = (NetworkInfo) msg.obj; int type = info.getType(); - updateNetworkSettings(mNetTrackers[type]); + if (mNetConfigs[type].isDefault()) updateNetworkSettings(mNetTrackers[type]); break; } } From edf0ac7298f0c765bfdf4e57eaf66bcf70540ae7 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 14 Feb 2014 13:22:34 -0800 Subject: [PATCH 191/296] Add the calling package name to requestRouteToHost The calling package name will be used to check if an application is a system application when deciding if a route should be exempt from VPN routing rules. Bug: 12937545 Change-Id: I2c09c875fe9bb9685871a0a801ddcbb32fc17405 --- core/java/android/net/ConnectivityManager.java | 7 +++++-- core/java/android/net/IConnectivityManager.aidl | 4 ++-- .../java/com/android/server/ConnectivityService.java | 9 +++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index c78a973cee..70c8750623 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -395,6 +395,8 @@ public class ConnectivityManager { private final IConnectivityManager mService; + private final String mPackageName; + /** * Tests if a given integer represents a valid network type. * @param networkType the type to be tested @@ -802,7 +804,7 @@ public class ConnectivityManager { public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { byte[] address = hostAddress.getAddress(); try { - return mService.requestRouteToHostAddress(networkType, address); + return mService.requestRouteToHostAddress(networkType, address, mPackageName); } catch (RemoteException e) { return false; } @@ -898,8 +900,9 @@ public class ConnectivityManager { /** * {@hide} */ - public ConnectivityManager(IConnectivityManager service) { + public ConnectivityManager(IConnectivityManager service, String packageName) { mService = checkNotNull(service, "missing IConnectivityManager"); + mPackageName = checkNotNull(packageName, "missing package name"); } /** {@hide} */ diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index c1da2e32aa..4bca7fefbc 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -71,9 +71,9 @@ interface IConnectivityManager int stopUsingNetworkFeature(int networkType, in String feature); - boolean requestRouteToHost(int networkType, int hostAddress); + boolean requestRouteToHost(int networkType, int hostAddress, String packageName); - boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress); + boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName); boolean getMobileDataEnabled(); void setMobileDataEnabled(boolean enabled); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 2d0c2856f8..af6433a75b 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -1537,14 +1537,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { * desired * @return {@code true} on success, {@code false} on failure */ - public boolean requestRouteToHost(int networkType, int hostAddress) { + public boolean requestRouteToHost(int networkType, int hostAddress, String packageName) { InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); if (inetAddress == null) { return false; } - return requestRouteToHostAddress(networkType, inetAddress.getAddress()); + return requestRouteToHostAddress(networkType, inetAddress.getAddress(), packageName); } /** @@ -1556,7 +1556,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { * desired * @return {@code true} on success, {@code false} on failure */ - public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) { + public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress, + String packageName) { enforceChangePermission(); if (mProtectedNetworks.contains(networkType)) { enforceConnectivityInternalPermission(); @@ -4351,7 +4352,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Make a route to host so we check the specific interface. if (mCs.requestRouteToHostAddress(ConnectivityManager.TYPE_MOBILE_HIPRI, - hostAddr.getAddress())) { + hostAddr.getAddress(), null)) { // Wait a short time to be sure the route is established ?? log("isMobileOk:" + " wait to establish route to hostAddr=" + hostAddr); From 342cd4d21482897f7f28580c191d48385497fc2f Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Fri, 14 Feb 2014 13:24:29 -0800 Subject: [PATCH 192/296] Only allow System apps to make VPN exempt routes requestRouteToHost will only allow system applications to make routes exempt from the VPN's routing rules. If a VPN is currently running and a non-system app requests a route it will only succeed if that host is currently covered by a VPN exempt routing rule. Otherwise it will fail. For example, if a VPN is running and the MMS network is brought online those routes will be added as VPN exempt. If an application then tries to request a route to a MMS endpoint it will succeed because the routes already exist. If an application tries to request a route to a host covered by the VPN the call will fail. Bug: 12937545 Change-Id: If7bcec91bbb96c62c8fb69748c975847e6c00b6f --- .../android/server/ConnectivityService.java | 76 +++++++++++++++++-- 1 file changed, 70 insertions(+), 6 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index af6433a75b..83a3bfd05f 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -32,6 +32,7 @@ import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import android.app.AlarmManager; +import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -43,7 +44,9 @@ import android.content.Context; import android.content.ContextWrapper; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Configuration; import android.content.res.Resources; import android.database.ContentObserver; @@ -412,6 +415,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private SettingsObserver mSettingsObserver; + private AppOpsManager mAppOpsManager; + NetworkConfig[] mNetConfigs; int mNetworksDefined; @@ -695,6 +700,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { filter = new IntentFilter(); filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); mContext.registerReceiver(mProvisioningReceiver, filter); + + mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); } /** @@ -1526,6 +1533,40 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + /** + * Check if the address falls into any of currently running VPN's route's. + */ + private boolean isAddressUnderVpn(InetAddress address) { + synchronized (mVpns) { + synchronized (mRoutesLock) { + int uid = UserHandle.getCallingUserId(); + Vpn vpn = mVpns.get(uid); + if (vpn == null) { + return false; + } + + // Check if an exemption exists for this address. + for (LinkAddress destination : mExemptAddresses) { + if (!NetworkUtils.addressTypeMatches(address, destination.getAddress())) { + continue; + } + + int prefix = destination.getNetworkPrefixLength(); + InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix); + InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(), + prefix); + + if (addrMasked.equals(destMasked)) { + return false; + } + } + + // Finally check if the address is covered by the VPN. + return vpn.isAddressCovered(address); + } + } + } + /** * @deprecated use requestRouteToHostAddress instead * @@ -1562,6 +1603,34 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mProtectedNetworks.contains(networkType)) { enforceConnectivityInternalPermission(); } + boolean exempt; + InetAddress addr; + try { + addr = InetAddress.getByAddress(hostAddress); + } catch (UnknownHostException e) { + if (DBG) log("requestRouteToHostAddress got " + e.toString()); + return false; + } + // System apps may request routes bypassing the VPN to keep other networks working. + if (Binder.getCallingUid() == Process.SYSTEM_UID) { + exempt = true; + } else { + mAppOpsManager.checkPackage(Binder.getCallingUid(), packageName); + try { + ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(packageName, + 0); + exempt = (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } catch (NameNotFoundException e) { + throw new IllegalArgumentException("Failed to find calling package details", e); + } + } + + // Non-exempt routeToHost's can only be added if the host is not covered by the VPN. + // This can be either because the VPN's routes do not cover the destination or a + // system application added an exemption that covers this destination. + if (!exempt && isAddressUnderVpn(addr)) { + return false; + } if (!ConnectivityManager.isNetworkTypeValid(networkType)) { if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType); @@ -1585,18 +1654,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } final long token = Binder.clearCallingIdentity(); try { - InetAddress addr = InetAddress.getByAddress(hostAddress); LinkProperties lp = tracker.getLinkProperties(); - boolean ok = addRouteToAddress(lp, addr, EXEMPT); + boolean ok = addRouteToAddress(lp, addr, exempt); if (DBG) log("requestRouteToHostAddress ok=" + ok); return ok; - } catch (UnknownHostException e) { - if (DBG) log("requestRouteToHostAddress got " + e.toString()); } finally { Binder.restoreCallingIdentity(token); } - if (DBG) log("requestRouteToHostAddress X bottom return false"); - return false; } private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, From 41236f1dff1f79651b3f77058d74625b96f1d107 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Tue, 11 Feb 2014 14:18:56 -0800 Subject: [PATCH 193/296] Remove SO_BINDTODEVICE from VPN protect SO_BINDTODEVICE is not needed with policy routing. SO_BINDTODEVICE was also used on the default iface which causes problems when the default iface is IPv6 only and the socket tries to connect to a IPv4 address. Bug: 12940882 Change-Id: I5b2bde0ac5459433fc5749f509072a548532f730 --- services/java/com/android/server/ConnectivityService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 83a3bfd05f..df2fd5ef65 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3658,8 +3658,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int user = UserHandle.getUserId(Binder.getCallingUid()); if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) { synchronized(mVpns) { - mVpns.get(user).protect(socket, - mNetTrackers[type].getLinkProperties().getInterfaceName()); + mVpns.get(user).protect(socket); } return true; } From af3781c98312d561ecdbf8ec54803c570462fdf2 Mon Sep 17 00:00:00 2001 From: JP Abgrall Date: Fri, 21 Feb 2014 12:05:20 -0800 Subject: [PATCH 194/296] ConnectivityService: add support to set TCP initial rwnd The value for the TCP initial receive window comes from, in order, kernel /proc/sys/net/ipv4/tcp_default_init_rwnd init.rc (via properties) net.tcp.default_init_rwnd properties net.tcp.default_init_rwnd gservices Settings.Global.TCP_DEFAULT_INIT_RWND Bug: 12020135 Change-Id: I0e271be19472900fa9f3bab037d53383ec014a9e --- .../java/com/android/server/ConnectivityService.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 83a3bfd05f..6a28fd67bb 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -2757,6 +2757,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { } setBufferSize(bufferSizes); } + + final String defaultRwndKey = "net.tcp.default_init_rwnd"; + int defaultRwndValue = SystemProperties.getInt(defaultRwndKey, 0); + Integer rwndValue = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.TCP_DEFAULT_INIT_RWND, defaultRwndValue); + final String sysctlKey = "sys.sysctl.tcp_def_init_rwnd"; + if (rwndValue != 0) { + SystemProperties.set(sysctlKey, rwndValue.toString()); + } } /** From 11ca0a104d1a256dfd6378195dca59697db1f377 Mon Sep 17 00:00:00 2001 From: Chad Brubaker Date: Thu, 20 Feb 2014 14:46:33 -0800 Subject: [PATCH 195/296] Include the interface for clearDnsInterfaceForUidRange With netd allowing overlapping rules for uid range rules the interface name is needed to make sure only the correct rule is removed. Bug: 12134439 Change-Id: I94f77f154f49ca8d5f6cf49683a4473cc92c3eb7 --- services/java/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index df2fd5ef65..5c7951a55d 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3898,7 +3898,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean forwardDns) { try { mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd); - if (forwardDns) mNetd.clearDnsInterfaceForUidRange(uidStart, uidEnd); + if (forwardDns) mNetd.clearDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); } catch (RemoteException e) { } From 98fee2c93b7c721f2aa5c12093b4efe2ead35811 Mon Sep 17 00:00:00 2001 From: Wink Saville Date: Thu, 13 Mar 2014 06:54:59 -0700 Subject: [PATCH 196/296] Handle provisioning APN by turning off/on data. This is a start and two tests succeed: Tested expired AT&T SIM and waiting 15min for alarm to fire. Tested a provisioned Verizon SIM and works normally. I've NOT tested AT&T where I've properly completed the provisioning. I've NOT tested T-Mobile SIM either provisioned or not-provisioned. I've NOT tested provisioning over WiFi. I've NOT tested that WiFi <-> Mobile works I've NOT tested voice calls, SMS, MMS ... The current bug is below, but it is poorly named either it should be renamed or a new bug created. Bug: 13190133 Change-Id: I0a09f642614cd27a8655e9dae764b8999ce485b8 --- .../android/server/ConnectivityService.java | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 594f6831be..47b8b518c6 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -3975,6 +3975,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int CMP_RESULT_CODE_PROVISIONING_NETWORK = 5; + /** + * The mobile network is provisioning + */ + private static final int CMP_RESULT_CODE_IS_PROVISIONING = 6; + + private AtomicBoolean mIsProvisioningNetwork = new AtomicBoolean(false); + private AtomicBoolean mIsStartingProvisioning = new AtomicBoolean(false); + private AtomicBoolean mIsCheckingMobileProvisioning = new AtomicBoolean(false); @Override @@ -4045,11 +4053,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { setProvNotificationVisible(true, ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(), url); + // Mark that we've got a provisioning network and + // Disable Mobile Data until user actually starts provisioning. + mIsProvisioningNetwork.set(true); + MobileDataStateTracker mdst = (MobileDataStateTracker) + mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.setInternalDataEnable(false); } else { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); } break; } + case CMP_RESULT_CODE_IS_PROVISIONING: { + // FIXME: Need to know when provisioning is done. Probably we can + // check the completion status if successful we're done if we + // "timedout" or still connected to provisioning APN turn off data? + if (DBG) log("CheckMp.onComplete: provisioning started"); + mIsStartingProvisioning.set(false); + break; + } default: { loge("CheckMp.onComplete: ignore unexpected result=" + result); break; @@ -4199,6 +4221,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { return result; } + if (mCs.mIsStartingProvisioning.get()) { + result = CMP_RESULT_CODE_IS_PROVISIONING; + log("isMobileOk: X is provisioning result=" + result); + return result; + } + // See if we've already determined we've got a provisioning connection, // if so we don't need to do anything active. MobileDataStateTracker mdstDefault = (MobileDataStateTracker) @@ -4533,19 +4561,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { }; private void handleMobileProvisioningAction(String url) { - // Notication mark notification as not visible + // Mark notification as not visible setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); // If provisioning network handle as a special case, // otherwise launch browser with the intent directly. - NetworkInfo ni = getProvisioningNetworkInfo(); - if ((ni != null) && ni.isConnectedToProvisioningNetwork()) { - if (DBG) log("handleMobileProvisioningAction: on provisioning network"); + if (mIsProvisioningNetwork.get()) { + if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch"); + mIsStartingProvisioning.set(true); MobileDataStateTracker mdst = (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + mdst.setEnableFailFastMobileData(DctConstants.ENABLED); mdst.enableMobileProvisioning(url); } else { - if (DBG) log("handleMobileProvisioningAction: on default network"); + if (DBG) log("handleMobileProvisioningAction: not prov network, launch browser directly"); Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_BROWSER); newIntent.setData(Uri.parse(url)); From 29f7e0e8ca31be4ebaa8801b3cbce5d08351fc19 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Wed, 12 Mar 2014 18:42:23 -0700 Subject: [PATCH 197/296] Include elapsed realtime (nanos) of the event in the radio state change notifications. Bug: 13247811 Change-Id: I3454aa159a68b9087b4762df947b41965b5a3941 --- core/java/android/net/ConnectivityManager.java | 5 +++++ .../core/java/com/android/server/ConnectivityService.java | 7 ++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 5b2a29ea0c..3da00b176b 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -175,6 +175,11 @@ public class ConnectivityManager { * {@hide} */ public static final String EXTRA_IS_ACTIVE = "isActive"; + /** + * The lookup key for a long that contains the timestamp (nanos) of the radio state change. + * {@hide} + */ + public static final String EXTRA_REALTIME_NS = "tsNanos"; /** * Broadcast Action: The setting for background data usage has changed diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ffc748fa37..68b779c023 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1183,9 +1183,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() { @Override - public void interfaceClassDataActivityChanged(String label, boolean active) { + public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) { int deviceType = Integer.parseInt(label); - sendDataActivityBroadcast(deviceType, active); + sendDataActivityBroadcast(deviceType, active, tsNanos); } }; @@ -2169,10 +2169,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs); } - private void sendDataActivityBroadcast(int deviceType, boolean active) { + private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) { Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE); intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType); intent.putExtra(ConnectivityManager.EXTRA_IS_ACTIVE, active); + intent.putExtra(ConnectivityManager.EXTRA_REALTIME_NS, tsNanos); final long ident = Binder.clearCallingIdentity(); try { mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, From 40298930a2876e5ae8b23bec4a9187f3e0e156d1 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Tue, 18 Mar 2014 16:38:58 -0700 Subject: [PATCH 198/296] Update the tests to deal with the new timestamps in idletimer module. Change-Id: I1a8368d84ef806f1501b0a1f5e817388a1d10518 --- .../server/NetworkManagementServiceTest.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java index 7a30d31daa..0d5daa5def 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java @@ -141,14 +141,21 @@ public class NetworkManagementServiceTest extends AndroidTestCase { /** * Interface class activity. */ + sendMessage("613 IfaceClass active rmnet0"); - expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true, 0); + + sendMessage("613 IfaceClass active rmnet0 1234"); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true, 1234); sendMessage("613 IfaceClass idle eth0"); - expectSoon(observer).interfaceClassDataActivityChanged("eth0", false); + expectSoon(observer).interfaceClassDataActivityChanged("eth0", false, 0); - sendMessage("613 IfaceClass reallyactive rmnet0"); - expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", false); + sendMessage("613 IfaceClass idle eth0 1234"); + expectSoon(observer).interfaceClassDataActivityChanged("eth0", false, 1234); + + sendMessage("613 IfaceClass reallyactive rmnet0 1234"); + expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", false, 1234); sendMessage("613 InterfaceClass reallyactive rmnet0"); // Invalid group. From cdb8463420a62964a38927fd1dee01045a0cb88a Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 19 Mar 2014 14:26:28 -0700 Subject: [PATCH 199/296] Catch Netd exceptions to avoid runtime restart bug:13475636 Change-Id: If36a0051a957fc066711fe8225f8981bc07add04 --- .../core/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 68b779c023..ca1c0aee29 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2434,7 +2434,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (timeout > 0 && iface != null) { try { mNetd.addIdleTimer(iface, timeout, type); - } catch (RemoteException e) { + } catch (Exception e) { + // You shall not crash! + loge("Exception in setupDataActivityTracking " + e); } } } @@ -2451,7 +2453,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { // the call fails silently if no idletimer setup for this interface mNetd.removeIdleTimer(iface); - } catch (RemoteException e) { + } catch (Exception e) { + loge("Exception in removeDataActivityTracking " + e); } } } From 5fad0b3ae577ce7d02e76221705e57d19976e675 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 19 Mar 2014 14:26:28 -0700 Subject: [PATCH 200/296] Catch Netd exceptions to avoid runtime restart bug:13475636 Change-Id: If36a0051a957fc066711fe8225f8981bc07add04 --- .../core/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 68b779c023..ca1c0aee29 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2434,7 +2434,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (timeout > 0 && iface != null) { try { mNetd.addIdleTimer(iface, timeout, type); - } catch (RemoteException e) { + } catch (Exception e) { + // You shall not crash! + loge("Exception in setupDataActivityTracking " + e); } } } @@ -2451,7 +2453,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { // the call fails silently if no idletimer setup for this interface mNetd.removeIdleTimer(iface); - } catch (RemoteException e) { + } catch (Exception e) { + loge("Exception in removeDataActivityTracking " + e); } } } From d4f7652c2793a8221ab6951f3806e41cfd09fa71 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 7 Feb 2014 03:52:12 -0800 Subject: [PATCH 201/296] DO NOT MERGE Sanitize WifiConfigs Do this both on input from apps (giving error) and between wifi and ConnectivityService (ignoring bad data). This means removing all addresses beyond the first and all routes but the first default and the implied direct-connect routes. We do this because the user can't monitor the others (no UI), their support wasn't intended, they allow redirection of all traffic without user knowledge and they allow circumvention of legacy VPNs. This should not move forward from JB as it breaks IPv6 and K has a more resilient VPN. Bug:12663469 Change-Id: I80912cc08ffa1e4b63008c94630006cf316e7a64 --- core/java/android/net/LinkProperties.java | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 75646fdf90..bf411cccd5 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -112,6 +112,16 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(mLinkAddresses); } + /** + * Replaces the LinkAddresses on this link with the given collection of addresses + */ + public void setLinkAddresses(Collection addresses) { + mLinkAddresses.clear(); + for (LinkAddress address: addresses) { + addLinkAddress(address); + } + } + public void addDns(InetAddress dns) { if (dns != null) mDnses.add(dns); } @@ -127,6 +137,16 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(mRoutes); } + /** + * Replaces the RouteInfos on this link with the given collection of RouteInfos. + */ + public void setRoutes(Collection routes) { + mRoutes.clear(); + for (RouteInfo route : routes) { + addRoute(route); + } + } + public void setHttpProxy(ProxyProperties proxy) { mHttpProxy = proxy; } From e51d2c5ade588a9a5b612de0071b5faba29ea21e Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 10 Mar 2014 17:10:51 +0900 Subject: [PATCH 202/296] Refactor IpConfiguration from WifiConfiguration Bug: 7606609, Bug: 8687763 Change-Id: I736eb3c73a8ffc8f137a04a5ea66ee564dc2b530 --- core/java/android/net/IpConfiguration.java | 158 +++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 core/java/android/net/IpConfiguration.java diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java new file mode 100644 index 0000000000..7f835e4b7a --- /dev/null +++ b/core/java/android/net/IpConfiguration.java @@ -0,0 +1,158 @@ +/* + * 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; + +import android.net.LinkProperties; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +/** + * A class representing a configured network. + */ +public class IpConfiguration implements Parcelable { + private static final String TAG = "IpConfiguration"; + + /** + * @hide + */ + public enum IpAssignment { + /* Use statically configured IP settings. Configuration can be accessed + * with linkProperties */ + STATIC, + /* Use dynamically configured IP settigns */ + DHCP, + /* no IP details are assigned, this is used to indicate + * that any existing IP settings should be retained */ + UNASSIGNED + } + + /** + * @hide + */ + public IpAssignment ipAssignment; + + /** + * @hide + */ + public enum ProxySettings { + /* No proxy is to be used. Any existing proxy settings + * should be cleared. */ + NONE, + /* Use statically configured proxy. Configuration can be accessed + * with linkProperties */ + STATIC, + /* no proxy details are assigned, this is used to indicate + * that any existing proxy settings should be retained */ + UNASSIGNED, + /* Use a Pac based proxy. + */ + PAC + } + + /** + * @hide + */ + public ProxySettings proxySettings; + + /** + * @hide + */ + public LinkProperties linkProperties; + + public IpConfiguration() { + ipAssignment = IpAssignment.UNASSIGNED; + proxySettings = ProxySettings.UNASSIGNED; + linkProperties = new LinkProperties(); + } + + /** copy constructor {@hide} */ + public IpConfiguration(IpConfiguration source) { + if (source != null) { + ipAssignment = source.ipAssignment; + proxySettings = source.proxySettings; + linkProperties = new LinkProperties(source.linkProperties); + } + } + + public static IpConfiguration createDefaultConfiguration() { + IpConfiguration config = new IpConfiguration(); + config.ipAssignment = IpAssignment.DHCP; + config.proxySettings = ProxySettings.NONE; + return config; + } + + public void mergeFrom(IpConfiguration source) { + if (source == null) { + Log.e(TAG, "source is null"); + return; + } + + linkProperties = source.linkProperties; + if (source.ipAssignment != IpAssignment.UNASSIGNED) { + ipAssignment = source.ipAssignment; + } + if (source.proxySettings != ProxySettings.UNASSIGNED) { + proxySettings = source.proxySettings; + } + } + + @Override + public String toString() { + StringBuilder sbuf = new StringBuilder(); + sbuf.append("IP assignment: " + ipAssignment.toString()); + sbuf.append("\n"); + sbuf.append("Proxy settings: " + proxySettings.toString()); + sbuf.append("\n"); + sbuf.append(linkProperties.toString()); + sbuf.append("\n"); + + return sbuf.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(ipAssignment.name()); + dest.writeString(proxySettings.name()); + dest.writeParcelable(linkProperties, flags); + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator CREATOR = + new Creator() { + public IpConfiguration createFromParcel(Parcel in) { + IpConfiguration config = new IpConfiguration(); + config.setFromParcel(in); + return config; + } + + public IpConfiguration[] newArray(int size) { + return new IpConfiguration[size]; + } + }; + + protected void setFromParcel(Parcel in) { + ipAssignment = IpAssignment.valueOf(in.readString()); + proxySettings = ProxySettings.valueOf(in.readString()); + linkProperties = in.readParcelable(null); + } +} From 3b81925ae8c0594275918fd1f39fa0991c0bf590 Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 7 Apr 2014 17:10:22 +0900 Subject: [PATCH 203/296] Hide IpConfiguration Bug: 7606609, Bug: 8687763 Change-Id: I2970bf79ef14cb993878c1dc10c7022a716f46c5 --- core/java/android/net/IpConfiguration.java | 24 +++++----------------- 1 file changed, 5 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index 7f835e4b7a..45070b9fa3 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -23,13 +23,11 @@ import android.util.Log; /** * A class representing a configured network. + * @hide */ public class IpConfiguration implements Parcelable { private static final String TAG = "IpConfiguration"; - /** - * @hide - */ public enum IpAssignment { /* Use statically configured IP settings. Configuration can be accessed * with linkProperties */ @@ -41,14 +39,8 @@ public class IpConfiguration implements Parcelable { UNASSIGNED } - /** - * @hide - */ public IpAssignment ipAssignment; - /** - * @hide - */ public enum ProxySettings { /* No proxy is to be used. Any existing proxy settings * should be cleared. */ @@ -64,14 +56,8 @@ public class IpConfiguration implements Parcelable { PAC } - /** - * @hide - */ public ProxySettings proxySettings; - /** - * @hide - */ public LinkProperties linkProperties; public IpConfiguration() { @@ -80,7 +66,7 @@ public class IpConfiguration implements Parcelable { linkProperties = new LinkProperties(); } - /** copy constructor {@hide} */ + /** copy constructor */ public IpConfiguration(IpConfiguration source) { if (source != null) { ipAssignment = source.ipAssignment; @@ -124,19 +110,19 @@ public class IpConfiguration implements Parcelable { return sbuf.toString(); } - /** Implement the Parcelable interface {@hide} */ + /** Implement the Parcelable interface */ public int describeContents() { return 0; } - /** Implement the Parcelable interface {@hide} */ + /** Implement the Parcelable interface */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(ipAssignment.name()); dest.writeString(proxySettings.name()); dest.writeParcelable(linkProperties, flags); } - /** Implement the Parcelable interface {@hide} */ + /** Implement the Parcelable interface */ public static final Creator CREATOR = new Creator() { public IpConfiguration createFromParcel(Parcel in) { From 6a9403215a1a9af6fe68cb311154dc3bbde3f15f Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 7 Apr 2014 08:54:45 +0000 Subject: [PATCH 204/296] Revert "Hide IpConfiguration" This reverts commit 3b81925ae8c0594275918fd1f39fa0991c0bf590. Change-Id: I5728114dbd9ef37509e8ab3c942648ec92ef0c1a --- core/java/android/net/IpConfiguration.java | 24 +++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java index 45070b9fa3..7f835e4b7a 100644 --- a/core/java/android/net/IpConfiguration.java +++ b/core/java/android/net/IpConfiguration.java @@ -23,11 +23,13 @@ import android.util.Log; /** * A class representing a configured network. - * @hide */ public class IpConfiguration implements Parcelable { private static final String TAG = "IpConfiguration"; + /** + * @hide + */ public enum IpAssignment { /* Use statically configured IP settings. Configuration can be accessed * with linkProperties */ @@ -39,8 +41,14 @@ public class IpConfiguration implements Parcelable { UNASSIGNED } + /** + * @hide + */ public IpAssignment ipAssignment; + /** + * @hide + */ public enum ProxySettings { /* No proxy is to be used. Any existing proxy settings * should be cleared. */ @@ -56,8 +64,14 @@ public class IpConfiguration implements Parcelable { PAC } + /** + * @hide + */ public ProxySettings proxySettings; + /** + * @hide + */ public LinkProperties linkProperties; public IpConfiguration() { @@ -66,7 +80,7 @@ public class IpConfiguration implements Parcelable { linkProperties = new LinkProperties(); } - /** copy constructor */ + /** copy constructor {@hide} */ public IpConfiguration(IpConfiguration source) { if (source != null) { ipAssignment = source.ipAssignment; @@ -110,19 +124,19 @@ public class IpConfiguration implements Parcelable { return sbuf.toString(); } - /** Implement the Parcelable interface */ + /** Implement the Parcelable interface {@hide} */ public int describeContents() { return 0; } - /** Implement the Parcelable interface */ + /** Implement the Parcelable interface {@hide} */ public void writeToParcel(Parcel dest, int flags) { dest.writeString(ipAssignment.name()); dest.writeString(proxySettings.name()); dest.writeParcelable(linkProperties, flags); } - /** Implement the Parcelable interface */ + /** Implement the Parcelable interface {@hide} */ public static final Creator CREATOR = new Creator() { public IpConfiguration createFromParcel(Parcel in) { From 273c161b688af1fbc732a0993eddb4d1f40d168a Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 7 Apr 2014 09:01:24 +0000 Subject: [PATCH 205/296] Revert "Refactor IpConfiguration from WifiConfiguration" This reverts commit e51d2c5ade588a9a5b612de0071b5faba29ea21e. Change-Id: Ibccea84e5dc44c1b8954779660e0721b27f762d4 --- core/java/android/net/IpConfiguration.java | 158 --------------------- 1 file changed, 158 deletions(-) delete mode 100644 core/java/android/net/IpConfiguration.java diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java deleted file mode 100644 index 7f835e4b7a..0000000000 --- a/core/java/android/net/IpConfiguration.java +++ /dev/null @@ -1,158 +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; - -import android.net.LinkProperties; -import android.os.Parcel; -import android.os.Parcelable; -import android.util.Log; - -/** - * A class representing a configured network. - */ -public class IpConfiguration implements Parcelable { - private static final String TAG = "IpConfiguration"; - - /** - * @hide - */ - public enum IpAssignment { - /* Use statically configured IP settings. Configuration can be accessed - * with linkProperties */ - STATIC, - /* Use dynamically configured IP settigns */ - DHCP, - /* no IP details are assigned, this is used to indicate - * that any existing IP settings should be retained */ - UNASSIGNED - } - - /** - * @hide - */ - public IpAssignment ipAssignment; - - /** - * @hide - */ - public enum ProxySettings { - /* No proxy is to be used. Any existing proxy settings - * should be cleared. */ - NONE, - /* Use statically configured proxy. Configuration can be accessed - * with linkProperties */ - STATIC, - /* no proxy details are assigned, this is used to indicate - * that any existing proxy settings should be retained */ - UNASSIGNED, - /* Use a Pac based proxy. - */ - PAC - } - - /** - * @hide - */ - public ProxySettings proxySettings; - - /** - * @hide - */ - public LinkProperties linkProperties; - - public IpConfiguration() { - ipAssignment = IpAssignment.UNASSIGNED; - proxySettings = ProxySettings.UNASSIGNED; - linkProperties = new LinkProperties(); - } - - /** copy constructor {@hide} */ - public IpConfiguration(IpConfiguration source) { - if (source != null) { - ipAssignment = source.ipAssignment; - proxySettings = source.proxySettings; - linkProperties = new LinkProperties(source.linkProperties); - } - } - - public static IpConfiguration createDefaultConfiguration() { - IpConfiguration config = new IpConfiguration(); - config.ipAssignment = IpAssignment.DHCP; - config.proxySettings = ProxySettings.NONE; - return config; - } - - public void mergeFrom(IpConfiguration source) { - if (source == null) { - Log.e(TAG, "source is null"); - return; - } - - linkProperties = source.linkProperties; - if (source.ipAssignment != IpAssignment.UNASSIGNED) { - ipAssignment = source.ipAssignment; - } - if (source.proxySettings != ProxySettings.UNASSIGNED) { - proxySettings = source.proxySettings; - } - } - - @Override - public String toString() { - StringBuilder sbuf = new StringBuilder(); - sbuf.append("IP assignment: " + ipAssignment.toString()); - sbuf.append("\n"); - sbuf.append("Proxy settings: " + proxySettings.toString()); - sbuf.append("\n"); - sbuf.append(linkProperties.toString()); - sbuf.append("\n"); - - return sbuf.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(ipAssignment.name()); - dest.writeString(proxySettings.name()); - dest.writeParcelable(linkProperties, flags); - } - - /** Implement the Parcelable interface {@hide} */ - public static final Creator CREATOR = - new Creator() { - public IpConfiguration createFromParcel(Parcel in) { - IpConfiguration config = new IpConfiguration(); - config.setFromParcel(in); - return config; - } - - public IpConfiguration[] newArray(int size) { - return new IpConfiguration[size]; - } - }; - - protected void setFromParcel(Parcel in) { - ipAssignment = IpAssignment.valueOf(in.readString()); - proxySettings = ProxySettings.valueOf(in.readString()); - linkProperties = in.readParcelable(null); - } -} From 6d1b0b70aff7a7b2e3fb5cc3c3b923b92b6f1702 Mon Sep 17 00:00:00 2001 From: Christopher Lane Date: Mon, 17 Mar 2014 16:35:45 -0700 Subject: [PATCH 206/296] Add support for custom TXT records in NSD Change-Id: I8e6dc9852ad4d273c71ad6a63a7fbd28a206806d --- .../android/core/NsdServiceInfoTest.java | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 tests/CoreTests/android/core/NsdServiceInfoTest.java diff --git a/tests/CoreTests/android/core/NsdServiceInfoTest.java b/tests/CoreTests/android/core/NsdServiceInfoTest.java new file mode 100644 index 0000000000..5bf0167f1c --- /dev/null +++ b/tests/CoreTests/android/core/NsdServiceInfoTest.java @@ -0,0 +1,163 @@ +package android.core; + +import android.test.AndroidTestCase; + +import android.os.Bundle; +import android.os.Parcel; +import android.os.StrictMode; +import android.net.nsd.NsdServiceInfo; +import android.util.Log; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.net.InetAddress; +import java.net.UnknownHostException; + + +public class NsdServiceInfoTest extends AndroidTestCase { + + public final static InetAddress LOCALHOST; + static { + // Because test. + StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); + StrictMode.setThreadPolicy(policy); + + InetAddress _host = null; + try { + _host = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { } + LOCALHOST = _host; + } + + public void testLimits() throws Exception { + NsdServiceInfo info = new NsdServiceInfo(); + + // Non-ASCII keys. + boolean exceptionThrown = false; + try { + info.setAttribute("猫", "meow"); + } catch (IllegalArgumentException e) { + exceptionThrown = true; + } + assertTrue(exceptionThrown); + assertEmptyServiceInfo(info); + + // ASCII keys with '=' character. + exceptionThrown = false; + try { + info.setAttribute("kitten=", "meow"); + } catch (IllegalArgumentException e) { + exceptionThrown = true; + } + assertTrue(exceptionThrown); + assertEmptyServiceInfo(info); + + // Single key + value length too long. + exceptionThrown = false; + try { + String longValue = "loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + + "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + + "oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo" + + "ooooooooooooooooooooooooooooong"; // 248 characters. + info.setAttribute("longcat", longValue); // Key + value == 255 characters. + } catch (IllegalArgumentException e) { + exceptionThrown = true; + } + assertTrue(exceptionThrown); + assertEmptyServiceInfo(info); + + // Total TXT record length too long. + exceptionThrown = false; + int recordsAdded = 0; + try { + for (int i = 100; i < 300; ++i) { + // 6 char key + 5 char value + 2 bytes overhead = 13 byte record length. + String key = String.format("key%d", i); + info.setAttribute(key, "12345"); + recordsAdded++; + } + } catch (IllegalArgumentException e) { + exceptionThrown = true; + } + assertTrue(exceptionThrown); + assertTrue(100 == recordsAdded); + assertTrue(info.getTxtRecord().length == 1300); + } + + public void testParcel() throws Exception { + NsdServiceInfo emptyInfo = new NsdServiceInfo(); + checkParcelable(emptyInfo); + + NsdServiceInfo fullInfo = new NsdServiceInfo(); + fullInfo.setServiceName("kitten"); + fullInfo.setServiceType("_kitten._tcp"); + fullInfo.setPort(4242); + fullInfo.setHost(LOCALHOST); + checkParcelable(fullInfo); + + NsdServiceInfo noHostInfo = new NsdServiceInfo(); + noHostInfo.setServiceName("kitten"); + noHostInfo.setServiceType("_kitten._tcp"); + noHostInfo.setPort(4242); + checkParcelable(noHostInfo); + + NsdServiceInfo attributedInfo = new NsdServiceInfo(); + attributedInfo.setServiceName("kitten"); + attributedInfo.setServiceType("_kitten._tcp"); + attributedInfo.setPort(4242); + attributedInfo.setHost(LOCALHOST); + attributedInfo.setAttribute("color", "pink"); + attributedInfo.setAttribute("sound", (new String("にゃあ")).getBytes("UTF-8")); + attributedInfo.setAttribute("adorable", (String) null); + attributedInfo.setAttribute("sticky", "yes"); + attributedInfo.setAttribute("siblings", new byte[] {}); + attributedInfo.setAttribute("edge cases", new byte[] {0, -1, 127, -128}); + attributedInfo.removeAttribute("sticky"); + checkParcelable(attributedInfo); + + // Sanity check that we actually wrote attributes to attributedInfo. + assertTrue(attributedInfo.getAttributes().keySet().contains("adorable")); + String sound = new String(attributedInfo.getAttributes().get("sound"), "UTF-8"); + assertTrue(sound.equals("にゃあ")); + byte[] edgeCases = attributedInfo.getAttributes().get("edge cases"); + assertTrue(Arrays.equals(edgeCases, new byte[] {0, -1, 127, -128})); + assertFalse(attributedInfo.getAttributes().keySet().contains("sticky")); + } + + public void checkParcelable(NsdServiceInfo original) { + // Write to parcel. + Parcel p = Parcel.obtain(); + Bundle writer = new Bundle(); + writer.putParcelable("test_info", original); + writer.writeToParcel(p, 0); + + // Extract from parcel. + p.setDataPosition(0); + Bundle reader = p.readBundle(); + reader.setClassLoader(NsdServiceInfo.class.getClassLoader()); + NsdServiceInfo result = reader.getParcelable("test_info"); + + // Assert equality of base fields. + assertEquality(original.getServiceName(), result.getServiceName()); + assertEquality(original.getServiceType(), result.getServiceType()); + assertEquality(original.getHost(), result.getHost()); + assertTrue(original.getPort() == result.getPort()); + + // Assert equality of attribute map. + Map originalMap = original.getAttributes(); + Map resultMap = result.getAttributes(); + assertEquality(originalMap.keySet(), resultMap.keySet()); + for (String key : originalMap.keySet()) { + assertTrue(Arrays.equals(originalMap.get(key), resultMap.get(key))); + } + } + + public void assertEquality(Object expected, Object result) { + assertTrue(expected == result || expected.equals(result)); + } + + public void assertEmptyServiceInfo(NsdServiceInfo shouldBeEmpty) { + assertTrue(null == shouldBeEmpty.getTxtRecord()); + } +} From 8732b35f5165e57cb2396b5b8a085f4cd765d202 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Mon, 28 Apr 2014 11:11:32 -0700 Subject: [PATCH 207/296] Track libcore.os' move to android.system. (This is partial, but should cover everything in AOSP master except for the zygote.) Change-Id: I1042c99245765746a744c44e714095cb2c6cb75d --- core/java/android/net/LinkAddress.java | 14 +++++++------- .../coretests/src/android/net/LinkAddressTest.java | 14 +++++++------- .../src/android/net/LinkPropertiesTest.java | 3 +-- 3 files changed, 15 insertions(+), 16 deletions(-) diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index 22543e3ef1..a725becd74 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -24,13 +24,13 @@ import java.net.InetAddress; import java.net.InterfaceAddress; import java.net.UnknownHostException; -import static libcore.io.OsConstants.IFA_F_DADFAILED; -import static libcore.io.OsConstants.IFA_F_DEPRECATED; -import static libcore.io.OsConstants.IFA_F_TENTATIVE; -import static libcore.io.OsConstants.RT_SCOPE_HOST; -import static libcore.io.OsConstants.RT_SCOPE_LINK; -import static libcore.io.OsConstants.RT_SCOPE_SITE; -import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE; +import static android.system.OsConstants.IFA_F_DADFAILED; +import static android.system.OsConstants.IFA_F_DEPRECATED; +import static android.system.OsConstants.IFA_F_TENTATIVE; +import static android.system.OsConstants.RT_SCOPE_HOST; +import static android.system.OsConstants.RT_SCOPE_LINK; +import static android.system.OsConstants.RT_SCOPE_SITE; +import static android.system.OsConstants.RT_SCOPE_UNIVERSE; /** * Identifies an IP address on a network link. diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java index 17423be65f..bccf556486 100644 --- a/core/tests/coretests/src/android/net/LinkAddressTest.java +++ b/core/tests/coretests/src/android/net/LinkAddressTest.java @@ -32,13 +32,13 @@ import android.os.Parcel; import android.test.AndroidTestCase; import android.test.suitebuilder.annotation.SmallTest; -import static libcore.io.OsConstants.IFA_F_DEPRECATED; -import static libcore.io.OsConstants.IFA_F_PERMANENT; -import static libcore.io.OsConstants.IFA_F_TENTATIVE; -import static libcore.io.OsConstants.RT_SCOPE_HOST; -import static libcore.io.OsConstants.RT_SCOPE_LINK; -import static libcore.io.OsConstants.RT_SCOPE_SITE; -import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE; +import static android.system.OsConstants.IFA_F_DEPRECATED; +import static android.system.OsConstants.IFA_F_PERMANENT; +import static android.system.OsConstants.IFA_F_TENTATIVE; +import static android.system.OsConstants.RT_SCOPE_HOST; +import static android.system.OsConstants.RT_SCOPE_LINK; +import static android.system.OsConstants.RT_SCOPE_SITE; +import static android.system.OsConstants.RT_SCOPE_UNIVERSE; /** * Tests for {@link LinkAddress}. diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index a602e07d9b..553afe0d69 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -18,14 +18,13 @@ package android.net; import android.net.LinkProperties; import android.net.RouteInfo; +import android.system.OsConstants; import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; import java.net.InetAddress; import java.util.ArrayList; -import libcore.io.OsConstants; - public class LinkPropertiesTest extends TestCase { private static InetAddress ADDRV4 = NetworkUtils.numericToInetAddress("75.208.6.1"); private static InetAddress ADDRV6 = NetworkUtils.numericToInetAddress( From 4d5e20f87058811f2becfde1828427601a0447e4 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 25 Apr 2014 15:00:09 -0400 Subject: [PATCH 208/296] Make proxy API public Also exposed proxy-related functions that were on the ConnectivityManager. Change-Id: I9fb5f1bcc257a6198679ea1d56e18da2ec5a3b33 --- .../java/android/net/ConnectivityManager.java | 14 +- .../android/net/IConnectivityManager.aidl | 8 +- core/java/android/net/LinkProperties.java | 12 +- .../{ProxyProperties.java => ProxyInfo.java} | 176 +++++++++++++----- .../android/server/ConnectivityService.java | 40 ++-- 5 files changed, 161 insertions(+), 89 deletions(-) rename core/java/android/net/{ProxyProperties.java => ProxyInfo.java} (61%) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3da00b176b..25708ea99c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1307,14 +1307,13 @@ public class ConnectivityManager { * doing something unusual like general internal filtering this may be useful. On * a private network where the proxy is not accessible, you may break HTTP using this. * - * @param p The a {@link ProxyProperties} object defining the new global + * @param p The a {@link ProxyInfo} object defining the new global * HTTP proxy. A {@code null} value will clear the global HTTP proxy. * *

      This method requires the call to hold the permission * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. - * {@hide} */ - public void setGlobalProxy(ProxyProperties p) { + public void setGlobalProxy(ProxyInfo p) { try { mService.setGlobalProxy(p); } catch (RemoteException e) { @@ -1324,14 +1323,13 @@ public class ConnectivityManager { /** * Retrieve any network-independent global HTTP proxy. * - * @return {@link ProxyProperties} for the current global HTTP proxy or {@code null} + * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null} * if no global HTTP proxy is set. * *

      This method requires the call to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. - * {@hide} */ - public ProxyProperties getGlobalProxy() { + public ProxyInfo getGlobalProxy() { try { return mService.getGlobalProxy(); } catch (RemoteException e) { @@ -1343,14 +1341,14 @@ public class ConnectivityManager { * Get the HTTP proxy settings for the current default network. Note that * if a global proxy is set, it will override any per-network setting. * - * @return the {@link ProxyProperties} for the current HTTP proxy, or {@code null} if no + * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no * HTTP proxy is active. * *

      This method requires the call to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ - public ProxyProperties getProxy() { + public ProxyInfo getProxy() { try { return mService.getProxy(); } catch (RemoteException e) { diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 381a817cd2..d53a856b48 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -21,7 +21,7 @@ import android.net.LinkProperties; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; import android.net.NetworkState; -import android.net.ProxyProperties; +import android.net.ProxyInfo; import android.os.IBinder; import android.os.Messenger; import android.os.ParcelFileDescriptor; @@ -107,11 +107,11 @@ interface IConnectivityManager void reportInetCondition(int networkType, int percentage); - ProxyProperties getGlobalProxy(); + ProxyInfo getGlobalProxy(); - void setGlobalProxy(in ProxyProperties p); + void setGlobalProxy(in ProxyInfo p); - ProxyProperties getProxy(); + ProxyInfo getProxy(); void setDataDependency(int networkType, boolean met); diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 4dfd3d9586..2dcc544f6f 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -16,7 +16,7 @@ package android.net; -import android.net.ProxyProperties; +import android.net.ProxyInfo; import android.os.Parcelable; import android.os.Parcel; import android.text.TextUtils; @@ -65,7 +65,7 @@ public class LinkProperties implements Parcelable { private ArrayList mDnses = new ArrayList(); private String mDomains; private ArrayList mRoutes = new ArrayList(); - private ProxyProperties mHttpProxy; + private ProxyInfo mHttpProxy; private int mMtu; // Stores the properties of links that are "stacked" above this link. @@ -101,7 +101,7 @@ public class LinkProperties implements Parcelable { mDomains = source.getDomains(); for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? - null : new ProxyProperties(source.getHttpProxy()); + null : new ProxyInfo(source.getHttpProxy()); for (LinkProperties l: source.mStackedLinks.values()) { addStackedLink(l); } @@ -295,10 +295,10 @@ public class LinkProperties implements Parcelable { return routes; } - public void setHttpProxy(ProxyProperties proxy) { + public void setHttpProxy(ProxyInfo proxy) { mHttpProxy = proxy; } - public ProxyProperties getHttpProxy() { + public ProxyInfo getHttpProxy() { return mHttpProxy; } @@ -720,7 +720,7 @@ public class LinkProperties implements Parcelable { netProp.addRoute((RouteInfo)in.readParcelable(null)); } if (in.readByte() == 1) { - netProp.setHttpProxy((ProxyProperties)in.readParcelable(null)); + netProp.setHttpProxy((ProxyInfo)in.readParcelable(null)); } ArrayList stackedLinks = new ArrayList(); in.readList(stackedLinks, LinkProperties.class.getClassLoader()); diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyInfo.java similarity index 61% rename from core/java/android/net/ProxyProperties.java rename to core/java/android/net/ProxyInfo.java index 50f45e8b5e..b40941fe9c 100644 --- a/core/java/android/net/ProxyProperties.java +++ b/core/java/android/net/ProxyInfo.java @@ -21,14 +21,23 @@ import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import org.apache.http.client.HttpClient; + import java.net.InetSocketAddress; +import java.net.URLConnection; +import java.util.List; import java.util.Locale; /** - * A container class for the http proxy info - * @hide + * Describes a proxy configuration. + * + * Proxy configurations are already integrated within the Apache HTTP stack. + * So {@link URLConnection} and {@link HttpClient} will use them automatically. + * + * Other HTTP stacks will need to obtain the proxy info from + * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}. */ -public class ProxyProperties implements Parcelable { +public class ProxyInfo implements Parcelable { private String mHost; private int mPort; @@ -36,32 +45,82 @@ public class ProxyProperties implements Parcelable { private String[] mParsedExclusionList; private String mPacFileUrl; + /** + *@hide + */ public static final String LOCAL_EXCL_LIST = ""; + /** + *@hide + */ public static final int LOCAL_PORT = -1; + /** + *@hide + */ public static final String LOCAL_HOST = "localhost"; - public ProxyProperties(String host, int port, String exclList) { + /** + * Constructs a {@link ProxyInfo} object that points at a Direct proxy + * on the specified host and port. + */ + public static ProxyInfo buildDirectProxy(String host, int port) { + return new ProxyInfo(host, port, null); + } + + /** + * Constructs a {@link ProxyInfo} object that points at a Direct proxy + * on the specified host and port. + * + * The proxy will not be used to access any host in exclusion list, exclList. + * + * @param exclList Hosts to exclude using the proxy on connections for. These + * hosts can use wildcards such as *.example.com. + */ + public static ProxyInfo buildDirectProxy(String host, int port, List exclList) { + String[] array = exclList.toArray(new String[exclList.size()]); + return new ProxyInfo(host, port, TextUtils.join(",", array), array); + } + + /** + * Construct a {@link ProxyInfo} that will download and run the PAC script + * at the specified URL. + */ + public static ProxyInfo buildPacProxy(Uri pacUri) { + return new ProxyInfo(pacUri.toString()); + } + + /** + * Create a ProxyProperties that points at a HTTP Proxy. + * @hide + */ + public ProxyInfo(String host, int port, String exclList) { mHost = host; mPort = port; setExclusionList(exclList); } - public ProxyProperties(String pacFileUrl) { + /** + * Create a ProxyProperties that points at a PAC URL. + * @hide + */ + public ProxyInfo(String pacFileUrl) { mHost = LOCAL_HOST; mPort = LOCAL_PORT; setExclusionList(LOCAL_EXCL_LIST); mPacFileUrl = pacFileUrl; } - // Only used in PacManager after Local Proxy is bound. - public ProxyProperties(String pacFileUrl, int localProxyPort) { + /** + * Only used in PacManager after Local Proxy is bound. + * @hide + */ + public ProxyInfo(String pacFileUrl, int localProxyPort) { mHost = LOCAL_HOST; mPort = localProxyPort; setExclusionList(LOCAL_EXCL_LIST); mPacFileUrl = pacFileUrl; } - private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) { + private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) { mHost = host; mPort = port; mExclusionList = exclList; @@ -70,16 +129,22 @@ public class ProxyProperties implements Parcelable { } // copy constructor instead of clone - public ProxyProperties(ProxyProperties source) { + /** + * @hide + */ + public ProxyInfo(ProxyInfo source) { if (source != null) { mHost = source.getHost(); mPort = source.getPort(); - mPacFileUrl = source.getPacFileUrl(); - mExclusionList = source.getExclusionList(); + mPacFileUrl = source.mPacFileUrl; + mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; } } + /** + * @hide + */ public InetSocketAddress getSocketAddress() { InetSocketAddress inetSocketAddress = null; try { @@ -88,20 +153,46 @@ public class ProxyProperties implements Parcelable { return inetSocketAddress; } - public String getPacFileUrl() { - return mPacFileUrl; + /** + * Returns the URL of the current PAC script or null if there is + * no PAC script. + */ + public Uri getPacFileUrl() { + if (TextUtils.isEmpty(mPacFileUrl)) { + return null; + } + return Uri.parse(mPacFileUrl); } + /** + * When configured to use a Direct Proxy this returns the host + * of the proxy. + */ public String getHost() { return mHost; } + /** + * When configured to use a Direct Proxy this returns the port + * of the proxy + */ public int getPort() { return mPort; } - // comma separated - public String getExclusionList() { + /** + * When configured to use a Direct Proxy this returns the list + * of hosts for which the proxy is ignored. + */ + public String[] getExclusionList() { + return mParsedExclusionList; + } + + /** + * comma separated + * @hide + */ + public String getExclusionListAsString() { return mExclusionList; } @@ -111,33 +202,13 @@ public class ProxyProperties implements Parcelable { if (mExclusionList == null) { mParsedExclusionList = new String[0]; } else { - String splitExclusionList[] = exclusionList.toLowerCase(Locale.ROOT).split(","); - mParsedExclusionList = new String[splitExclusionList.length * 2]; - for (int i = 0; i < splitExclusionList.length; i++) { - String s = splitExclusionList[i].trim(); - if (s.startsWith(".")) s = s.substring(1); - mParsedExclusionList[i*2] = s; - mParsedExclusionList[(i*2)+1] = "." + s; - } + mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(","); } } - public boolean isExcluded(String url) { - if (TextUtils.isEmpty(url) || mParsedExclusionList == null || - mParsedExclusionList.length == 0) return false; - - Uri u = Uri.parse(url); - String urlDomain = u.getHost(); - if (urlDomain == null) return false; - for (int i = 0; i< mParsedExclusionList.length; i+=2) { - if (urlDomain.equals(mParsedExclusionList[i]) || - urlDomain.endsWith(mParsedExclusionList[i+1])) { - return true; - } - } - return false; - } - + /** + * @hide + */ public boolean isValid() { if (!TextUtils.isEmpty(mPacFileUrl)) return true; return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, @@ -145,6 +216,9 @@ public class ProxyProperties implements Parcelable { mExclusionList == null ? "" : mExclusionList); } + /** + * @hide + */ public java.net.Proxy makeProxy() { java.net.Proxy proxy = java.net.Proxy.NO_PROXY; if (mHost != null) { @@ -179,17 +253,17 @@ public class ProxyProperties implements Parcelable { @Override public boolean equals(Object o) { - if (!(o instanceof ProxyProperties)) return false; - ProxyProperties p = (ProxyProperties)o; + if (!(o instanceof ProxyInfo)) return false; + ProxyInfo p = (ProxyInfo)o; // If PAC URL is present in either then they must be equal. // Other parameters will only be for fall back. if (!TextUtils.isEmpty(mPacFileUrl)) { return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; } - if (!TextUtils.isEmpty(p.getPacFileUrl())) { + if (!TextUtils.isEmpty(p.mPacFileUrl)) { return false; } - if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) return false; + if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false; if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { return false; } @@ -245,15 +319,15 @@ public class ProxyProperties implements Parcelable { * Implement the Parcelable interface. * @hide */ - public static final Creator CREATOR = - new Creator() { - public ProxyProperties createFromParcel(Parcel in) { + public static final Creator CREATOR = + new Creator() { + public ProxyInfo createFromParcel(Parcel in) { String host = null; int port = 0; if (in.readByte() != 0) { String url = in.readString(); int localPort = in.readInt(); - return new ProxyProperties(url, localPort); + return new ProxyInfo(url, localPort); } if (in.readByte() != 0) { host = in.readString(); @@ -261,13 +335,13 @@ public class ProxyProperties implements Parcelable { } String exclList = in.readString(); String[] parsedExclList = in.readStringArray(); - ProxyProperties proxyProperties = - new ProxyProperties(host, port, exclList, parsedExclList); + ProxyInfo proxyProperties = + new ProxyInfo(host, port, exclList, parsedExclList); return proxyProperties; } - public ProxyProperties[] newArray(int size) { - return new ProxyProperties[size]; + public ProxyInfo[] newArray(int size) { + return new ProxyInfo[size]; } }; } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 45cdb654d6..ea03eb7a33 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -74,7 +74,7 @@ import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; import android.net.ProxyDataTracker; -import android.net.ProxyProperties; +import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.SamplingDataTracker; import android.net.Uri; @@ -406,12 +406,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { private ArrayList mInetLog; // track the current default http proxy - tell the world if we get a new one (real change) - private ProxyProperties mDefaultProxy = null; + private ProxyInfo mDefaultProxy = null; private Object mProxyLock = new Object(); private boolean mDefaultProxyDisabled = false; // track the global proxy. - private ProxyProperties mGlobalProxy = null; + private ProxyInfo mGlobalProxy = null; private PacManager mPacManager = null; @@ -3192,7 +3192,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } case EVENT_PROXY_HAS_CHANGED: { - handleApplyDefaultProxy((ProxyProperties)msg.obj); + handleApplyDefaultProxy((ProxyInfo)msg.obj); break; } } @@ -3410,19 +3410,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } - public ProxyProperties getProxy() { + public ProxyInfo getProxy() { // this information is already available as a world read/writable jvm property // so this API change wouldn't have a benifit. It also breaks the passing // of proxy info to all the JVMs. // enforceAccessPermission(); synchronized (mProxyLock) { - ProxyProperties ret = mGlobalProxy; + ProxyInfo ret = mGlobalProxy; if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy; return ret; } } - public void setGlobalProxy(ProxyProperties proxyProperties) { + public void setGlobalProxy(ProxyInfo proxyProperties) { enforceConnectivityInternalPermission(); synchronized (mProxyLock) { @@ -3435,18 +3435,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { String exclList = ""; String pacFileUrl = ""; if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) || - !TextUtils.isEmpty(proxyProperties.getPacFileUrl()))) { + (proxyProperties.getPacFileUrl() != null))) { if (!proxyProperties.isValid()) { if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); return; } - mGlobalProxy = new ProxyProperties(proxyProperties); + mGlobalProxy = new ProxyInfo(proxyProperties); host = mGlobalProxy.getHost(); port = mGlobalProxy.getPort(); - exclList = mGlobalProxy.getExclusionList(); + exclList = mGlobalProxy.getExclusionListAsString(); if (proxyProperties.getPacFileUrl() != null) { - pacFileUrl = proxyProperties.getPacFileUrl(); + pacFileUrl = proxyProperties.getPacFileUrl().toString(); } } else { mGlobalProxy = null; @@ -3478,11 +3478,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { Settings.Global.GLOBAL_HTTP_PROXY_EXCLUSION_LIST); String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC); if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) { - ProxyProperties proxyProperties; + ProxyInfo proxyProperties; if (!TextUtils.isEmpty(pacFileUrl)) { - proxyProperties = new ProxyProperties(pacFileUrl); + proxyProperties = new ProxyInfo(pacFileUrl); } else { - proxyProperties = new ProxyProperties(host, port, exclList); + proxyProperties = new ProxyInfo(host, port, exclList); } if (!proxyProperties.isValid()) { if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); @@ -3495,7 +3495,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - public ProxyProperties getGlobalProxy() { + public ProxyInfo getGlobalProxy() { // this information is already available as a world read/writable jvm property // so this API change wouldn't have a benifit. It also breaks the passing // of proxy info to all the JVMs. @@ -3505,9 +3505,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void handleApplyDefaultProxy(ProxyProperties proxy) { + private void handleApplyDefaultProxy(ProxyInfo proxy) { if (proxy != null && TextUtils.isEmpty(proxy.getHost()) - && TextUtils.isEmpty(proxy.getPacFileUrl())) { + && (proxy.getPacFileUrl() == null)) { proxy = null; } synchronized (mProxyLock) { @@ -3544,13 +3544,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } } - ProxyProperties p = new ProxyProperties(data[0], proxyPort, ""); + ProxyInfo p = new ProxyInfo(data[0], proxyPort, ""); setGlobalProxy(p); } } - private void sendProxyBroadcast(ProxyProperties proxy) { - if (proxy == null) proxy = new ProxyProperties("", 0, ""); + private void sendProxyBroadcast(ProxyInfo proxy) { + if (proxy == null) proxy = new ProxyInfo("", 0, ""); if (mPacManager.setCurrentProxyScriptUrl(proxy)) return; if (DBG) log("sending Proxy Broadcast for " + proxy); Intent intent = new Intent(Proxy.PROXY_CHANGE_ACTION); From 0adf31f4b8e57221811816fa3dadd7f5b6a88634 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Wed, 7 May 2014 18:41:13 -0400 Subject: [PATCH 209/296] Fix Docs breakage Change-Id: Idaa57d16165203ad38143e493552ddf8a1ff56e5 --- core/java/android/net/ConnectivityManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 25708ea99c..30d70434a2 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1311,7 +1311,7 @@ public class ConnectivityManager { * HTTP proxy. A {@code null} value will clear the global HTTP proxy. * *

      This method requires the call to hold the permission - * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. + * android.Manifest.permission#CONNECTIVITY_INTERNAL. */ public void setGlobalProxy(ProxyInfo p) { try { From c8b9171607e02d28c6ff10061306f2fa4a0fdfd9 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Mon, 28 Apr 2014 14:57:27 -0400 Subject: [PATCH 210/296] Fix Global Proxy when used with PAC Since PAC needs to relay the local proxy port back to the ConnectivityService it ends up calling handleApplyDefaultProxy... This works fine for PAC on WiFi, but when tested on global proxy (not currently used anywhere), it sets the mDefaultProxy. This mDefaultProxy does not get cleared when the global proxy is cleared and requires a reboot to get things cleared out. This CL adds a check to overwrite mGlobalProxy rather than mDefaultProxy in this use case. Change-Id: I92782d11e213b91f8ddda2faaf996a7252273fc3 --- .../java/com/android/server/ConnectivityService.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ea03eb7a33..dfffa8a463 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3517,6 +3517,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) log("Invalid proxy properties, ignoring: " + proxy.toString()); return; } + + // This call could be coming from the PacManager, containing the port of the local + // proxy. If this new proxy matches the global proxy then copy this proxy to the + // global (to get the correct local port), and send a broadcast. + // TODO: Switch PacManager to have its own message to send back rather than + // reusing EVENT_HAS_CHANGED_PROXY and this call to handleApplyDefaultProxy. + if ((mGlobalProxy != null) && (proxy != null) && (proxy.getPacFileUrl() != null) + && proxy.getPacFileUrl().equals(mGlobalProxy.getPacFileUrl())) { + mGlobalProxy = proxy; + sendProxyBroadcast(mGlobalProxy); + return; + } mDefaultProxy = proxy; if (mGlobalProxy != null) return; From 42a0e1ee846636a6a38cd214792ebe8bd1048cc8 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 19 Mar 2014 17:56:12 -0700 Subject: [PATCH 211/296] First pass on multinetwork framework Starting to switch netd to use NetId. Adding the Network identifying class bug:13550136 Change-Id: Ie0db4fb17c9300bfafb63329adfa02339911b33d --- .../java/android/net/ConnectivityManager.java | 5 ++ core/java/android/net/Network.java | 59 ++++++++++++++++ .../android/server/ConnectivityService.java | 68 ++++++++++++++++--- 3 files changed, 121 insertions(+), 11 deletions(-) create mode 100644 core/java/android/net/Network.java diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 30d70434a2..3e0025043a 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -408,6 +408,11 @@ public class ConnectivityManager { */ public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000; + /** + * @hide + */ + public final static int INVALID_NET_ID = 0; + private final IConnectivityManager mService; private final String mPackageName; diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java new file mode 100644 index 0000000000..f82bc22483 --- /dev/null +++ b/core/java/android/net/Network.java @@ -0,0 +1,59 @@ +/* + * 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; + +import android.os.Parcelable; +import android.os.Parcel; + + +/** + * Identifies the Network. + * @hide + */ +public class Network implements Parcelable { + + public final int netId; + + public Network(int netId) { + this.netId = netId; + } + + public Network(Network that) { + this.netId = that.netId; + } + + // implement the Parcelable interface + public int describeContents() { + return 0; + } + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(netId); + } + + public static final Creator CREATOR = + new Creator() { + public Network createFromParcel(Parcel in) { + int netId = in.readInt(); + + return new Network(netId); + } + + public Network[] newArray(int size) { + return new Network[size]; + } + }; +} diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index dfffa8a463..4ea33db475 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -65,6 +65,7 @@ import android.net.LinkProperties; import android.net.LinkProperties.CompareResult; import android.net.LinkQualityInfo; import android.net.MobileDataStateTracker; +import android.net.Network; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; @@ -165,6 +166,8 @@ import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLSession; +import static android.net.ConnectivityManager.INVALID_NET_ID; + /** * @hide */ @@ -442,6 +445,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; + private final static int MIN_NET_ID = 10; // some reserved marks + private final static int MAX_NET_ID = 65535; + private int mNextNetId = MIN_NET_ID; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -706,6 +713,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); } + private synchronized int nextNetId() { + int netId = mNextNetId; + if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID; + return netId; + } + /** * Factory that creates {@link NetworkStateTracker} instances using given * {@link NetworkConfig}. @@ -1984,6 +1997,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int prevNetType = info.getType(); mNetTrackers[prevNetType].setTeardownRequested(false); + int thisNetId = mNetTrackers[prevNetType].getNetwork().netId; // Remove idletimer previously setup in {@code handleConnect} if (mNetConfigs[prevNetType].isDefault()) { @@ -2069,6 +2083,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { sendConnectedBroadcastDelayed(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(), getConnectivityChangeDelay()); } + try { + mNetd.removeNetwork(thisNetId); + } catch (Exception e) { + loge("Exception removing network: " + e); + } finally { + mNetTrackers[prevNetType].setNetId(INVALID_NET_ID); + } } private void tryFailover(int prevNetType) { @@ -2336,17 +2357,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mNetConfigs[newNetType].isDefault()) { if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) { if (isNewNetTypePreferredOverCurrentNetType(newNetType)) { - // tear down the other - NetworkStateTracker otherNet = - mNetTrackers[mActiveDefaultNetwork]; - if (DBG) { - log("Policy requires " + otherNet.getNetworkInfo().getTypeName() + - " teardown"); - } - if (!teardown(otherNet)) { - loge("Network declined teardown request"); - teardown(thisNet); - return; + String teardownPolicy = SystemProperties.get("net.teardownPolicy"); + if (TextUtils.equals(teardownPolicy, "keep") == false) { + // tear down the other + NetworkStateTracker otherNet = + mNetTrackers[mActiveDefaultNetwork]; + if (DBG) { + log("Policy requires " + otherNet.getNetworkInfo().getTypeName() + + " teardown"); + } + if (!teardown(otherNet)) { + loge("Network declined teardown request"); + teardown(thisNet); + return; + } + } else { + //TODO - remove + loge("network teardown skipped due to net.teardownPolicy setting"); } } else { // don't accept this one @@ -2358,6 +2385,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } } + int thisNetId = nextNetId(); + thisNet.setNetId(thisNetId); + try { + mNetd.createNetwork(thisNetId, thisIface); + } catch (Exception e) { + loge("Exception creating network :" + e); + teardown(thisNet); + return; + } setupDataActivityTracking(newNetType); synchronized (ConnectivityService.this) { // have a new default network, release the transition wakelock in a second @@ -2380,6 +2416,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Don't do this - if we never sign in stay, grey //reportNetworkCondition(mActiveDefaultNetwork, 100); updateNetworkSettings(thisNet); + } else { + int thisNetId = nextNetId(); + thisNet.setNetId(thisNetId); + try { + mNetd.createNetwork(thisNetId, thisIface); + } catch (Exception e) { + loge("Exception creating network :" + e); + teardown(thisNet); + return; + } } thisNet.setTeardownRequested(false); updateMtuSizeSettings(thisNet); From 52cd9bfc48db3a1c75d31cac85925982d656ca10 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 8 Apr 2014 13:41:39 -0700 Subject: [PATCH 212/296] Add NetworkCapabilities part of API. Merging to master, adding @hide until we're ready to reveal the API change. bug:13885501 Change-Id: Ib40e28092e092630bfec557bde77f58eec8ae1c8 --- .../java/android/net/NetworkCapabilities.java | 312 ++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 core/java/android/net/NetworkCapabilities.java diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java new file mode 100644 index 0000000000..adbb185200 --- /dev/null +++ b/core/java/android/net/NetworkCapabilities.java @@ -0,0 +1,312 @@ +/* + * 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; + +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Log; + +import java.lang.IllegalArgumentException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * A class representing the capabilities of a network + * @hide + */ +public final class NetworkCapabilities implements Parcelable { + private static final String TAG = "NetworkCapabilities"; + private static final boolean DBG = false; + + + /** + * Represents the network's capabilities. If any are specified they will be satisfied + * by any Network that matches all of them. + */ + private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED); + + /** + * Values for NetworkCapabilities. Roughly matches/extends deprecated + * ConnectivityManager TYPE_* + */ + public static final int NET_CAPABILITY_MMS = 0; + public static final int NET_CAPABILITY_SUPL = 1; + public static final int NET_CAPABILITY_DUN = 2; + public static final int NET_CAPABILITY_FOTA = 3; + public static final int NET_CAPABILITY_IMS = 4; + public static final int NET_CAPABILITY_CBS = 5; + public static final int NET_CAPABILITY_WIFI_P2P = 6; + public static final int NET_CAPABILITY_IA = 7; + public static final int NET_CAPABILITY_RCS = 8; + public static final int NET_CAPABILITY_XCAP = 9; + public static final int NET_CAPABILITY_EIMS = 10; + public static final int NET_CAPABILITY_NOT_METERED = 11; + public static final int NET_CAPABILITY_INTERNET = 12; + /** Set by default */ + public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; + + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_RESTRICTED; + + public void addNetworkCapability(int networkCapability) { + if (networkCapability < MIN_NET_CAPABILITY || + networkCapability > MAX_NET_CAPABILITY) { + throw new IllegalArgumentException("NetworkCapability out of range"); + } + mNetworkCapabilities |= 1 << networkCapability; + } + public void removeNetworkCapability(int networkCapability) { + if (networkCapability < MIN_NET_CAPABILITY || + networkCapability > MAX_NET_CAPABILITY) { + throw new IllegalArgumentException("NetworkCapability out of range"); + } + mNetworkCapabilities &= ~(1 << networkCapability); + } + public Collection getNetworkCapabilities() { + return enumerateBits(mNetworkCapabilities); + } + + private Collection enumerateBits(long val) { + ArrayList result = new ArrayList(); + int resource = 0; + while (val > 0) { + if ((val & 1) == 1) result.add(resource); + val = val >> 1; + resource++; + } + return result; + } + + private void combineNetCapabilities(NetworkCapabilities nc) { + this.mNetworkCapabilities |= nc.mNetworkCapabilities; + } + + private boolean satisfiedByNetCapabilities(NetworkCapabilities nc) { + return ((nc.mNetworkCapabilities & this.mNetworkCapabilities) == this.mNetworkCapabilities); + } + + private boolean equalsNetCapabilities(NetworkCapabilities nc) { + return (nc.mNetworkCapabilities == this.mNetworkCapabilities); + } + + /** + * Representing the transport type. Apps should generally not care about transport. A + * request for a fast internet connection could be satisfied by a number of different + * transports. If any are specified here it will be satisfied a Network that matches + * any of them. If a caller doesn't care about the transport it should not specify any. + */ + private long mTransportTypes; + + /** + * Values for TransportType + */ + public static final int TRANSPORT_CELLULAR = 0; + public static final int TRANSPORT_WIFI = 1; + public static final int TRANSPORT_BLUETOOTH = 2; + public static final int TRANSPORT_ETHERNET = 3; + + private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR; + private static final int MAX_TRANSPORT = TRANSPORT_ETHERNET; + + public void addTransportType(int transportType) { + if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { + throw new IllegalArgumentException("TransportType out of range"); + } + mTransportTypes |= 1 << transportType; + } + public void removeTransportType(int transportType) { + if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { + throw new IllegalArgumentException("TransportType out of range"); + } + mTransportTypes &= ~(1 << transportType); + } + public Collection getTransportTypes() { + return enumerateBits(mTransportTypes); + } + + private void combineTransportTypes(NetworkCapabilities nc) { + this.mTransportTypes |= nc.mTransportTypes; + } + private boolean satisfiedByTransportTypes(NetworkCapabilities nc) { + return ((this.mTransportTypes == 0) || + ((this.mTransportTypes & nc.mTransportTypes) != 0)); + } + private boolean equalsTransportTypes(NetworkCapabilities nc) { + return (nc.mTransportTypes == this.mTransportTypes); + } + + /** + * Passive link bandwidth. This is a rough guide of the expected peak bandwidth + * for the first hop on the given transport. It is not measured, but may take into account + * link parameters (Radio technology, allocated channels, etc). + */ + private int mLinkUpBandwidthKbps; + private int mLinkDownBandwidthKbps; + + public void setLinkUpstreamBandwidthKbps(int upKbps) { + mLinkUpBandwidthKbps = upKbps; + } + public int getLinkUpstreamBandwidthKbps() { + return mLinkUpBandwidthKbps; + } + public void setLinkDownstreamBandwidthKbps(int downKbps) { + mLinkDownBandwidthKbps = downKbps; + } + public int getLinkDownstreamBandwidthKbps() { + return mLinkDownBandwidthKbps; + } + + private void combineLinkBandwidths(NetworkCapabilities nc) { + this.mLinkUpBandwidthKbps = + Math.max(this.mLinkUpBandwidthKbps, nc.mLinkUpBandwidthKbps); + this.mLinkDownBandwidthKbps = + Math.max(this.mLinkDownBandwidthKbps, nc.mLinkDownBandwidthKbps); + } + private boolean satisfiedByLinkBandwidths(NetworkCapabilities nc) { + return !(this.mLinkUpBandwidthKbps > nc.mLinkUpBandwidthKbps || + this.mLinkDownBandwidthKbps > nc.mLinkDownBandwidthKbps); + } + private boolean equalsLinkBandwidths(NetworkCapabilities nc) { + return (this.mLinkUpBandwidthKbps == nc.mLinkUpBandwidthKbps && + this.mLinkDownBandwidthKbps == nc.mLinkDownBandwidthKbps); + } + + /** + * Combine a set of Capabilities to this one. Useful for coming up with the complete set + * {@hide} + */ + public void combineCapabilities(NetworkCapabilities nc) { + combineNetCapabilities(nc); + combineTransportTypes(nc); + combineLinkBandwidths(nc); + } + + /** + * Check if our requirements are satisfied by the given Capabilities. + * {@hide} + */ + public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) { + return (satisfiedByNetCapabilities(nc) && + satisfiedByTransportTypes(nc) && + satisfiedByLinkBandwidths(nc)); + } + + @Override + public boolean equals(Object obj) { + if (obj == null || (obj instanceof NetworkCapabilities == false)) return false; + NetworkCapabilities that = (NetworkCapabilities)obj; + return (equalsNetCapabilities(that) && + equalsTransportTypes(that) && + equalsLinkBandwidths(that)); + } + + @Override + public int hashCode() { + return ((int)(mNetworkCapabilities & 0xFFFFFFFF) + + ((int)(mNetworkCapabilities >> 32) * 3) + + ((int)(mTransportTypes & 0xFFFFFFFF) * 5) + + ((int)(mTransportTypes >> 32) * 7) + + (mLinkUpBandwidthKbps * 11) + + (mLinkDownBandwidthKbps * 13)); + } + + public NetworkCapabilities() { + } + + public NetworkCapabilities(NetworkCapabilities nc) { + mNetworkCapabilities = nc.mNetworkCapabilities; + mTransportTypes = nc.mTransportTypes; + mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; + mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; + } + + // Parcelable + public int describeContents() { + return 0; + } + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mNetworkCapabilities); + dest.writeLong(mTransportTypes); + dest.writeInt(mLinkUpBandwidthKbps); + dest.writeInt(mLinkDownBandwidthKbps); + } + public static final Creator CREATOR = + new Creator() { + public NetworkCapabilities createFromParcel(Parcel in) { + NetworkCapabilities netCap = new NetworkCapabilities(); + + netCap.mNetworkCapabilities = in.readLong(); + netCap.mTransportTypes = in.readLong(); + netCap.mLinkUpBandwidthKbps = in.readInt(); + netCap.mLinkDownBandwidthKbps = in.readInt(); + return netCap; + } + public NetworkCapabilities[] newArray(int size) { + return new NetworkCapabilities[size]; + } + }; + + public String toString() { + Collection types = getTransportTypes(); + String transports = (types.size() > 0 ? " Transports: " : ""); + Iterator i = types.iterator(); + while (i.hasNext()) { + switch (i.next()) { + case TRANSPORT_CELLULAR: transports += "CELLULAR"; break; + case TRANSPORT_WIFI: transports += "WIFI"; break; + case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break; + case TRANSPORT_ETHERNET: transports += "ETHERNET"; break; + } + if (i.hasNext()) transports += "|"; + } + + types = getNetworkCapabilities(); + String capabilities = (types.size() > 0 ? " Capabilities: " : ""); + i = types.iterator(); + while (i.hasNext()) { + switch (i.next().intValue()) { + case NET_CAPABILITY_MMS: capabilities += "MMS"; break; + case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break; + case NET_CAPABILITY_DUN: capabilities += "DUN"; break; + case NET_CAPABILITY_FOTA: capabilities += "FOTA"; break; + case NET_CAPABILITY_IMS: capabilities += "IMS"; break; + case NET_CAPABILITY_CBS: capabilities += "CBS"; break; + case NET_CAPABILITY_WIFI_P2P: capabilities += "WIFI_P2P"; break; + case NET_CAPABILITY_IA: capabilities += "IA"; break; + case NET_CAPABILITY_RCS: capabilities += "RCS"; break; + case NET_CAPABILITY_XCAP: capabilities += "XCAP"; break; + case NET_CAPABILITY_EIMS: capabilities += "EIMS"; break; + case NET_CAPABILITY_NOT_METERED: capabilities += "NOT_METERED"; break; + case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break; + case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break; + } + if (i.hasNext()) capabilities += "&"; + } + + String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" + + mLinkUpBandwidthKbps + "Kbps" : ""); + String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" + + mLinkDownBandwidthKbps + "Kbps" : ""); + + return "NetworkCapabilities: [" + transports + capabilities + upBand + dnBand + "]"; + } +} From 19c6561c5092f0b7d52c153daf033f24595b02ba Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Fri, 9 May 2014 15:16:06 -0400 Subject: [PATCH 213/296] Switch PacUrl storage from String to Uri Since the interface for creating/accessing PAC URLs through a ProxyInfo is Uri based, so should the internal storage and references. Change-Id: Ibf15c350f4cc526f81aba3ec463070f26af8f535 --- core/java/android/net/ProxyInfo.java | 54 +++++++++++++++++++--------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index b40941fe9c..991d9dacd7 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -44,7 +44,7 @@ public class ProxyInfo implements Parcelable { private String mExclusionList; private String[] mParsedExclusionList; - private String mPacFileUrl; + private Uri mPacFileUrl; /** *@hide */ @@ -85,7 +85,7 @@ public class ProxyInfo implements Parcelable { * at the specified URL. */ public static ProxyInfo buildPacProxy(Uri pacUri) { - return new ProxyInfo(pacUri.toString()); + return new ProxyInfo(pacUri); } /** @@ -96,6 +96,21 @@ public class ProxyInfo implements Parcelable { mHost = host; mPort = port; setExclusionList(exclList); + mPacFileUrl = Uri.EMPTY; + } + + /** + * Create a ProxyProperties that points at a PAC URL. + * @hide + */ + public ProxyInfo(Uri pacFileUrl) { + mHost = LOCAL_HOST; + mPort = LOCAL_PORT; + setExclusionList(LOCAL_EXCL_LIST); + if (pacFileUrl == null) { + throw new NullPointerException(); + } + mPacFileUrl = pacFileUrl; } /** @@ -106,17 +121,20 @@ public class ProxyInfo implements Parcelable { mHost = LOCAL_HOST; mPort = LOCAL_PORT; setExclusionList(LOCAL_EXCL_LIST); - mPacFileUrl = pacFileUrl; + mPacFileUrl = Uri.parse(pacFileUrl); } /** * Only used in PacManager after Local Proxy is bound. * @hide */ - public ProxyInfo(String pacFileUrl, int localProxyPort) { + public ProxyInfo(Uri pacFileUrl, int localProxyPort) { mHost = LOCAL_HOST; mPort = localProxyPort; setExclusionList(LOCAL_EXCL_LIST); + if (pacFileUrl == null) { + throw new NullPointerException(); + } mPacFileUrl = pacFileUrl; } @@ -125,7 +143,7 @@ public class ProxyInfo implements Parcelable { mPort = port; mExclusionList = exclList; mParsedExclusionList = parsedExclList; - mPacFileUrl = null; + mPacFileUrl = Uri.EMPTY; } // copy constructor instead of clone @@ -137,6 +155,9 @@ public class ProxyInfo implements Parcelable { mHost = source.getHost(); mPort = source.getPort(); mPacFileUrl = source.mPacFileUrl; + if (mPacFileUrl == null) { + mPacFileUrl = Uri.EMPTY; + } mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; } @@ -158,10 +179,7 @@ public class ProxyInfo implements Parcelable { * no PAC script. */ public Uri getPacFileUrl() { - if (TextUtils.isEmpty(mPacFileUrl)) { - return null; - } - return Uri.parse(mPacFileUrl); + return mPacFileUrl; } /** @@ -210,7 +228,7 @@ public class ProxyInfo implements Parcelable { * @hide */ public boolean isValid() { - if (!TextUtils.isEmpty(mPacFileUrl)) return true; + if (!Uri.EMPTY.equals(mPacFileUrl)) return true; return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, mPort == 0 ? "" : Integer.toString(mPort), mExclusionList == null ? "" : mExclusionList); @@ -234,7 +252,7 @@ public class ProxyInfo implements Parcelable { @Override public String toString() { StringBuilder sb = new StringBuilder(); - if (mPacFileUrl != null) { + if (!Uri.EMPTY.equals(mPacFileUrl)) { sb.append("PAC Script: "); sb.append(mPacFileUrl); } else if (mHost != null) { @@ -257,13 +275,15 @@ public class ProxyInfo implements Parcelable { ProxyInfo p = (ProxyInfo)o; // If PAC URL is present in either then they must be equal. // Other parameters will only be for fall back. - if (!TextUtils.isEmpty(mPacFileUrl)) { + if (!Uri.EMPTY.equals(mPacFileUrl)) { return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; } - if (!TextUtils.isEmpty(p.mPacFileUrl)) { + if (!Uri.EMPTY.equals(p.mPacFileUrl)) { + return false; + } + if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) { return false; } - if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) return false; if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { return false; } @@ -296,9 +316,9 @@ public class ProxyInfo implements Parcelable { * @hide */ public void writeToParcel(Parcel dest, int flags) { - if (mPacFileUrl != null) { + if (!Uri.EMPTY.equals(mPacFileUrl)) { dest.writeByte((byte)1); - dest.writeString(mPacFileUrl); + mPacFileUrl.writeToParcel(dest, 0); dest.writeInt(mPort); return; } else { @@ -325,7 +345,7 @@ public class ProxyInfo implements Parcelable { String host = null; int port = 0; if (in.readByte() != 0) { - String url = in.readString(); + Uri url = Uri.CREATOR.createFromParcel(in); int localPort = in.readInt(); return new ProxyInfo(url, localPort); } From 3e0c794056573e1dd765ce929e2a27629606e46b Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 8 Apr 2014 17:34:00 -0700 Subject: [PATCH 214/296] Replace LinkCapabilities with NetworkCapabilities Also remove unused LinkSocket and LinkSocketNotifier. bug:13885501 Change-Id: Id426e31b201fa4f29109b5fea485d8efb34519d3 --- core/java/android/net/NetworkState.java | 14 +++++++------- .../com/android/server/ConnectivityService.java | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java index fbe1f8296b..2e0e9e432b 100644 --- a/core/java/android/net/NetworkState.java +++ b/core/java/android/net/NetworkState.java @@ -28,21 +28,21 @@ public class NetworkState implements Parcelable { public final NetworkInfo networkInfo; public final LinkProperties linkProperties; - public final LinkCapabilities linkCapabilities; + public final NetworkCapabilities networkCapabilities; /** Currently only used by testing. */ public final String subscriberId; public final String networkId; public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - LinkCapabilities linkCapabilities) { - this(networkInfo, linkProperties, linkCapabilities, null, null); + NetworkCapabilities networkCapabilities) { + this(networkInfo, linkProperties, networkCapabilities, null, null); } public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - LinkCapabilities linkCapabilities, String subscriberId, String networkId) { + NetworkCapabilities networkCapabilities, String subscriberId, String networkId) { this.networkInfo = networkInfo; this.linkProperties = linkProperties; - this.linkCapabilities = linkCapabilities; + this.networkCapabilities = networkCapabilities; this.subscriberId = subscriberId; this.networkId = networkId; } @@ -50,7 +50,7 @@ public class NetworkState implements Parcelable { public NetworkState(Parcel in) { networkInfo = in.readParcelable(null); linkProperties = in.readParcelable(null); - linkCapabilities = in.readParcelable(null); + networkCapabilities = in.readParcelable(null); subscriberId = in.readString(); networkId = in.readString(); } @@ -64,7 +64,7 @@ public class NetworkState implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeParcelable(networkInfo, flags); out.writeParcelable(linkProperties, flags); - out.writeParcelable(linkCapabilities, flags); + out.writeParcelable(networkCapabilities, flags); out.writeString(subscriberId); out.writeString(networkId); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 4ea33db475..c1ffd56ae5 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1117,7 +1117,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (tracker != null) { final NetworkInfo info = getFilteredNetworkInfo(tracker, uid); result.add(new NetworkState( - info, tracker.getLinkProperties(), tracker.getLinkCapabilities())); + info, tracker.getLinkProperties(), tracker.getNetworkCapabilities())); } } } @@ -1129,7 +1129,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { final NetworkStateTracker tracker = mNetTrackers[networkType]; if (tracker != null) { return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(), - tracker.getLinkCapabilities()); + tracker.getNetworkCapabilities()); } } return null; From d6ee688546bd262eb67b28c5351b04da15d0263b Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 11 Apr 2014 15:08:03 -0700 Subject: [PATCH 215/296] Add NetworkRequest to the multinetwork API bug:13885501 Change-Id: I7b9a01aadf26b6ff104d088b6e283c838ec4dfac --- core/java/android/net/NetworkRequest.java | 87 +++++++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 core/java/android/net/NetworkRequest.java diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java new file mode 100644 index 0000000000..7e3a06d380 --- /dev/null +++ b/core/java/android/net/NetworkRequest.java @@ -0,0 +1,87 @@ +/* + * 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; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.concurrent.atomic.AtomicInteger; + +/** + * @hide + */ +public class NetworkRequest implements Parcelable { + public final NetworkCapabilities networkCapabilities; + public final int requestId; + public final boolean legacy; + private static final AtomicInteger sRequestId = new AtomicInteger(); + + public NetworkRequest(NetworkCapabilities nc) { + this(nc, false, sRequestId.incrementAndGet()); + } + + public NetworkRequest(NetworkCapabilities nc, boolean legacy) { + this(nc, legacy, sRequestId.incrementAndGet()); + } + + private NetworkRequest(NetworkCapabilities nc, boolean legacy, int rId) { + requestId = rId; + networkCapabilities = nc; + this.legacy = legacy; + } + + // implement the Parcelable interface + public int describeContents() { + return 0; + } + public void writeToParcel(Parcel dest, int flags) { + dest.writeParcelable(networkCapabilities, flags); + dest.writeInt(legacy ? 1 : 0); + dest.writeInt(requestId); + } + public static final Creator CREATOR = + new Creator() { + public NetworkRequest createFromParcel(Parcel in) { + NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null); + boolean legacy = (in.readInt() == 1); + int requestId = in.readInt(); + return new NetworkRequest(nc, legacy, requestId); + } + public NetworkRequest[] newArray(int size) { + return new NetworkRequest[size]; + } + }; + + public String toString() { + return "NetworkRequest [ id=" + requestId + ", legacy=" + legacy + ", " + + networkCapabilities.toString() + " ]"; + } + + public boolean equals(Object obj) { + if (obj instanceof NetworkRequest == false) return false; + NetworkRequest that = (NetworkRequest)obj; + return (that.legacy == this.legacy && + that.requestId == this.requestId && + ((that.networkCapabilities == null && this.networkCapabilities == null) || + (that.networkCapabilities != null && + that.networkCapabilities.equals(this.networkCapabilities)))); + } + + public int hashCode() { + return requestId + (legacy ? 1013 : 2026) + (networkCapabilities.hashCode() * 1051); + } +} From 6b4985d8fd306522dccc659a12815f3e7992624e Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 21 Apr 2014 14:24:51 +0900 Subject: [PATCH 216/296] Fix reboot loop. The multinetwork branch is rebooting on startup with: E/AndroidRuntime( 1024): *** FATAL EXCEPTION IN SYSTEM PROCESS: NetworkStats [...] E/AndroidRuntime( 1024): Caused by: java.lang.NullPointerException: Attempt to read from field 'long android.net.NetworkCapabilities.mNetworkCapabilities' on a null object reference E/AndroidRuntime( 1024): at android.net.NetworkCapabilities.(NetworkCapabilities.java:235) E/AndroidRuntime( 1024): at android.net.BaseNetworkStateTracker.getNetworkCapabilities(BaseNetworkStateTracker.java:103) E/AndroidRuntime( 1024): at com.android.server.ConnectivityService.getAllNetworkState(ConnectivityService.java:1134) E/AndroidRuntime( 1024): at com.android.server.net.NetworkStatsService.updateIfacesLocked(NetworkStatsService.java:877) E/AndroidRuntime( 1024): at com.android.server.net.NetworkStatsService.updateIfaces(NetworkStatsService.java:849) E/AndroidRuntime( 1024): at com.android.server.net.NetworkStatsService.access$600(NetworkStatsService.java:139) E/AndroidRuntime( 1024): at com.android.server.net.NetworkStatsService$2.onReceive(NetworkStatsService.java:717) E/AndroidRuntime( 1024): at android.app.LoadedApk$ReceiverDispatcher$Args.run(LoadedApk.java:766) E/AndroidRuntime( 1024): ... 4 more This seems to be due to NetworkCapabilities' copy constructor not null-checking its argument. Unbreak things by ignoring null. Change-Id: Iff3c38e6d72390fa86e51bfce534ebd42a262e19 --- core/java/android/net/NetworkCapabilities.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index adbb185200..1d6ac64df2 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -233,10 +233,12 @@ public final class NetworkCapabilities implements Parcelable { } public NetworkCapabilities(NetworkCapabilities nc) { - mNetworkCapabilities = nc.mNetworkCapabilities; - mTransportTypes = nc.mTransportTypes; - mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; - mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; + if (nc != null) { + mNetworkCapabilities = nc.mNetworkCapabilities; + mTransportTypes = nc.mTransportTypes; + mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; + mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; + } } // Parcelable From c41962f220f0003c2c90ebdbd2164be31d92ee3a Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 8 May 2014 00:02:04 -0700 Subject: [PATCH 217/296] Add has* utility functions to NetworkCapabilities Change-Id: Icf735b778a3956812be522db39c29cf54c757a25 --- core/java/android/net/NetworkCapabilities.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index adbb185200..0bb26323a5 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -84,6 +84,13 @@ public final class NetworkCapabilities implements Parcelable { public Collection getNetworkCapabilities() { return enumerateBits(mNetworkCapabilities); } + public boolean hasCapability(int networkCapability) { + if (networkCapability < MIN_NET_CAPABILITY || + networkCapability > MAX_NET_CAPABILITY) { + return false; + } + return ((mNetworkCapabilities & (1 << networkCapability)) != 0); + } private Collection enumerateBits(long val) { ArrayList result = new ArrayList(); @@ -142,6 +149,12 @@ public final class NetworkCapabilities implements Parcelable { public Collection getTransportTypes() { return enumerateBits(mTransportTypes); } + public boolean hasTransport(int transportType) { + if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { + return false; + } + return ((mTransportTypes & (1 << transportType)) != 0); + } private void combineTransportTypes(NetworkCapabilities nc) { this.mTransportTypes |= nc.mTransportTypes; @@ -205,7 +218,8 @@ public final class NetworkCapabilities implements Parcelable { * {@hide} */ public boolean satisfiedByNetworkCapabilities(NetworkCapabilities nc) { - return (satisfiedByNetCapabilities(nc) && + return (nc != null && + satisfiedByNetCapabilities(nc) && satisfiedByTransportTypes(nc) && satisfiedByLinkBandwidths(nc)); } From c0669e3db048a1be59bc37c9c21403e444ece889 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 13 May 2014 06:32:53 -0700 Subject: [PATCH 218/296] Comment out some new netd calls to fix networking. bug:14869053 Change-Id: Ifc44f3cbadd0402c7b06e01962695e6b65dc48b3 --- .../core/java/com/android/server/ConnectivityService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c1ffd56ae5..ce2aefb6b5 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2084,7 +2084,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { getConnectivityChangeDelay()); } try { - mNetd.removeNetwork(thisNetId); +// mNetd.removeNetwork(thisNetId); } catch (Exception e) { loge("Exception removing network: " + e); } finally { @@ -2388,7 +2388,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int thisNetId = nextNetId(); thisNet.setNetId(thisNetId); try { - mNetd.createNetwork(thisNetId, thisIface); +// mNetd.createNetwork(thisNetId, thisIface); } catch (Exception e) { loge("Exception creating network :" + e); teardown(thisNet); @@ -2420,7 +2420,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int thisNetId = nextNetId(); thisNet.setNetId(thisNetId); try { - mNetd.createNetwork(thisNetId, thisIface); +// mNetd.createNetwork(thisNetId, thisIface); } catch (Exception e) { loge("Exception creating network :" + e); teardown(thisNet); From 09480006afe4c0610e45ceed124f37f5dacaebc8 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 13 May 2014 06:32:53 -0700 Subject: [PATCH 219/296] Comment out some new netd calls to fix networking. bug:14869053 Change-Id: Ifc44f3cbadd0402c7b06e01962695e6b65dc48b3 --- .../core/java/com/android/server/ConnectivityService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c1ffd56ae5..ce2aefb6b5 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2084,7 +2084,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { getConnectivityChangeDelay()); } try { - mNetd.removeNetwork(thisNetId); +// mNetd.removeNetwork(thisNetId); } catch (Exception e) { loge("Exception removing network: " + e); } finally { @@ -2388,7 +2388,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int thisNetId = nextNetId(); thisNet.setNetId(thisNetId); try { - mNetd.createNetwork(thisNetId, thisIface); +// mNetd.createNetwork(thisNetId, thisIface); } catch (Exception e) { loge("Exception creating network :" + e); teardown(thisNet); @@ -2420,7 +2420,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { int thisNetId = nextNetId(); thisNet.setNetId(thisNetId); try { - mNetd.createNetwork(thisNetId, thisIface); +// mNetd.createNetwork(thisNetId, thisIface); } catch (Exception e) { loge("Exception creating network :" + e); teardown(thisNet); From da1c1d4e6a24c9a0f69e71d9ce5dc6219eda2163 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 13 May 2014 19:05:13 -0400 Subject: [PATCH 220/296] Add Network-specific host name resolution API. Change-Id: I932f73158a8f6e3ccc36c319d138180dff2aa070 --- core/java/android/net/Network.java | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index f82bc22483..ac1289b93a 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -19,6 +19,8 @@ package android.net; import android.os.Parcelable; import android.os.Parcel; +import java.net.InetAddress; +import java.net.UnknownHostException; /** * Identifies the Network. @@ -36,6 +38,32 @@ public class Network implements Parcelable { this.netId = that.netId; } + /** + * Operates the same as {@code InetAddress.getAllByName} except that host + * resolution is done on this network. + * + * @param host the hostname or literal IP string to be resolved. + * @return the array of addresses associated with the specified host. + * @throws UnknownHostException if the address lookup fails. + */ + public InetAddress[] getAllByName(String host) throws UnknownHostException { + return InetAddress.getAllByNameOnNet(host, netId); + } + + /** + * Operates the same as {@code InetAddress.getByName} except that host + * resolution is done on this network. + * + * @param host + * the hostName to be resolved to an address or {@code null}. + * @return the {@code InetAddress} instance representing the host. + * @throws UnknownHostException + * if the address lookup fails. + */ + public InetAddress getByName(String host) throws UnknownHostException { + return InetAddress.getByNameOnNet(host, netId); + } + // implement the Parcelable interface public int describeContents() { return 0; From 7e45d1159f980dd7d6f3c807da47813d8667d639 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 11 Apr 2014 15:53:27 -0700 Subject: [PATCH 221/296] Add NetworkFactory support. This is a protocol allowing transports to dynamically register with CS for Handler to Handler communications. bug:13885501 Change-Id: Ic7275e3724a15efc7e5f80981560c4cb3106007b --- .../java/android/net/ConnectivityManager.java | 7 +++ .../android/net/IConnectivityManager.aidl | 2 + .../android/server/ConnectivityService.java | 53 +++++++++++++++++++ 3 files changed, 62 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3e0025043a..2406cbaa28 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1587,4 +1587,11 @@ public class ConnectivityManager { } catch (RemoteException e) { } } + + /** {@hide} */ + public void registerNetworkFactory(Messenger messenger) { + try { + mService.registerNetworkFactory(messenger); + } catch (RemoteException e) { } + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index d53a856b48..b69797e0b7 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -150,4 +150,6 @@ interface IConnectivityManager void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); void setAirplaneMode(boolean enable); + + void registerNetworkFactory(in Messenger messenger); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index ce2aefb6b5..741bf958ff 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -29,6 +29,7 @@ import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; +import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; @@ -66,10 +67,12 @@ import android.net.LinkProperties.CompareResult; import android.net.LinkQualityInfo; import android.net.MobileDataStateTracker; import android.net.Network; +import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkQuotaInfo; +import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkStateTracker; import android.net.NetworkUtils; @@ -119,6 +122,7 @@ import com.android.internal.telephony.DctConstants; import com.android.internal.telephony.Phone; import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; +import com.android.internal.util.AsyncChannel; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; @@ -372,6 +376,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_PROXY_HAS_CHANGED = 16; + /** + * used internally when registering NetworkFactories + * obj = Messenger + */ + private static final int EVENT_REGISTER_NETWORK_FACTORY = 17; + /** Handler used for internal events. */ private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -461,6 +471,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkFactory netFactory) { if (DBG) log("ConnectivityService starting up"); + NetworkCapabilities netCap = new NetworkCapabilities(); + netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + NetworkRequest netRequest = new NetworkRequest(netCap); + mNetworkRequests.append(netRequest.requestId, netRequest); + HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); handlerThread.start(); mHandler = new InternalHandler(handlerThread.getLooper()); @@ -3048,6 +3064,22 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void handleMessage(Message msg) { NetworkInfo info; switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { + AsyncChannel ac = (AsyncChannel) msg.obj; + if (mNetworkFactories.contains(ac)) { + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + if (VDBG) log("NetworkFactory connected"); + for (int i = 0; i < mNetworkRequests.size(); i++) { + ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, + mNetworkRequests.valueAt(i)); + } + } else { + loge("Error connecting NetworkFactory"); + mNetworkFactories.remove((AsyncChannel) msg.obj); + } + } + break; + } case NetworkStateTracker.EVENT_STATE_CHANGED: { info = (NetworkInfo) msg.obj; NetworkInfo.State state = info.getState(); @@ -3241,6 +3273,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleApplyDefaultProxy((ProxyInfo)msg.obj); break; } + case EVENT_REGISTER_NETWORK_FACTORY: { + handleRegisterNetworkFactory((Messenger)msg.obj); + break; + } } } } @@ -5081,4 +5117,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds; mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent); } + + private final ArrayList mNetworkFactories = new ArrayList(); + + public void registerNetworkFactory(Messenger messenger) { + enforceConnectivityInternalPermission(); + + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger)); + } + + private void handleRegisterNetworkFactory(Messenger messenger) { + if (VDBG) log("Got NetworkFactory Messenger"); + AsyncChannel ac = new AsyncChannel(); + mNetworkFactories.add(ac); + ac.connect(mContext, mTrackerHandler, messenger); + } + + private final SparseArray mNetworkRequests = new SparseArray(); } From faca3b780d8015d8e823985b3e506cf72dd0ecdd Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 31 Mar 2014 10:43:43 -0700 Subject: [PATCH 222/296] Stop adding host routes for dns bug:13550136 Change-Id: I748e13b96dab111f8f6a4b11d9beaf2a72d0742b --- .../android/server/ConnectivityService.java | 25 ------------------- 1 file changed, 25 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 741bf958ff..3e7d9cfd96 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2703,31 +2703,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - if (!isLinkDefault) { - // handle DNS routes - if (routesChanged) { - // routes changed - remove all old dns entries and add new - if (curLp != null) { - for (InetAddress oldDns : curLp.getDnses()) { - removeRouteToAddress(curLp, oldDns); - } - } - if (newLp != null) { - for (InetAddress newDns : newLp.getDnses()) { - addRouteToAddress(newLp, newDns, exempt); - } - } - } else { - // no change in routes, check for change in dns themselves - for (InetAddress oldDns : dnsDiff.removed) { - removeRouteToAddress(curLp, oldDns); - } - for (InetAddress newDns : dnsDiff.added) { - addRouteToAddress(newLp, newDns, exempt); - } - } - } - for (RouteInfo r : routeDiff.added) { if (isLinkDefault || ! r.isDefaultRoute()) { addRoute(newLp, r, TO_DEFAULT_TABLE, exempt); From 50daca44817a0835f6e550e0b222a548b8da1afa Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Thu, 10 Apr 2014 14:16:37 -0400 Subject: [PATCH 223/296] Use NetId instead of interface name when communicating DNS changes to netd. Change-Id: Ic82b73de6f50d39d56c5e1a32f5b1f3ebb80bb7d --- .../android/server/ConnectivityService.java | 66 ++++++++++--------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 3e7d9cfd96..2603395849 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2620,20 +2620,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } - if (resetDns) { - flushVmDnsCache(); - if (VDBG) log("resetting DNS cache for " + iface); - try { - mNetd.flushInterfaceDnsCache(iface); - } catch (Exception e) { - // never crash - catch them all - if (DBG) loge("Exception resetting dns cache: " + e); - } - } } else { loge("Can't reset connection for type "+netType); } } + if (resetDns) { + flushVmDnsCache(); + if (VDBG) log("resetting DNS cache for type " + netType); + try { + mNetd.flushNetworkDnsCache(mNetTrackers[netType].getNetwork().netId); + } catch (Exception e) { + // never crash - catch them all + if (DBG) loge("Exception resetting dns cache: " + e); + } + } } } @@ -2834,7 +2834,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (p == null) continue; if (mNetRequestersPids[i].contains(myPid)) { try { - mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid); + // TODO: Reimplement this via local variable in bionic. + // mNetd.setDnsNetworkForPid(nt.getNetwork().netId, pid); } catch (Exception e) { Slog.e(TAG, "exception reasseses pid dns: " + e); } @@ -2844,7 +2845,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // nothing found - delete try { - mNetd.clearDnsInterfaceForPid(pid); + // TODO: Reimplement this via local variable in bionic. + // mNetd.clearDnsNetworkForPid(pid); } catch (Exception e) { Slog.e(TAG, "exception clear interface from pid: " + e); } @@ -2869,8 +2871,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // Caller must grab mDnsLock. - private void updateDnsLocked(String network, String iface, - Collection dnses, String domains, boolean defaultDns) { + private void updateDnsLocked(String network, int netId, + Collection dnses, String domains) { int last = 0; if (dnses.size() == 0 && mDefaultDns != null) { dnses = new ArrayList(); @@ -2881,10 +2883,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } try { - mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains); - if (defaultDns) { - mNetd.setDefaultInterfaceForDns(iface); - } + mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), domains); for (InetAddress dns : dnses) { ++last; @@ -2909,14 +2908,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { LinkProperties p = nt.getLinkProperties(); if (p == null) return; Collection dnses = p.getDnses(); + int netId = nt.getNetwork().netId; if (mNetConfigs[netType].isDefault()) { String network = nt.getNetworkInfo().getTypeName(); synchronized (mDnsLock) { - updateDnsLocked(network, p.getInterfaceName(), dnses, p.getDomains(), true); + updateDnsLocked(network, netId, dnses, p.getDomains()); } } else { try { - mNetd.setDnsServersForInterface(p.getInterfaceName(), + mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), p.getDomains()); } catch (Exception e) { if (DBG) loge("exception setting dns servers: " + e); @@ -2925,7 +2925,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { List pids = mNetRequestersPids[netType]; for (Integer pid : pids) { try { - mNetd.setDnsInterfaceForPid(p.getInterfaceName(), pid); + // TODO: Reimplement this via local variable in bionic. + // mNetd.setDnsNetworkForPid(netId, pid); } catch (Exception e) { Slog.e(TAG, "exception setting interface for pid: " + e); } @@ -3878,7 +3879,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Apply DNS changes. synchronized (mDnsLock) { - updateDnsLocked("VPN", iface, addresses, domains, false); + // TODO: Re-enable this when the netId of the VPN is known. + // updateDnsLocked("VPN", netId, addresses, domains); } // Temporarily disable the default proxy (not global). @@ -3946,21 +3948,21 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void addUidForwarding(String interfaze, int uidStart, int uidEnd, boolean forwardDns) { - try { - mNetd.setUidRangeRoute(interfaze,uidStart, uidEnd); - if (forwardDns) mNetd.setDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); - } catch (RemoteException e) { - } + // TODO: Re-enable this when the netId of the VPN is known. + // try { + // mNetd.setUidRangeRoute(netId, uidStart, uidEnd, forwardDns); + // } catch (RemoteException e) { + // } } public void clearUidForwarding(String interfaze, int uidStart, int uidEnd, boolean forwardDns) { - try { - mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd); - if (forwardDns) mNetd.clearDnsInterfaceForUidRange(interfaze, uidStart, uidEnd); - } catch (RemoteException e) { - } + // TODO: Re-enable this when the netId of the VPN is known. + // try { + // mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd); + // } catch (RemoteException e) { + // } } } From 9d74d59302f14e03a04edf6102b228153d63f9cc Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 15 Apr 2014 15:48:48 -0400 Subject: [PATCH 224/296] Get ConnectivityServiceTest building again after 8f80cc8. Change-Id: I4520011ba2076d8fac1ca234cb9a79c774992671 --- .../src/com/android/server/ConnectivityServiceTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index f955f4fd57..b4a02f1c4c 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -165,7 +165,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { // verify that both routes were added and DNS was flushed verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4)); verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6)); - verify(mNetManager).flushInterfaceDnsCache(MOBILE_IFACE); + verify(mNetManager).flushNetworkDnsCache(mMobile.tracker.getNetwork().netId); } @@ -202,7 +202,7 @@ public class ConnectivityServiceTest extends AndroidTestCase { // verify that wifi routes added, and teardown requested verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V4)); verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V6)); - verify(mNetManager).flushInterfaceDnsCache(WIFI_IFACE); + verify(mNetManager).flushNetworkDnsCache(mWifi.tracker.getNetwork().netId); verify(mMobile.tracker).teardown(); reset(mNetManager, mMobile.tracker); From b62e139e692390d18244d64cb8584fbe8669e316 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Tue, 15 Apr 2014 16:35:19 -0700 Subject: [PATCH 225/296] Set and clear the default network. Change-Id: I305951e0c4735d708804baa597cc2d9b10f501c0 --- .../java/com/android/server/ConnectivityService.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 2603395849..1826478c05 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2120,6 +2120,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("tryFailover: set mActiveDefaultNetwork=-1, prevNetType=" + prevNetType); } mActiveDefaultNetwork = -1; + try { + mNetd.clearDefaultNetId(); + } catch (Exception e) { + loge("Exception clearing default network :" + e); + } } // don't signal a reconnect for anything lower or equal priority than our @@ -2423,6 +2428,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } mActiveDefaultNetwork = newNetType; + try { + mNetd.setDefaultNetId(thisNetId); + } catch (Exception e) { + loge("Exception setting default network :" + e); + } // this will cause us to come up initially as unconnected and switching // to connected after our normal pause unless somebody reports us as reall // disconnected From 96765661511eb1ff385c1f4e9b71a8b43a01d007 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Tue, 15 Apr 2014 19:07:12 -0700 Subject: [PATCH 226/296] Specify netId when adding/removing routes. Change-Id: I07fd950aee726e9721153f75c3e4c10d8e19d8e9 --- .../android/server/ConnectivityService.java | 53 ++++++++++--------- 1 file changed, 28 insertions(+), 25 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1826478c05..1cb873e66c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1691,7 +1691,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { final long token = Binder.clearCallingIdentity(); try { LinkProperties lp = tracker.getLinkProperties(); - boolean ok = addRouteToAddress(lp, addr, exempt); + boolean ok = addRouteToAddress(lp, addr, exempt, tracker.getNetwork().netId); if (DBG) log("requestRouteToHostAddress ok=" + ok); return ok; } finally { @@ -1700,24 +1700,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, - boolean exempt) { - return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt); + boolean exempt, int netId) { + return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt, netId); } - private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) { - return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT); + private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, int netId) { + return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT, netId); } - private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt) { - return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt); + private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt, + int netId) { + return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, netId); } - private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) { - return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT); + private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr, int netId) { + return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT, netId); } private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, - boolean toDefaultTable, boolean exempt) { + boolean toDefaultTable, boolean exempt, int netId) { RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr); if (bestRoute == null) { bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName()); @@ -1732,11 +1733,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface); } } - return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt); + return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt, netId); } private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd, - boolean toDefaultTable, boolean exempt) { + boolean toDefaultTable, boolean exempt, int netId) { if ((lp == null) || (r == null)) { if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r); return false; @@ -1765,7 +1766,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute.getGateway(), ifaceName); } - modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt); + modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId); } } if (doAdd) { @@ -1775,7 +1776,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { synchronized (mRoutesLock) { // only track default table - only one apps can effect mAddedRoutes.add(r); - mNetd.addRoute(ifaceName, r); + mNetd.addRoute(netId, r); if (exempt) { LinkAddress dest = r.getDestination(); if (!mExemptAddresses.contains(dest)) { @@ -1785,7 +1786,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } else { - mNetd.addSecondaryRoute(ifaceName, r); + mNetd.addRoute(netId, r); } } catch (Exception e) { // never crash - catch them all @@ -1801,7 +1802,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mAddedRoutes.contains(r) == false) { if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { - mNetd.removeRoute(ifaceName, r); + mNetd.removeRoute(netId, r); LinkAddress dest = r.getDestination(); if (mExemptAddresses.contains(dest)) { mNetd.clearHostExemption(dest); @@ -1819,7 +1820,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { - mNetd.removeSecondaryRoute(ifaceName, r); + mNetd.removeRoute(netId, r); } catch (Exception e) { // never crash - catch them all if (VDBG) loge("Exception trying to remove a route: " + e); @@ -2608,7 +2609,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } mCurrentLinkProperties[netType] = newLp; - boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt); + boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt, + mNetTrackers[netType].getNetwork().netId); if (resetMask != 0 || resetDns) { if (VDBG) log("handleConnectivityChange: resetting"); @@ -2687,7 +2689,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * returns a boolean indicating the routes changed */ private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp, - boolean isLinkDefault, boolean exempt) { + boolean isLinkDefault, boolean exempt, int netId) { Collection routesToAdd = null; CompareResult dnsDiff = new CompareResult(); CompareResult routeDiff = new CompareResult(); @@ -2705,20 +2707,20 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (RouteInfo r : routeDiff.removed) { if (isLinkDefault || ! r.isDefaultRoute()) { if (VDBG) log("updateRoutes: default remove route r=" + r); - removeRoute(curLp, r, TO_DEFAULT_TABLE); + removeRoute(curLp, r, TO_DEFAULT_TABLE, netId); } if (isLinkDefault == false) { // remove from a secondary route table - removeRoute(curLp, r, TO_SECONDARY_TABLE); + removeRoute(curLp, r, TO_SECONDARY_TABLE, netId); } } for (RouteInfo r : routeDiff.added) { if (isLinkDefault || ! r.isDefaultRoute()) { - addRoute(newLp, r, TO_DEFAULT_TABLE, exempt); + addRoute(newLp, r, TO_DEFAULT_TABLE, exempt, netId); } else { // add to a secondary route table - addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT); + addRoute(newLp, r, TO_SECONDARY_TABLE, UNEXEMPT, netId); // many radios add a default route even when we don't want one. // remove the default route unless somebody else has asked for it @@ -2727,7 +2729,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) { if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { - mNetd.removeRoute(ifaceName, r); + mNetd.removeRoute(netId, r); } catch (Exception e) { // never crash - catch them all if (DBG) loge("Exception trying to remove a route: " + e); @@ -3122,7 +3124,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // connection will fail until the provisioning network // is enabled. for (RouteInfo r : lp.getRoutes()) { - removeRoute(lp, r, TO_DEFAULT_TABLE); + removeRoute(lp, r, TO_DEFAULT_TABLE, + mNetTrackers[info.getType()].getNetwork().netId); } } else if (state == NetworkInfo.State.DISCONNECTED) { handleDisconnect(info); From 2a9d35f655084c82139ba95da5a78b17f915dc03 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Wed, 16 Apr 2014 10:56:07 -0700 Subject: [PATCH 227/296] Fix build. Change-Id: I5dab09d2d8a9cff56fa17bb4e8c14b365449399b --- .../server/ConnectivityServiceTest.java | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index b4a02f1c4c..88aaafc095 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -163,9 +163,10 @@ public class ConnectivityServiceTest extends AndroidTestCase { nextConnBroadcast.get(); // verify that both routes were added and DNS was flushed - verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4)); - verify(mNetManager).addRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6)); - verify(mNetManager).flushNetworkDnsCache(mMobile.tracker.getNetwork().netId); + int mobileNetId = mMobile.tracker.getNetwork().netId; + verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4)); + verify(mNetManager).addRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6)); + verify(mNetManager).flushNetworkDnsCache(mobileNetId); } @@ -200,11 +201,14 @@ public class ConnectivityServiceTest extends AndroidTestCase { nextConnBroadcast.get(); // verify that wifi routes added, and teardown requested - verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V4)); - verify(mNetManager).addRoute(eq(WIFI_IFACE), eq(WIFI_ROUTE_V6)); - verify(mNetManager).flushNetworkDnsCache(mWifi.tracker.getNetwork().netId); + int wifiNetId = mWifi.tracker.getNetwork().netId; + verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V4)); + verify(mNetManager).addRoute(eq(wifiNetId), eq(WIFI_ROUTE_V6)); + verify(mNetManager).flushNetworkDnsCache(wifiNetId); verify(mMobile.tracker).teardown(); + int mobileNetId = mMobile.tracker.getNetwork().netId; + reset(mNetManager, mMobile.tracker); // tear down mobile network, as requested @@ -216,8 +220,8 @@ public class ConnectivityServiceTest extends AndroidTestCase { mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget(); nextConnBroadcast.get(); - verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V4)); - verify(mNetManager).removeRoute(eq(MOBILE_IFACE), eq(MOBILE_ROUTE_V6)); + verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4)); + verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6)); } From e20f7a2429e85a4eeb0bf612f83f64268cfab9b3 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 18 Apr 2014 15:25:25 -0700 Subject: [PATCH 228/296] Enabling internal msg apis NetworkFactory and NetworkAgent. First trying with wifi and getting rid of WifiStateTracker. Conflicts: api/current.txt services/core/java/com/android/server/ConnectivityService.java Change-Id: I7f0ec13d7d8988b32f3c6dc71f72012f3349fe02 --- .../java/android/net/ConnectivityManager.java | 131 ++- .../android/net/IConnectivityManager.aidl | 14 +- core/java/android/net/NetworkAgent.java | 397 +++++++++ core/java/android/net/NetworkRequest.java | 62 +- .../android/server/ConnectivityService.java | 773 ++++++++++++------ .../server/connectivity/NetworkAgentInfo.java | 75 ++ 6 files changed, 1139 insertions(+), 313 deletions(-) create mode 100644 core/java/android/net/NetworkAgent.java create mode 100644 services/core/java/com/android/server/connectivity/NetworkAgentInfo.java diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2406cbaa28..1ee4ec0990 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -534,38 +534,32 @@ public class ConnectivityManager { /** * Specifies the preferred network type. When the device has more * than one type available the preferred network type will be used. - * Note that this made sense when we only had 2 network types, - * but with more and more default networks we need an array to list - * their ordering. This will be deprecated soon. * * @param preference the network type to prefer over all others. It is * unspecified what happens to the old preferred network in the * overall ordering. + * @Deprecated Functionality has been removed as it no longer makes sense, + * with many more than two networks - we'd need an array to express + * preference. Instead we use dynamic network properties of + * the networks to describe their precedence. */ public void setNetworkPreference(int preference) { - try { - mService.setNetworkPreference(preference); - } catch (RemoteException e) { - } } /** * Retrieves the current preferred network type. - * Note that this made sense when we only had 2 network types, - * but with more and more default networks we need an array to list - * their ordering. This will be deprecated soon. * * @return an integer representing the preferred network type * *

      This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * @Deprecated Functionality has been removed as it no longer makes sense, + * with many more than two networks - we'd need an array to express + * preference. Instead we use dynamic network properties of + * the networks to describe their precedence. */ public int getNetworkPreference() { - try { - return mService.getNetworkPreference(); - } catch (RemoteException e) { - return -1; - } + return -1; } /** @@ -723,13 +717,14 @@ public class ConnectivityManager { * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ - public boolean setRadios(boolean turnOn) { - try { - return mService.setRadios(turnOn); - } catch (RemoteException e) { - return false; - } - } +// TODO - check for any callers and remove +// public boolean setRadios(boolean turnOn) { +// try { +// return mService.setRadios(turnOn); +// } catch (RemoteException e) { +// return false; +// } +// } /** * Tells a given networkType to set its radio power state as directed. @@ -743,13 +738,14 @@ public class ConnectivityManager { * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ - public boolean setRadio(int networkType, boolean turnOn) { - try { - return mService.setRadio(networkType, turnOn); - } catch (RemoteException e) { - return false; - } - } +// TODO - check for any callers and remove +// public boolean setRadio(int networkType, boolean turnOn) { +// try { +// return mService.setRadio(networkType, turnOn); +// } catch (RemoteException e) { +// return false; +// } +// } /** * Tells the underlying networking system that the caller wants to @@ -1594,4 +1590,81 @@ public class ConnectivityManager { mService.registerNetworkFactory(messenger); } catch (RemoteException e) { } } + + /** {@hide} */ + public void registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp, + NetworkCapabilities nc, int score) { + try { + mService.registerNetworkAgent(messenger, ni, lp, nc, score); + } catch (RemoteException e) { } + } + + /** Interface for NetworkRequest callbacks {@hide} */ + public static class NetworkCallbacks { + public static final int PRECHECK = 1; + public static final int AVAILABLE = 2; + public static final int LOSING = 3; + public static final int LOST = 4; + public static final int UNAVAIL = 5; + public static final int CAP_CHANGED = 6; + public static final int PROP_CHANGED = 7; + public static final int CANCELED = 8; + + /** + * @hide + * Called whenever the framework connects to a network that it may use to + * satisfy this request + */ + public void onPreCheck(NetworkRequest networkRequest, Network network) {} + + /** + * Called when the framework connects and has validated the new network. + */ + public void onAvailable(NetworkRequest networkRequest, Network network) {} + + /** + * Called when the framework is losing the network. Often paired with an + * onAvailable call with the new replacement network for graceful handover. + * This may not be called if we have a hard loss (loss without warning). + * This may be followed by either an onLost call or an onAvailable call for this + * network depending on if we lose or regain it. + */ + public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {} + + /** + * Called when the framework has a hard loss of the network or when the + * graceful failure ends. Note applications should only request this callback + * if the application is willing to track the Available and Lost callbacks + * together, else the application may think it has no network when it + * really does (A Avail, B Avail, A Lost.. still have B). + */ + public void onLost(NetworkRequest networkRequest, Network network) {} + + /** + * Called if no network is found in the given timeout time. If no timeout is given, + * this will not be called. + */ + public void onUnavailable(NetworkRequest networkRequest) {} + + /** + * Called when the network the framework connected to for this request + * changes capabilities but still satisfies the stated need. + */ + public void onCapabilitiesChanged(NetworkRequest networkRequest, Network network, + NetworkCapabilities networkCapabilities) {} + + /** + * Called when the network the framework connected to for this request + * changes properties. + */ + public void onPropertiesChanged(NetworkRequest networkRequest, Network network, + LinkProperties linkProperties) {} + + /** + * Called when a CancelRequest call concludes and the registered callbacks will + * no longer be used. + */ + public void onCanceled(NetworkRequest networkRequest) {} + } + } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b69797e0b7..0d2e14db16 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -18,6 +18,7 @@ package android.net; import android.net.LinkQualityInfo; import android.net.LinkProperties; +import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; import android.net.NetworkState; @@ -41,10 +42,6 @@ interface IConnectivityManager // Keep this in sync with framework/native/services/connectivitymanager/ConnectivityManager.h void markSocketAsUser(in ParcelFileDescriptor socket, int uid); - void setNetworkPreference(int pref); - - int getNetworkPreference(); - NetworkInfo getActiveNetworkInfo(); NetworkInfo getActiveNetworkInfoForUid(int uid); NetworkInfo getNetworkInfo(int networkType); @@ -62,10 +59,6 @@ interface IConnectivityManager NetworkQuotaInfo getActiveNetworkQuotaInfo(); boolean isActiveNetworkMetered(); - boolean setRadios(boolean onOff); - - boolean setRadio(int networkType, boolean turnOn); - int startUsingNetworkFeature(int networkType, in String feature, in IBinder binder); @@ -147,9 +140,12 @@ interface IConnectivityManager LinkQualityInfo[] getAllLinkQualityInfo(); - void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, in String url); + void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, + in String url); void setAirplaneMode(boolean enable); void registerNetworkFactory(in Messenger messenger); + + void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score); } diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java new file mode 100644 index 0000000000..4b853987c9 --- /dev/null +++ b/core/java/android/net/NetworkAgent.java @@ -0,0 +1,397 @@ +/* + * 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; + +import android.content.Context; +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.util.Log; +import android.util.SparseArray; + +import com.android.internal.util.AsyncChannel; +import com.android.internal.util.Protocol; + +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * A Utility class for handling NetworkRequests. + * + * Created by bearer-specific code to handle tracking requests, scores, + * network data and handle communicating with ConnectivityService. Two + * abstract methods: connect and disconnect are used to act on the + * underlying bearer code. Connect is called when we have a NetworkRequest + * and our score is better than the current handling network's score, while + * disconnect is used when ConnectivityService requests a disconnect. + * + * A bearer may have more than one NetworkAgent if it can simultaneously + * support separate networks (IMS / Internet / MMS Apns on cellular, or + * perhaps connections with different SSID or P2P for Wi-Fi). The bearer + * code should pass its NetworkAgents the NetworkRequests each NetworkAgent + * can handle, demultiplexing for different network types. The bearer code + * can also filter out requests it can never handle. + * + * Each NetworkAgent needs to be given a score and NetworkCapabilities for + * their potential network. While disconnected, the NetworkAgent will check + * each time its score changes or a NetworkRequest changes to see if + * the NetworkAgent can provide a higher scored network for a NetworkRequest + * that the NetworkAgent's NetworkCapabilties can satisfy. This condition will + * trigger a connect request via connect(). After connection, connection data + * should be given to the NetworkAgent by the bearer, including LinkProperties + * NetworkCapabilties and NetworkInfo. After that the NetworkAgent will register + * with ConnectivityService and forward the data on. + * @hide + */ +public abstract class NetworkAgent extends Handler { + private final SparseArray mNetworkRequests = new SparseArray<>(); + private boolean mConnectionRequested = false; + + private AsyncChannel mAsyncChannel; + private final String LOG_TAG; + private static final boolean DBG = true; + // TODO - this class shouldn't cache data or it runs the risk of getting out of sync + // Make the API require each of these when any is updated so we have the data we need, + // without caching. + private LinkProperties mLinkProperties; + private NetworkInfo mNetworkInfo; + private NetworkCapabilities mNetworkCapabilities; + private int mNetworkScore; + private boolean mRegistered = false; + private final Context mContext; + private AtomicBoolean mHasRequests = new AtomicBoolean(false); + + // TODO - add a name member for logging purposes. + + protected final Object mLockObj = new Object(); + + + private static final int BASE = Protocol.BASE_NETWORK_AGENT; + + /** + * Sent by self to queue up a new/modified request. + * obj = NetworkRequestAndScore + */ + private static final int CMD_ADD_REQUEST = BASE + 1; + + /** + * Sent by self to queue up the removal of a request. + * obj = NetworkRequest + */ + private static final int CMD_REMOVE_REQUEST = BASE + 2; + + /** + * Sent by ConnectivityService to the NetworkAgent to inform it of + * suspected connectivity problems on its network. The NetworkAgent + * should take steps to verify and correct connectivity. + */ + public static final int CMD_SUSPECT_BAD = BASE + 3; + + /** + * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to + * ConnectivityService to pass the current NetworkInfo (connection state). + * Sent when the NetworkInfo changes, mainly due to change of state. + * obj = NetworkInfo + */ + public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 4; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * NetworkCapabilties. + * obj = NetworkCapabilities + */ + public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 5; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * NetworkProperties. + * obj = NetworkProperties + */ + public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 6; + + /** + * Sent by the NetworkAgent to ConnectivityService to pass the current + * network score. + * arg1 = network score int + */ + public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 7; + + public NetworkAgent(Looper looper, Context context, String logTag) { + super(looper); + LOG_TAG = logTag; + mContext = context; + } + + /** + * When conditions are right, register with ConnectivityService. + * Connditions include having a well defined network and a request + * that justifies it. The NetworkAgent will remain registered until + * disconnected. + * TODO - this should have all data passed in rather than caching + */ + private void registerSelf() { + synchronized(mLockObj) { + if (!mRegistered && mConnectionRequested && + mNetworkInfo != null && mNetworkInfo.isConnected() && + mNetworkCapabilities != null && + mLinkProperties != null && + mNetworkScore != 0) { + if (DBG) log("Registering NetworkAgent"); + mRegistered = true; + ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(mNetworkInfo), + new LinkProperties(mLinkProperties), + new NetworkCapabilities(mNetworkCapabilities), mNetworkScore); + } else if (DBG && !mRegistered) { + String err = "Not registering due to "; + if (mConnectionRequested == false) err += "no Connect requested "; + if (mNetworkInfo == null) err += "null NetworkInfo "; + if (mNetworkInfo != null && mNetworkInfo.isConnected() == false) { + err += "NetworkInfo disconnected "; + } + if (mLinkProperties == null) err += "null LinkProperties "; + if (mNetworkCapabilities == null) err += "null NetworkCapabilities "; + if (mNetworkScore == 0) err += "null NetworkScore"; + log(err); + } + } + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { + synchronized (mLockObj) { + if (mAsyncChannel != null) { + log("Received new connection while already connected!"); + } else { + if (DBG) log("NetworkAgent fully connected"); + mAsyncChannel = new AsyncChannel(); + mAsyncChannel.connected(null, this, msg.replyTo); + mAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, + AsyncChannel.STATUS_SUCCESSFUL); + } + } + break; + } + case AsyncChannel.CMD_CHANNEL_DISCONNECT: { + if (DBG) log("CMD_CHANNEL_DISCONNECT"); + if (mAsyncChannel != null) mAsyncChannel.disconnect(); + break; + } + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + if (DBG) log("NetworkAgent channel lost"); + disconnect(); + clear(); + break; + } + case CMD_SUSPECT_BAD: { + log("Unhandled Message " + msg); + break; + } + case CMD_ADD_REQUEST: { + handleAddRequest(msg); + break; + } + case CMD_REMOVE_REQUEST: { + handleRemoveRequest(msg); + break; + } + } + } + + private void clear() { + synchronized(mLockObj) { + mNetworkRequests.clear(); + mHasRequests.set(false); + mConnectionRequested = false; + mAsyncChannel = null; + mRegistered = false; + } + } + + private static class NetworkRequestAndScore { + NetworkRequest req; + int score; + + NetworkRequestAndScore(NetworkRequest networkRequest, int score) { + req = networkRequest; + this.score = score; + } + } + + private void handleAddRequest(Message msg) { + NetworkRequestAndScore n = (NetworkRequestAndScore)msg.obj; + // replaces old request, updating score + mNetworkRequests.put(n.req.requestId, n); + mHasRequests.set(true); + evalScores(); + } + + private void handleRemoveRequest(Message msg) { + NetworkRequest networkRequest = (NetworkRequest)msg.obj; + + if (mNetworkRequests.get(networkRequest.requestId) != null) { + mNetworkRequests.remove(networkRequest.requestId); + if (mNetworkRequests.size() == 0) mHasRequests.set(false); + evalScores(); + } + } + + /** + * called to go through our list of requests and see if we're + * good enough to try connecting. + * + * Only does connects - we disconnect when requested via + * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection + * between modules (bearer or ConnectivityService dies) or more commonly + * when the NetworkInfo reports to ConnectivityService it is disconnected. + */ + private void evalScores() { + if (mConnectionRequested) { + // already trying + return; + } + for (int i=0; i < mNetworkRequests.size(); i++) { + int score = mNetworkRequests.valueAt(i).score; + if (score < mNetworkScore) { + // have a request that has a lower scored network servicing it + // (or no network) than we could provide, so lets connect! + mConnectionRequested = true; + connect(); + return; + } + } + } + + public void addNetworkRequest(NetworkRequest networkRequest, int score) { + if (DBG) log("adding NetworkRequest " + networkRequest + " with score " + score); + sendMessage(obtainMessage(CMD_ADD_REQUEST, + new NetworkRequestAndScore(networkRequest, score))); + } + + public void removeNetworkRequest(NetworkRequest networkRequest) { + if (DBG) log("removing NetworkRequest " + networkRequest); + sendMessage(obtainMessage(CMD_REMOVE_REQUEST, networkRequest)); + } + + /** + * Called by the bearer code when it has new LinkProperties data. + * If we're a registered NetworkAgent, this new data will get forwarded on, + * otherwise we store a copy in anticipation of registering. This call + * may also prompt registration if it causes the NetworkAgent to meet + * the conditions (fully configured, connected, satisfys a request and + * has sufficient score). + */ + public void sendLinkProperties(LinkProperties linkProperties) { + linkProperties = new LinkProperties(linkProperties); + synchronized(mLockObj) { + mLinkProperties = linkProperties; + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, linkProperties); + } else { + registerSelf(); + } + } + } + + /** + * Called by the bearer code when it has new NetworkInfo data. + * If we're a registered NetworkAgent, this new data will get forwarded on, + * otherwise we store a copy in anticipation of registering. This call + * may also prompt registration if it causes the NetworkAgent to meet + * the conditions (fully configured, connected, satisfys a request and + * has sufficient score). + */ + public void sendNetworkInfo(NetworkInfo networkInfo) { + networkInfo = new NetworkInfo(networkInfo); + synchronized(mLockObj) { + mNetworkInfo = networkInfo; + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(EVENT_NETWORK_INFO_CHANGED, networkInfo); + } else { + registerSelf(); + } + } + } + + /** + * Called by the bearer code when it has new NetworkCapabilities data. + * If we're a registered NetworkAgent, this new data will get forwarded on, + * otherwise we store a copy in anticipation of registering. This call + * may also prompt registration if it causes the NetworkAgent to meet + * the conditions (fully configured, connected, satisfys a request and + * has sufficient score). + * Note that if these capabilities make the network non-useful, + * ConnectivityServce will tear this network down. + */ + public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) { + networkCapabilities = new NetworkCapabilities(networkCapabilities); + synchronized(mLockObj) { + mNetworkCapabilities = networkCapabilities; + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, networkCapabilities); + } else { + registerSelf(); + } + } + } + + public NetworkCapabilities getNetworkCapabilities() { + synchronized(mLockObj) { + return new NetworkCapabilities(mNetworkCapabilities); + } + } + + /** + * Called by the bearer code when it has a new score for this network. + * If we're a registered NetworkAgent, this new data will get forwarded on, + * otherwise we store a copy. + */ + public synchronized void sendNetworkScore(int score) { + synchronized(mLockObj) { + mNetworkScore = score; + evalScores(); + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(EVENT_NETWORK_SCORE_CHANGED, mNetworkScore); + } else { + registerSelf(); + } + } + } + + public boolean hasRequests() { + return mHasRequests.get(); + } + + public boolean isConnectionRequested() { + synchronized(mLockObj) { + return mConnectionRequested; + } + } + + + abstract protected void connect(); + abstract protected void disconnect(); + + protected void log(String s) { + Log.d(LOG_TAG, "NetworkAgent: " + s); + } +} diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 7e3a06d380..b3ae3f51e8 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -25,23 +25,55 @@ import java.util.concurrent.atomic.AtomicInteger; * @hide */ public class NetworkRequest implements Parcelable { + /** + * The NetworkCapabilities that define this request + */ public final NetworkCapabilities networkCapabilities; + + /** + * Identifies the request. NetworkRequests should only be constructed by + * the Framework and given out to applications as tokens to be used to identify + * the request. + * TODO - make sure this input is checked whenever a NR is passed in a public API + */ public final int requestId; - public final boolean legacy; - private static final AtomicInteger sRequestId = new AtomicInteger(); + /** + * Set for legacy requests and the default. + * Causes CONNECTIVITY_ACTION broadcasts to be sent. + * @hide + */ + public final boolean needsBroadcasts; + + private static final AtomicInteger sNextRequestId = new AtomicInteger(1); + + /** + * @hide + */ public NetworkRequest(NetworkCapabilities nc) { - this(nc, false, sRequestId.incrementAndGet()); + this(nc, false, sNextRequestId.getAndIncrement()); } - public NetworkRequest(NetworkCapabilities nc, boolean legacy) { - this(nc, legacy, sRequestId.incrementAndGet()); + /** + * @hide + */ + public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts) { + this(nc, needsBroadcasts, sNextRequestId.getAndIncrement()); } - private NetworkRequest(NetworkCapabilities nc, boolean legacy, int rId) { + /** + * @hide + */ + private NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) { requestId = rId; networkCapabilities = nc; - this.legacy = legacy; + this.needsBroadcasts = needsBroadcasts; + } + + public NetworkRequest(NetworkRequest that) { + networkCapabilities = new NetworkCapabilities(that.networkCapabilities); + requestId = that.requestId; + needsBroadcasts = that.needsBroadcasts; } // implement the Parcelable interface @@ -50,16 +82,17 @@ public class NetworkRequest implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(networkCapabilities, flags); - dest.writeInt(legacy ? 1 : 0); + dest.writeInt(needsBroadcasts ? 1 : 0); dest.writeInt(requestId); } public static final Creator CREATOR = new Creator() { public NetworkRequest createFromParcel(Parcel in) { NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null); - boolean legacy = (in.readInt() == 1); + boolean needsBroadcasts = (in.readInt() == 1); int requestId = in.readInt(); - return new NetworkRequest(nc, legacy, requestId); + NetworkRequest result = new NetworkRequest(nc, needsBroadcasts, requestId); + return result; } public NetworkRequest[] newArray(int size) { return new NetworkRequest[size]; @@ -67,14 +100,14 @@ public class NetworkRequest implements Parcelable { }; public String toString() { - return "NetworkRequest [ id=" + requestId + ", legacy=" + legacy + ", " + - networkCapabilities.toString() + " ]"; + return "NetworkRequest [ id=" + requestId + ", needsBroadcasts=" + needsBroadcasts + + ", " + networkCapabilities.toString() + " ]"; } public boolean equals(Object obj) { if (obj instanceof NetworkRequest == false) return false; NetworkRequest that = (NetworkRequest)obj; - return (that.legacy == this.legacy && + return (that.needsBroadcasts == this.needsBroadcasts && that.requestId == this.requestId && ((that.networkCapabilities == null && this.networkCapabilities == null) || (that.networkCapabilities != null && @@ -82,6 +115,7 @@ public class NetworkRequest implements Parcelable { } public int hashCode() { - return requestId + (legacy ? 1013 : 2026) + (networkCapabilities.hashCode() * 1051); + return requestId + (needsBroadcasts ? 1013 : 2026) + + (networkCapabilities.hashCode() * 1051); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1cb873e66c..cdb82e76a6 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; +import static android.net.ConnectivityManager.NetworkCallbacks; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_DUMMY; import static android.net.ConnectivityManager.TYPE_ETHERNET; @@ -30,6 +31,7 @@ import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; +import static android.net.ConnectivityServiceProtocol.NetworkMonitorProtocol; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; @@ -67,6 +69,7 @@ import android.net.LinkProperties.CompareResult; import android.net.LinkQualityInfo; import android.net.MobileDataStateTracker; import android.net.Network; +import android.net.NetworkAgent; import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkInfo; @@ -82,7 +85,6 @@ import android.net.ProxyInfo; import android.net.RouteInfo; import android.net.SamplingDataTracker; import android.net.Uri; -import android.net.wifi.WifiStateTracker; import android.net.wimax.WimaxManagerConstants; import android.os.AsyncTask; import android.os.Binder; @@ -128,6 +130,7 @@ import com.android.internal.util.XmlUtils; import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; +import com.android.server.connectivity.NetworkAgentInfo; import com.android.server.connectivity.PacManager; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; @@ -179,7 +182,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final String TAG = "ConnectivityService"; private static final boolean DBG = true; - private static final boolean VDBG = false; + private static final boolean VDBG = true; // STOPSHIP private static final boolean LOGD_RULES = false; @@ -305,12 +308,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2; - /** - * used internally to change our network preference setting - * arg1 = networkType to prefer - */ - private static final int EVENT_SET_NETWORK_PREFERENCE = 3; - /** * used internally to synchronize inet condition reports * arg1 = networkType @@ -382,10 +379,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_REGISTER_NETWORK_FACTORY = 17; + /** + * used internally when registering NetworkAgents + * obj = Messenger + */ + private static final int EVENT_REGISTER_NETWORK_AGENT = 18; + /** Handler used for internal events. */ - private InternalHandler mHandler; + final private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ - private NetworkStateTrackerHandler mTrackerHandler; + final private NetworkStateTrackerHandler mTrackerHandler; // list of DeathRecipients used to make sure features are turned off when // a process dies @@ -474,8 +477,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - NetworkRequest netRequest = new NetworkRequest(netCap); - mNetworkRequests.append(netRequest.requestId, netRequest); + mDefaultRequest = new NetworkRequest(netCap, true); + mNetworkRequests.append(mDefaultRequest.requestId, mDefaultRequest); HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); handlerThread.start(); @@ -624,21 +627,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - // Update mNetworkPreference according to user mannually first then overlay config.xml - mNetworkPreference = getPersistedNetworkPreference(); - if (mNetworkPreference == -1) { - for (int n : mPriorityList) { - if (mNetConfigs[n].isDefault() && ConnectivityManager.isNetworkTypeValid(n)) { - mNetworkPreference = n; - break; - } - } - if (mNetworkPreference == -1) { - throw new IllegalStateException( - "You should set at least one default Network in config.xml!"); - } - } - mNetRequestersPids = (List [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; for (int i : mPriorityList) { @@ -738,6 +726,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * Factory that creates {@link NetworkStateTracker} instances using given * {@link NetworkConfig}. + * + * TODO - this is obsolete and will be deleted. It's replaced by the + * registerNetworkFactory call and protocol. + * @Deprecated in favor of registerNetworkFactory dynamic bindings */ public interface NetworkFactory { public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config); @@ -755,10 +747,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) { switch (config.radio) { - case TYPE_WIFI: - return new WifiStateTracker(targetNetworkType, config.name); - case TYPE_MOBILE: - return new MobileDataStateTracker(targetNetworkType, config.name); case TYPE_DUMMY: return new DummyDataStateTracker(targetNetworkType, config.name); case TYPE_BLUETOOTH: @@ -859,41 +847,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return wimaxStateTracker; } - /** - * Sets the preferred network. - * @param preference the new preference - */ - public void setNetworkPreference(int preference) { - enforceChangePermission(); - - mHandler.sendMessage( - mHandler.obtainMessage(EVENT_SET_NETWORK_PREFERENCE, preference, 0)); - } - - public int getNetworkPreference() { - enforceAccessPermission(); - int preference; - synchronized(this) { - preference = mNetworkPreference; - } - return preference; - } - - private void handleSetNetworkPreference(int preference) { - if (ConnectivityManager.isNetworkTypeValid(preference) && - mNetConfigs[preference] != null && - mNetConfigs[preference].isDefault()) { - if (mNetworkPreference != preference) { - final ContentResolver cr = mContext.getContentResolver(); - Settings.Global.putInt(cr, Settings.Global.NETWORK_PREFERENCE, preference); - synchronized(this) { - mNetworkPreference = preference; - } - enforcePreference(); - } - } - } - private int getConnectivityChangeDelay() { final ContentResolver cr = mContext.getContentResolver(); @@ -905,41 +858,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { defaultDelay); } - private int getPersistedNetworkPreference() { - final ContentResolver cr = mContext.getContentResolver(); - - final int networkPrefSetting = Settings.Global - .getInt(cr, Settings.Global.NETWORK_PREFERENCE, -1); - - return networkPrefSetting; - } - - /** - * Make the state of network connectivity conform to the preference settings - * In this method, we only tear down a non-preferred network. Establishing - * a connection to the preferred network is taken care of when we handle - * the disconnect event from the non-preferred network - * (see {@link #handleDisconnect(NetworkInfo)}). - */ - private void enforcePreference() { - if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) - return; - - if (!mNetTrackers[mNetworkPreference].isAvailable()) - return; - - for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { - if (t != mNetworkPreference && mNetTrackers[t] != null && - mNetTrackers[t].getNetworkInfo().isConnected()) { - if (DBG) { - log("tearing down " + mNetTrackers[t].getNetworkInfo() + - " in enforcePreference"); - } - teardown(mNetTrackers[t]); - } - } - } - private boolean teardown(NetworkStateTracker netTracker) { if (netTracker.teardown()) { netTracker.setTeardownRequested(true); @@ -1192,24 +1110,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return false; } - public boolean setRadios(boolean turnOn) { - boolean result = true; - enforceChangePermission(); - for (NetworkStateTracker t : mNetTrackers) { - if (t != null) result = t.setRadio(turnOn) && result; - } - return result; - } - - public boolean setRadio(int netType, boolean turnOn) { - enforceChangePermission(); - if (!ConnectivityManager.isNetworkTypeValid(netType)) { - return false; - } - NetworkStateTracker tracker = mNetTrackers[netType]; - return tracker != null && tracker.setRadio(turnOn); - } - private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() { @Override public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) { @@ -1929,18 +1829,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void handleSetMobileData(boolean enabled) { - if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) { - if (VDBG) { - log(mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled); - } - mNetTrackers[ConnectivityManager.TYPE_MOBILE].setUserDataEnable(enabled); - } - if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) { - if (VDBG) { - log(mNetTrackers[ConnectivityManager.TYPE_WIMAX].toString() + enabled); - } - mNetTrackers[ConnectivityManager.TYPE_WIMAX].setUserDataEnable(enabled); - } + // TODO - handle this - probably generalize passing in a transport type and send to the + // factories? } @Override @@ -1953,12 +1843,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void handleSetPolicyDataEnable(int networkType, boolean enabled) { - if (isNetworkTypeValid(networkType)) { - final NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - tracker.setPolicyDataEnable(enabled); - } - } + // TODO - handle this passing to factories +// if (isNetworkTypeValid(networkType)) { +// final NetworkStateTracker tracker = mNetTrackers[networkType]; +// if (tracker != null) { +// tracker.setPolicyDataEnable(enabled); +// } +// } } private void enforceAccessPermission() { @@ -2226,67 +2117,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - /** - * Called when an attempt to fail over to another network has failed. - * @param info the {@link NetworkInfo} for the failed network - */ - private void handleConnectionFailure(NetworkInfo info) { - mNetTrackers[info.getType()].setTeardownRequested(false); - - String reason = info.getReason(); - String extraInfo = info.getExtraInfo(); - - String reasonText; - if (reason == null) { - reasonText = "."; - } else { - reasonText = " (" + reason + ")."; - } - loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText); - - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, new NetworkInfo(info)); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); - if (getActiveNetworkInfo() == null) { - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } - if (reason != null) { - intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); - } - if (extraInfo != null) { - intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); - } - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - info.setFailover(false); - } - - if (mNetConfigs[info.getType()].isDefault()) { - tryFailover(info.getType()); - if (mActiveDefaultNetwork != -1) { - NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); - intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); - } else { - mDefaultInetConditionPublished = 0; - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } - } - - intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); - - final Intent immediateIntent = new Intent(intent); - immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); - sendStickyBroadcast(immediateIntent); - sendStickyBroadcast(intent); - /* - * If the failover network is already connected, then immediately send - * out a followup broadcast indicating successful failover - */ - if (mActiveDefaultNetwork != -1) { - sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo()); - } - } - private void sendStickyBroadcast(Intent intent) { synchronized(this) { if (!mSystemReady) { @@ -2478,33 +2308,35 @@ public class ConnectivityService extends IConnectivityManager.Stub { } /** - * Setup data activity tracking for the given network interface. + * Setup data activity tracking for the given network. * * Every {@code setupDataActivityTracking} should be paired with a * {@link #removeDataActivityTracking} for cleanup. */ - private void setupDataActivityTracking(int type) { - final NetworkStateTracker thisNet = mNetTrackers[type]; - final String iface = thisNet.getLinkProperties().getInterfaceName(); + private void setupDataActivityTracking(NetworkAgentInfo networkAgent) { + final String iface = networkAgent.linkProperties.getInterfaceName(); final int timeout; + int type = ConnectivityManager.TYPE_NONE; - if (ConnectivityManager.isNetworkTypeMobile(type)) { + if (networkAgent.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_CELLULAR)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, 5); - // Canonicalize mobile network type type = ConnectivityManager.TYPE_MOBILE; - } else if (ConnectivityManager.TYPE_WIFI == type) { + } else if (networkAgent.networkCapabilities.hasTransport( + NetworkCapabilities.TRANSPORT_WIFI)) { timeout = Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.DATA_ACTIVITY_TIMEOUT_WIFI, 0); + type = ConnectivityManager.TYPE_WIFI; } else { // do not track any other networks timeout = 0; } - if (timeout > 0 && iface != null) { + if (timeout > 0 && iface != null && type != ConnectivityManager.TYPE_NONE) { try { mNetd.addIdleTimer(iface, timeout, type); } catch (Exception e) { @@ -2517,12 +2349,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * Remove data activity tracking when network disconnects. */ - private void removeDataActivityTracking(int type) { - final NetworkStateTracker net = mNetTrackers[type]; - final String iface = net.getLinkProperties().getInterfaceName(); + private void removeDataActivityTracking(NetworkAgentInfo networkAgent) { + final String iface = networkAgent.linkProperties.getInterfaceName(); + final NetworkCapabilities caps = networkAgent.networkCapabilities; - if (iface != null && (ConnectivityManager.isNetworkTypeMobile(type) || - ConnectivityManager.TYPE_WIFI == type)) { + if (iface != null && (caps.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) || + caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI))) { try { // the call fails silently if no idletimer setup for this interface mNetd.removeIdleTimer(iface); @@ -2537,8 +2369,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { * concerned with making sure that the list of DNS servers is set up * according to which networks are connected, and ensuring that the * right routing table entries exist. + * + * TODO - delete when we're sure all this functionallity is captured. */ - private void handleConnectivityChange(int netType, boolean doReset) { + private void handleConnectivityChange(int netType, LinkProperties curLp, boolean doReset) { int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0; boolean exempt = ConnectivityManager.isNetworkTypeExempt(netType); if (VDBG) { @@ -2552,7 +2386,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ handleDnsConfigurationChange(netType); - LinkProperties curLp = mCurrentLinkProperties[netType]; LinkProperties newLp = null; if (mNetTrackers[netType].getNetworkInfo().isConnected()) { @@ -2742,26 +2575,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { return routesChanged; } - /** + /** * Reads the network specific MTU size from reources. * and set it on it's iface. */ - private void updateMtuSizeSettings(NetworkStateTracker nt) { - final String iface = nt.getLinkProperties().getInterfaceName(); - final int mtu = nt.getLinkProperties().getMtu(); + private void updateMtu(LinkProperties newLp, LinkProperties oldLp) { + final String iface = newLp.getInterfaceName(); + final int mtu = newLp.getMtu(); + if (oldLp != null && newLp.isIdenticalMtu(oldLp)) { + if (VDBG) log("identical MTU - not setting"); + return; + } - if (mtu < 68 || mtu > 10000) { - loge("Unexpected mtu value: " + mtu + ", " + nt); - return; - } + if (mtu < 68 || mtu > 10000) { + loge("Unexpected mtu value: " + mtu + ", " + iface); + return; + } - try { - if (VDBG) log("Setting MTU size: " + iface + ", " + mtu); - mNetd.setMtu(iface, mtu); - } catch (Exception e) { - Slog.e(TAG, "exception in setMtu()" + e); - } - } + try { + if (VDBG) log("Setting MTU size: " + iface + ", " + mtu); + mNetd.setMtu(iface, mtu); + } catch (Exception e) { + Slog.e(TAG, "exception in setMtu()" + e); + } + } /** * Reads the network specific TCP buffer sizes from SystemProperties @@ -3053,21 +2890,58 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo info; switch (msg.what) { case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { - AsyncChannel ac = (AsyncChannel) msg.obj; - if (mNetworkFactories.contains(ac)) { - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - if (VDBG) log("NetworkFactory connected"); - for (int i = 0; i < mNetworkRequests.size(); i++) { - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, - mNetworkRequests.valueAt(i)); - } - } else { - loge("Error connecting NetworkFactory"); - mNetworkFactories.remove((AsyncChannel) msg.obj); - } + handleAsyncChannelHalfConnect(msg); + break; + } + case AsyncChannel.CMD_CHANNEL_DISCONNECT: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai != null) nai.asyncChannel.disconnect(); + break; + } + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { + handleAsyncChannelDisconnected(msg); + break; + } + case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("EVENT_NETWORK_CAPABILITIES_CHANGED from unknown NetworkAgent"); + } else { + updateCapabilities(nai, (NetworkCapabilities)msg.obj); } break; } + case NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED"); + } else { + LinkProperties oldLp = nai.linkProperties; + nai.linkProperties = (LinkProperties)msg.obj; + updateLinkProperties(nai, oldLp); + } + break; + } + case NetworkAgent.EVENT_NETWORK_INFO_CHANGED: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("EVENT_NETWORK_INFO_CHANGED from unknown NetworkAgent"); + break; + } + info = (NetworkInfo) msg.obj; + updateNetworkInfo(nai, info); + break; + } + case NetworkMonitorProtocol.EVENT_NETWORK_VALIDATED: { + NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; + handleConnectionValidated(nai); + break; + } + case NetworkMonitorProtocol.EVENT_NETWORK_LINGER_COMPLETE: { + NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; + handleLingerComplete(nai); + break; + } case NetworkStateTracker.EVENT_STATE_CHANGED: { info = (NetworkInfo) msg.obj; NetworkInfo.State state = info.getState(); @@ -3100,10 +2974,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { EventLogTags.writeConnectivityStateChanged( info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); - if (info.getDetailedState() == - NetworkInfo.DetailedState.FAILED) { - handleConnectionFailure(info); - } else if (info.isConnectedToProvisioningNetwork()) { + if (info.isConnectedToProvisioningNetwork()) { /** * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING * for now its an in between network, its a network that @@ -3128,18 +2999,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTrackers[info.getType()].getNetwork().netId); } } else if (state == NetworkInfo.State.DISCONNECTED) { - handleDisconnect(info); } else if (state == NetworkInfo.State.SUSPENDED) { - // TODO: need to think this over. - // the logic here is, handle SUSPENDED the same as - // DISCONNECTED. The only difference being we are - // broadcasting an intent with NetworkInfo that's - // suspended. This allows the applications an - // opportunity to handle DISCONNECTED and SUSPENDED - // differently, or not. - handleDisconnect(info); } else if (state == NetworkInfo.State.CONNECTED) { - handleConnect(info); + // handleConnect(info); } if (mLockdownTracker != null) { mLockdownTracker.onNetworkInfoChanged(info); @@ -3151,7 +3013,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // TODO: Temporary allowing network configuration // change not resetting sockets. // @see bug/4455071 - handleConnectivityChange(info.getType(), false); + handleConnectivityChange(info.getType(), mCurrentLinkProperties[info.getType()], + false); break; } case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { @@ -3164,6 +3027,66 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + private void handleAsyncChannelHalfConnect(Message msg) { + AsyncChannel ac = (AsyncChannel) msg.obj; + if (mNetworkFactories.contains(ac)) { + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + if (VDBG) log("NetworkFactory connected"); + // A network factory has connected. Send it all current NetworkRequests. + for (int i = 0; i < mNetworkRequests.size(); i++) { + NetworkRequest request = mNetworkRequests.valueAt(i); + NetworkAgentInfo nai = mNetworkForRequestId.get(request.requestId); + ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, + (nai != null ? nai.currentScore : 0), 0, request); + } + } else { + loge("Error connecting NetworkFactory"); + mNetworkFactories.remove(ac); + } + } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { + if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { + if (VDBG) log("NetworkAgent connected"); + // A network agent has requested a connection. Establish the connection. + mNetworkAgentInfos.get(msg.replyTo).asyncChannel. + sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); + } else { + loge("Error connecting NetworkAgent"); + mNetworkAgentInfos.remove(msg.replyTo); + } + } + } + private void handleAsyncChannelDisconnected(Message msg) { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai != null) { + if (DBG) log(nai.name() + " got DISCONNECTED"); + // A network agent has disconnected. + // Tell netd to clean up the configuration for this network + // (routing rules, DNS, etc). + try { + mNetd.removeNetwork(nai.network.netId); + } catch (Exception e) { + loge("Exception removing network: " + e); + } + notifyNetworkCallbacks(nai, NetworkCallbacks.LOST); + mNetworkAgentInfos.remove(nai); + // Since we've lost the network, go through all the requests that + // it was satisfying and see if any other factory can satisfy them. + for (int i = 0; i < nai.networkRequests.size(); i++) { + NetworkRequest request = nai.networkRequests.valueAt(i); + NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId); + if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { + mNetworkForRequestId.remove(request.requestId); + // TODO Check if any other live network will work + sendUpdatedScoreToFactories(request, 0); + } + } + if (nai.networkRequests.get(mDefaultRequest.requestId) != null) { + removeDataActivityTracking(nai); + } + } + } + + private class InternalHandler extends Handler { public InternalHandler(Looper looper) { super(looper); @@ -3204,11 +3127,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleInetConditionHoldEnd(netType, sequence); break; } - case EVENT_SET_NETWORK_PREFERENCE: { - int preference = msg.arg1; - handleSetNetworkPreference(preference); - break; - } case EVENT_SET_MOBILE_DATA: { boolean enabled = (msg.arg1 == ENABLED); handleSetMobileData(enabled); @@ -3266,6 +3184,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleRegisterNetworkFactory((Messenger)msg.obj); break; } + case EVENT_REGISTER_NETWORK_AGENT: { + handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj); + break; + } } } } @@ -5112,7 +5034,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void registerNetworkFactory(Messenger messenger) { enforceConnectivityInternalPermission(); - mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger)); } @@ -5123,5 +5044,335 @@ public class ConnectivityService extends IConnectivityManager.Stub { ac.connect(mContext, mTrackerHandler, messenger); } + // NetworkRequest by requestId private final SparseArray mNetworkRequests = new SparseArray(); + + /** + * NetworkAgentInfo supporting a request by requestId. + * These have already been vetted (their Capabilities satisfy the request) + * and the are the highest scored network available. + * the are keyed off the Requests requestId. + */ + private final SparseArray mNetworkForRequestId = + new SparseArray(); + + // NetworkAgentInfo keyed off its connecting messenger + // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays + private final HashMap mNetworkAgentInfos = + new HashMap(); + + private final NetworkRequest mDefaultRequest; + + public void registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo, + LinkProperties linkProperties, NetworkCapabilities networkCapabilities, + int currentScore) { + enforceConnectivityInternalPermission(); + + NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(), + new NetworkInfo(networkInfo), new LinkProperties(linkProperties), + new NetworkCapabilities(networkCapabilities), currentScore); + + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai)); + } + + private void handleRegisterNetworkAgent(NetworkAgentInfo na) { + if (VDBG) log("Got NetworkAgent Messenger"); + mNetworkAgentInfos.put(na.messenger, na); + na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger); + NetworkInfo networkInfo = na.networkInfo; + na.networkInfo = null; + updateNetworkInfo(na, networkInfo); + } + + private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) { + LinkProperties newLp = networkAgent.linkProperties; + int netId = networkAgent.network.netId; + + updateMtu(newLp, oldLp); + // TODO - figure out what to do for clat +// for (LinkProperties lp : newLp.getStackedLinks()) { +// updateMtu(lp, null); +// } + updateRoutes(newLp, oldLp, netId); + updateDnses(newLp, oldLp, netId); + } + private void updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) { + CompareResult routeDiff = new CompareResult(); + if (oldLp != null) { + routeDiff = oldLp.compareAllRoutes(newLp); + } else if (newLp != null) { + routeDiff.added = newLp.getAllRoutes(); + } + + // add routes before removing old in case it helps with continuous connectivity + + // do this twice, adding non-nexthop routes first, then routes they are dependent on + for (RouteInfo route : routeDiff.added) { + if (route.hasGateway()) continue; + try { + mNetd.addRoute(netId, route); + } catch (Exception e) { + loge("Exception in addRoute for non-gateway: " + e); + } + } + for (RouteInfo route : routeDiff.added) { + if (route.hasGateway() == false) continue; + try { + mNetd.addRoute(netId, route); + } catch (Exception e) { + loge("Exception in addRoute for gateway: " + e); + } + } + + for (RouteInfo route : routeDiff.removed) { + try { + mNetd.removeRoute(netId, route); + } catch (Exception e) { + loge("Exception in removeRoute: " + e); + } + } + } + private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) { + if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) { + Collection dnses = newLp.getDnses(); + if (dnses.size() == 0 && mDefaultDns != null) { + dnses = new ArrayList(); + dnses.add(mDefaultDns); + if (DBG) { + loge("no dns provided for netId " + netId + ", so using defaults"); + } + } + try { + mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), + newLp.getDomains()); + } catch (Exception e) { + loge("Exception in setDnsServersForNetwork: " + e); + } + // TODO - setprop "net.dnsX" + } + } + + private void updateCapabilities(NetworkAgentInfo networkAgent, + NetworkCapabilities networkCapabilities) { + // TODO - what else here? Verify still satisfies everybody? + // Check if satisfies somebody new? call callbacks? + networkAgent.networkCapabilities = networkCapabilities; + } + + private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { + if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); + for (AsyncChannel ac : mNetworkFactories) { + ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); + } + } + + private void callCallbackForRequest(NetworkRequest networkRequest, + NetworkAgentInfo networkAgent, int notificationType) { + // TODO + } + + private void handleLingerComplete(NetworkAgentInfo oldNetwork) { + if (oldNetwork == null) { + loge("Unknown NetworkAgentInfo in handleLingerComplete"); + return; + } + if (DBG) log("handleLingerComplete for " + oldNetwork.name()); + if (DBG) { + if (oldNetwork.networkRequests.size() != 0) { + loge("Dead network still had " + oldNetwork.networkRequests.size() + " requests"); + } + } + oldNetwork.asyncChannel.disconnect(); + } + + private void handleConnectionValidated(NetworkAgentInfo newNetwork) { + if (newNetwork == null) { + loge("Unknown NetworkAgentInfo in handleConnectionValidated"); + return; + } + boolean keep = false; + boolean isNewDefault = false; + if (DBG) log("handleConnectionValidated for "+newNetwork.name()); + // check if any NetworkRequest wants this NetworkAgent + // first check if it satisfies the NetworkCapabilities + for (int i = 0; i < mNetworkRequests.size(); i++) { + NetworkRequest nr = mNetworkRequests.valueAt(i); + if (nr.networkCapabilities.satisfiedByNetworkCapabilities( + newNetwork.networkCapabilities)) { + // next check if it's better than any current network we're using for + // this request + NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nr.requestId); + if (VDBG) { + log("currentScore = " + + (currentNetwork != null ? currentNetwork.currentScore : 0) + + ", newScore = " + newNetwork.currentScore); + } + if (currentNetwork == null || + currentNetwork.currentScore < newNetwork.currentScore) { + if (currentNetwork != null) { + currentNetwork.networkRequests.remove(nr.requestId); + currentNetwork.networkListens.add(nr); + if (currentNetwork.networkRequests.size() == 0) { + // TODO tell current Network to go to linger state + + // fake the linger state: + Message message = Message.obtain(); + message.obj = currentNetwork; + message.what = NetworkMonitorProtocol.EVENT_NETWORK_LINGER_COMPLETE; + mTrackerHandler.sendMessage(message); + + notifyNetworkCallbacks(currentNetwork, NetworkCallbacks.LOSING); + } + } + mNetworkForRequestId.put(nr.requestId, newNetwork); + newNetwork.networkRequests.put(nr.requestId, nr); + keep = true; + // TODO - this could get expensive if we have alot of requests for this + // network. Think about if there is a way to reduce this. Push + // netid->request mapping to each factory? + sendUpdatedScoreToFactories(nr, newNetwork.currentScore); + if (mDefaultRequest.requestId == nr.requestId) { + isNewDefault = true; + } + } + } + } + if (keep) { + if (isNewDefault) { + if (VDBG) log("Switching to new default network: " + newNetwork); + setupDataActivityTracking(newNetwork); + try { + mNetd.setDefaultNetId(newNetwork.network.netId); + } catch (Exception e) { + loge("Exception setting default network :" + e); + } + if (newNetwork.equals(mNetworkForRequestId.get(mDefaultRequest.requestId))) { + handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy()); + } + synchronized (ConnectivityService.this) { + // have a new default network, release the transition wakelock in + // a second if it's held. The second pause is to allow apps + // to reconnect over the new network + if (mNetTransitionWakeLock.isHeld()) { + mHandler.sendMessageDelayed(mHandler.obtainMessage( + EVENT_CLEAR_NET_TRANSITION_WAKELOCK, + mNetTransitionWakeLockSerialNumber, 0), + 1000); + } + } + + // this will cause us to come up initially as unconnected and switching + // to connected after our normal pause unless somebody reports us as + // really disconnected + mDefaultInetConditionPublished = 0; + mDefaultConnectionSequence++; + mInetConditionChangeInFlight = false; + // TODO - read the tcp buffer size config string from somewhere + // updateNetworkSettings(); + } + // notify battery stats service about this network +// try { + // TODO + //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType); +// } catch (RemoteException e) { } + notifyNetworkCallbacks(newNetwork, NetworkCallbacks.AVAILABLE); + } else { + if (VDBG) log("Validated network turns out to be unwanted. Tear it down."); + newNetwork.asyncChannel.disconnect(); + } + } + + + private void updateNetworkInfo(NetworkAgentInfo networkAgent, NetworkInfo newInfo) { + NetworkInfo.State state = newInfo.getState(); + NetworkInfo oldInfo = networkAgent.networkInfo; + networkAgent.networkInfo = newInfo; + + if (oldInfo != null && oldInfo.getState() == state) { + if (VDBG) log("ignoring duplicate network state non-change"); + return; + } + if (DBG) { + log(networkAgent.name() + " EVENT_NETWORK_INFO_CHANGED, going from " + + (oldInfo == null ? "null" : oldInfo.getState()) + + " to " + state); + } + if (state == NetworkInfo.State.CONNECTED) { + // TODO - check if we want it (optimization) + try { + mNetd.createNetwork(networkAgent.network.netId, + networkAgent.linkProperties.getInterfaceName()); + } catch (Exception e) { + loge("Error creating Network " + networkAgent.network.netId); + } + updateLinkProperties(networkAgent, null); + notifyNetworkCallbacks(networkAgent, NetworkCallbacks.PRECHECK); + // TODO - kick the network monitor + + // Fake things by sending self a NETWORK_VALIDATED msg + Message message = Message.obtain(); + message.obj = networkAgent; + message.what = NetworkMonitorProtocol.EVENT_NETWORK_VALIDATED; + mTrackerHandler.sendMessage(message); + } else if (state == NetworkInfo.State.DISCONNECTED || + state == NetworkInfo.State.SUSPENDED) { + networkAgent.asyncChannel.disconnect(); + } + } + + protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) { + if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name()); + boolean needsBroadcasts = false; + for (int i = 0; i < networkAgent.networkRequests.size(); i++) { + NetworkRequest request = networkAgent.networkRequests.valueAt(i); + if (request == null) continue; + if (request.needsBroadcasts) needsBroadcasts = true; + callCallbackForRequest(request, networkAgent, notifyType); + } + for (NetworkRequest request : networkAgent.networkListens) { + if (request.needsBroadcasts) needsBroadcasts = true; + callCallbackForRequest(request, networkAgent, notifyType); + } + if (needsBroadcasts) { + if (notifyType == NetworkCallbacks.AVAILABLE) { + sendConnectedBroadcastDelayed(networkAgent.networkInfo, + getConnectivityChangeDelay()); + } else if (notifyType == NetworkCallbacks.LOST) { + NetworkInfo info = new NetworkInfo(networkAgent.networkInfo); + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); + if (info.isFailover()) { + intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); + networkAgent.networkInfo.setFailover(false); + } + if (info.getReason() != null) { + intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); + } + if (info.getExtraInfo() != null) { + intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); + } + NetworkAgentInfo newDefaultAgent = null; + if (networkAgent.networkRequests.get(mDefaultRequest.requestId) != null) { + newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId); + if (newDefaultAgent != null) { + intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, + newDefaultAgent.networkInfo); + } else { + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); + } + } + intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, + mDefaultInetConditionPublished); + final Intent immediateIntent = new Intent(intent); + immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); + sendStickyBroadcast(immediateIntent); + sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); + if (newDefaultAgent != null) { + sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo, + getConnectivityChangeDelay()); + } + } + } + } } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java new file mode 100644 index 0000000000..4747487705 --- /dev/null +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -0,0 +1,75 @@ +/* + * 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 com.android.server.connectivity; + +import android.net.LinkProperties; +import android.net.Network; +import android.net.NetworkCapabilities; +import android.net.NetworkInfo; +import android.net.NetworkRequest; +import android.os.Messenger; +import android.util.SparseArray; + +import com.android.internal.util.AsyncChannel; + +import java.util.ArrayList; + +/** + * A bag class used by ConnectivityService for holding a collection of most recent + * information published by a particular NetworkAgent as well as the + * AsyncChannel/messenger for reaching that NetworkAgent and lists of NetworkRequests + * interested in using it. + */ +public class NetworkAgentInfo { + public NetworkInfo networkInfo; + public final Network network; + public LinkProperties linkProperties; + public NetworkCapabilities networkCapabilities; + public int currentScore; + + // The list of NetworkRequests being satisfied by this Network. + public final SparseArray networkRequests = new SparseArray(); + + // The list of NetworkListens listening for changes on this Network. + public final ArrayList networkListens = new ArrayList(); + public final Messenger messenger; + public final AsyncChannel asyncChannel; + + public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, int netId, NetworkInfo info, + LinkProperties lp, NetworkCapabilities nc, int score) { + this.messenger = messenger; + asyncChannel = ac; + network = new Network(netId); + networkInfo = info; + linkProperties = lp; + networkCapabilities = nc; + currentScore = score; + + } + + public String toString() { + return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" + + network + "} lp{" + + linkProperties + "} nc{" + + networkCapabilities + "} Score{" + currentScore + "} }"; + } + + public String name() { + return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" + + networkInfo.getSubtypeName() + ")]"; + } +} From bff73490ac373f8095f54ebfa26fc30d643bcb54 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Mon, 28 Apr 2014 10:33:11 -0400 Subject: [PATCH 229/296] Separate network and interface addition/removal netd APIs. This should facilitate stacked interfaces (i.e. clatd). Change-Id: Ib3e7a4d3847ef6ec4449451f6da42e75959baa4f --- core/java/android/net/LinkProperties.java | 29 +++++++++++++++++++ .../android/server/ConnectivityService.java | 28 ++++++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 2dcc544f6f..0a09fcba4e 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -642,6 +642,35 @@ public class LinkProperties implements Parcelable { return result; } + /** + * Compares all interface names in this LinkProperties with another + * LinkProperties, examining both the the base link and all stacked links. + * + * @param target a LinkProperties with the new list of interface names + * @return the differences between the interface names. + * @hide + */ + public CompareResult compareAllInterfaceNames(LinkProperties target) { + /* + * Duplicate the interface names into removed, we will be removing + * interface names which are common between this and target + * leaving the interface names that are different. And interface names which + * are in target but not in this are placed in added. + */ + CompareResult result = new CompareResult(); + + result.removed = getAllInterfaceNames(); + result.added.clear(); + if (target != null) { + for (String r : target.getAllInterfaceNames()) { + if (! result.removed.remove(r)) { + result.added.add(r); + } + } + } + return result; + } + @Override /** diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index cdb82e76a6..6cc738b763 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5088,6 +5088,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { LinkProperties newLp = networkAgent.linkProperties; int netId = networkAgent.network.netId; + updateInterfaces(newLp, oldLp, netId); updateMtu(newLp, oldLp); // TODO - figure out what to do for clat // for (LinkProperties lp : newLp.getStackedLinks()) { @@ -5096,6 +5097,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { updateRoutes(newLp, oldLp, netId); updateDnses(newLp, oldLp, netId); } + + private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) { + CompareResult interfaceDiff = new CompareResult(); + if (oldLp != null) { + interfaceDiff = oldLp.compareAllInterfaceNames(newLp); + } else if (newLp != null) { + interfaceDiff.added = newLp.getAllInterfaceNames(); + } + for (String iface : interfaceDiff.added) { + try { + mNetd.addInterfaceToNetwork(iface, netId); + } catch (Exception e) { + loge("Exception adding interface: " + e); + } + } + for (String iface : interfaceDiff.removed) { + try { + mNetd.removeInterfaceFromNetwork(iface, netId); + } catch (Exception e) { + loge("Exception removing interface: " + e); + } + } + } + private void updateRoutes(LinkProperties newLp, LinkProperties oldLp, int netId) { CompareResult routeDiff = new CompareResult(); if (oldLp != null) { @@ -5300,8 +5325,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (state == NetworkInfo.State.CONNECTED) { // TODO - check if we want it (optimization) try { - mNetd.createNetwork(networkAgent.network.netId, - networkAgent.linkProperties.getInterfaceName()); + mNetd.createNetwork(networkAgent.network.netId); } catch (Exception e) { loge("Error creating Network " + networkAgent.network.netId); } From 4bc35b4aa59dd00a496ce6d52d285eacd1b7c869 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Fri, 9 May 2014 12:47:55 -0400 Subject: [PATCH 230/296] Add NetworkMonitor. At present the network evaluation / captive portal detection is disabled pending addition of API to bind socket to network. Change-Id: I5d1f5dc86d4dd9481d52dd45d6da0732054c8315 --- .../android/server/ConnectivityService.java | 48 +++++++++++-------- .../server/connectivity/NetworkAgentInfo.java | 10 +++- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 6cc738b763..752dce9187 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -31,7 +31,6 @@ import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; -import static android.net.ConnectivityServiceProtocol.NetworkMonitorProtocol; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; @@ -131,6 +130,7 @@ import com.android.server.am.BatteryStatsService; import com.android.server.connectivity.DataConnectionStats; import com.android.server.connectivity.Nat464Xlat; import com.android.server.connectivity.NetworkAgentInfo; +import com.android.server.connectivity.NetworkMonitor; import com.android.server.connectivity.PacManager; import com.android.server.connectivity.Tethering; import com.android.server.connectivity.Vpn; @@ -2932,12 +2932,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { updateNetworkInfo(nai, info); break; } - case NetworkMonitorProtocol.EVENT_NETWORK_VALIDATED: { + case NetworkMonitor.EVENT_NETWORK_VALIDATED: { NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; handleConnectionValidated(nai); break; } - case NetworkMonitorProtocol.EVENT_NETWORK_LINGER_COMPLETE: { + case NetworkMonitor.EVENT_NETWORK_LINGER_COMPLETE: { NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; handleLingerComplete(nai); break; @@ -3068,21 +3068,39 @@ public class ConnectivityService extends IConnectivityManager.Stub { loge("Exception removing network: " + e); } notifyNetworkCallbacks(nai, NetworkCallbacks.LOST); + nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); mNetworkAgentInfos.remove(nai); // Since we've lost the network, go through all the requests that // it was satisfying and see if any other factory can satisfy them. + final ArrayList toActivate = new ArrayList(); for (int i = 0; i < nai.networkRequests.size(); i++) { NetworkRequest request = nai.networkRequests.valueAt(i); NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId); if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { mNetworkForRequestId.remove(request.requestId); - // TODO Check if any other live network will work sendUpdatedScoreToFactories(request, 0); + NetworkAgentInfo alternative = null; + for (Map.Entry entry : mNetworkAgentInfos.entrySet()) { + NetworkAgentInfo existing = (NetworkAgentInfo)entry.getValue(); + if (existing.networkInfo.isConnected() && + request.networkCapabilities.satisfiedByNetworkCapabilities( + existing.networkCapabilities) && + (alternative == null || + alternative.currentScore < existing.currentScore)) { + alternative = existing; + } + } + if (alternative != null && !toActivate.contains(alternative)) { + toActivate.add(alternative); + } } } if (nai.networkRequests.get(mDefaultRequest.requestId) != null) { removeDataActivityTracking(nai); } + for (NetworkAgentInfo networkToActivate : toActivate) { + networkToActivate.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); + } } } @@ -5070,7 +5088,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(), new NetworkInfo(networkInfo), new LinkProperties(linkProperties), - new NetworkCapabilities(networkCapabilities), currentScore); + new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai)); } @@ -5238,14 +5256,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { currentNetwork.networkRequests.remove(nr.requestId); currentNetwork.networkListens.add(nr); if (currentNetwork.networkRequests.size() == 0) { - // TODO tell current Network to go to linger state - - // fake the linger state: - Message message = Message.obtain(); - message.obj = currentNetwork; - message.what = NetworkMonitorProtocol.EVENT_NETWORK_LINGER_COMPLETE; - mTrackerHandler.sendMessage(message); - + currentNetwork.networkMonitor.sendMessage( + NetworkMonitor.CMD_NETWORK_LINGER); notifyNetworkCallbacks(currentNetwork, NetworkCallbacks.LOSING); } } @@ -5301,7 +5313,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType); // } catch (RemoteException e) { } notifyNetworkCallbacks(newNetwork, NetworkCallbacks.AVAILABLE); - } else { + } else if (newNetwork.networkRequests.size() == 0) { if (VDBG) log("Validated network turns out to be unwanted. Tear it down."); newNetwork.asyncChannel.disconnect(); } @@ -5331,13 +5343,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } updateLinkProperties(networkAgent, null); notifyNetworkCallbacks(networkAgent, NetworkCallbacks.PRECHECK); - // TODO - kick the network monitor - - // Fake things by sending self a NETWORK_VALIDATED msg - Message message = Message.obtain(); - message.obj = networkAgent; - message.what = NetworkMonitorProtocol.EVENT_NETWORK_VALIDATED; - mTrackerHandler.sendMessage(message); + networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); } else if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.SUSPENDED) { networkAgent.asyncChannel.disconnect(); diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 4747487705..0c568b73f9 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -16,15 +16,18 @@ package com.android.server.connectivity; +import android.content.Context; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkRequest; +import android.os.Handler; import android.os.Messenger; import android.util.SparseArray; import com.android.internal.util.AsyncChannel; +import com.android.server.connectivity.NetworkMonitor; import java.util.ArrayList; @@ -40,6 +43,8 @@ public class NetworkAgentInfo { public LinkProperties linkProperties; public NetworkCapabilities networkCapabilities; public int currentScore; + public final NetworkMonitor networkMonitor; + // The list of NetworkRequests being satisfied by this Network. public final SparseArray networkRequests = new SparseArray(); @@ -50,7 +55,8 @@ public class NetworkAgentInfo { public final AsyncChannel asyncChannel; public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, int netId, NetworkInfo info, - LinkProperties lp, NetworkCapabilities nc, int score) { + LinkProperties lp, NetworkCapabilities nc, int score, Context context, + Handler handler) { this.messenger = messenger; asyncChannel = ac; network = new Network(netId); @@ -58,7 +64,7 @@ public class NetworkAgentInfo { linkProperties = lp; networkCapabilities = nc; currentScore = score; - + networkMonitor = new NetworkMonitor(context, handler, this); } public String toString() { From c206e65756fc550ae487df1746a96a605e379f6a Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Mon, 12 May 2014 17:39:09 -0400 Subject: [PATCH 231/296] Disable calls to MobileDataStateTracker.isProvisioning() as there is no more MobileDataStateTracker so these just crash. Change-Id: Ib45a85db505c0a99fb65d9a6d0c39b860f9d019d --- .../core/java/com/android/server/ConnectivityService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 752dce9187..1e29d7c52e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -4176,7 +4176,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { CheckMp.Params params = new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); if (DBG) log("checkMobileProvisioning: params=" + params); - checkMp.execute(params); + // TODO: Reenable when calls to the now defunct + // MobileDataStateTracker.isProvisioningNetwork() are removed. + // This code should be moved to the Telephony code. + // checkMp.execute(params); } finally { Binder.restoreCallingIdentity(token); if (DBG) log("checkMobileProvisioning: X"); From 52f1e4631e8650a9901934c5f5d241d550ecd6c8 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 14 May 2014 01:42:29 -0700 Subject: [PATCH 232/296] Fix compile errors after merge. These are due to changes to ConnectivityService that were made after master-multinetwork-dev branched off. They mostly didn't cause merge conflicts because they were in different parts of the file from the multinetwork changes, but they cause compile errors now. These particular changes should be fine - they are all in dead code anyway, and their functionality had already been re-implemented in the new code. Change-Id: I0ac9e39c3c975c8e8dc04ad11b6b85366693865c --- .../android/server/ConnectivityService.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1e29d7c52e..a9d226edaf 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1908,9 +1908,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { int thisNetId = mNetTrackers[prevNetType].getNetwork().netId; // Remove idletimer previously setup in {@code handleConnect} - if (mNetConfigs[prevNetType].isDefault()) { - removeDataActivityTracking(prevNetType); - } +// Already in place in new function. This is dead code. +// if (mNetConfigs[prevNetType].isDefault()) { +// removeDataActivityTracking(prevNetType); +// } /* * If the disconnected network is not the active one, then don't report @@ -1977,7 +1978,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } // do this before we broadcast the change - handleConnectivityChange(prevNetType, doReset); +// Already done in new function. This is dead code. +// handleConnectivityChange(prevNetType, doReset); final Intent immediateIntent = new Intent(intent); immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); @@ -2246,7 +2248,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { teardown(thisNet); return; } - setupDataActivityTracking(newNetType); +// Already in place in new function. This is dead code. +// setupDataActivityTracking(newNetType); synchronized (ConnectivityService.this) { // have a new default network, release the transition wakelock in a second // if it's held. The second pause is to allow apps to reconnect over the @@ -2285,8 +2288,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } thisNet.setTeardownRequested(false); - updateMtuSizeSettings(thisNet); - handleConnectivityChange(newNetType, false); +// Already in place in new function. This is dead code. +// updateMtuSizeSettings(thisNet); +// handleConnectivityChange(newNetType, false); sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); // notify battery stats service about this network From 3927e336e747b3a74adc0a94e28c5b3767b65adb Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 13 May 2014 11:44:01 -0400 Subject: [PATCH 233/296] Get clatd/Nat464Xlat working with new NetworkAgents. Change-Id: I65dfb59ce519a42bdb872940d229039b5403fd92 --- .../android/server/ConnectivityService.java | 45 ++++++------- .../server/connectivity/Nat464Xlat.java | 63 +++++++++++-------- 2 files changed, 61 insertions(+), 47 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index a9d226edaf..71977d38ee 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2486,26 +2486,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - // Update 464xlat state. - NetworkStateTracker tracker = mNetTrackers[netType]; - if (mClat.requiresClat(netType, tracker)) { - - // If the connection was previously using clat, but is not using it now, stop the clat - // daemon. Normally, this happens automatically when the connection disconnects, but if - // the disconnect is not reported, or if the connection's LinkProperties changed for - // some other reason (e.g., handoff changes the IP addresses on the link), it would - // still be running. If it's not running, then stopping it is a no-op. - if (Nat464Xlat.isRunningClat(curLp) && !Nat464Xlat.isRunningClat(newLp)) { - mClat.stopClat(); - } - // If the link requires clat to be running, then start the daemon now. - if (mNetTrackers[netType].getNetworkInfo().isConnected()) { - mClat.startClat(tracker); - } else { - mClat.stopClat(); - } - } - // TODO: Temporary notifying upstread change to Tethering. // @see bug/4455071 /** Notify TetheringService if interface name has been changed. */ @@ -3073,7 +3053,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } notifyNetworkCallbacks(nai, NetworkCallbacks.LOST); nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); - mNetworkAgentInfos.remove(nai); + mNetworkAgentInfos.remove(msg.replyTo); + updateClat(null, nai.linkProperties, nai); // Since we've lost the network, go through all the requests that // it was satisfying and see if any other factory can satisfy them. final ArrayList toActivate = new ArrayList(); @@ -5121,6 +5102,28 @@ public class ConnectivityService extends IConnectivityManager.Stub { // } updateRoutes(newLp, oldLp, netId); updateDnses(newLp, oldLp, netId); + updateClat(newLp, oldLp, networkAgent); + } + + private void updateClat(LinkProperties newLp, LinkProperties oldLp, NetworkAgentInfo na) { + // Update 464xlat state. + if (mClat.requiresClat(na)) { + + // If the connection was previously using clat, but is not using it now, stop the clat + // daemon. Normally, this happens automatically when the connection disconnects, but if + // the disconnect is not reported, or if the connection's LinkProperties changed for + // some other reason (e.g., handoff changes the IP addresses on the link), it would + // still be running. If it's not running, then stopping it is a no-op. + if (Nat464Xlat.isRunningClat(oldLp) && !Nat464Xlat.isRunningClat(newLp)) { + mClat.stopClat(); + } + // If the link requires clat to be running, then start the daemon now. + if (newLp != null && na.networkInfo.isConnected()) { + mClat.startClat(na); + } else { + mClat.stopClat(); + } + } } private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) { diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index a15d678520..3884ab057b 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -25,11 +25,12 @@ import android.net.IConnectivityManager; import android.net.InterfaceConfiguration; import android.net.LinkAddress; import android.net.LinkProperties; -import android.net.NetworkStateTracker; +import android.net.NetworkAgent; import android.net.NetworkUtils; import android.net.RouteInfo; import android.os.Handler; import android.os.Message; +import android.os.Messenger; import android.os.INetworkManagementService; import android.os.RemoteException; import android.util.Slog; @@ -45,15 +46,18 @@ public class Nat464Xlat extends BaseNetworkObserver { private Context mContext; private INetworkManagementService mNMService; private IConnectivityManager mConnService; - private NetworkStateTracker mTracker; - private Handler mHandler; - // Whether we started clatd and expect it to be running. private boolean mIsStarted; // Whether the clatd interface exists (i.e., clatd is running). private boolean mIsRunning; // The LinkProperties of the clat interface. private LinkProperties mLP; + // Current LinkProperties of the network. Includes mLP as a stacked link when clat is active. + private LinkProperties mBaseLP; + // ConnectivityService Handler for LinkProperties updates. + private Handler mHandler; + // Marker to connote which network we're augmenting. + private Messenger mNetworkMessenger; // This must match the interface name in clatd.conf. private static final String CLAT_INTERFACE_NAME = "clat4"; @@ -73,14 +77,13 @@ public class Nat464Xlat extends BaseNetworkObserver { } /** - * Determines whether an interface requires clat. - * @param netType the network type (one of the - * android.net.ConnectivityManager.TYPE_* constants) - * @param tracker the NetworkStateTracker corresponding to the network type. - * @return true if the interface requires clat, false otherwise. + * Determines whether a network requires clat. + * @param network the NetworkAgentInfo corresponding to the network. + * @return true if the network requires clat, false otherwise. */ - public boolean requiresClat(int netType, NetworkStateTracker tracker) { - LinkProperties lp = tracker.getLinkProperties(); + public boolean requiresClat(NetworkAgentInfo network) { + int netType = network.networkInfo.getType(); + LinkProperties lp = network.linkProperties; // Only support clat on mobile for now. Slog.d(TAG, "requiresClat: netType=" + netType + ", hasIPv4Address=" + lp.hasIPv4Address()); @@ -95,13 +98,18 @@ public class Nat464Xlat extends BaseNetworkObserver { * Starts the clat daemon. * @param lp The link properties of the interface to start clatd on. */ - public void startClat(NetworkStateTracker tracker) { + public void startClat(NetworkAgentInfo network) { + if (mNetworkMessenger != null && mNetworkMessenger != network.messenger) { + Slog.e(TAG, "startClat: too many networks requesting clat"); + return; + } + mNetworkMessenger = network.messenger; + LinkProperties lp = network.linkProperties; + mBaseLP = new LinkProperties(lp); if (mIsStarted) { Slog.e(TAG, "startClat: already started"); return; } - mTracker = tracker; - LinkProperties lp = mTracker.getLinkProperties(); String iface = lp.getInterfaceName(); Slog.i(TAG, "Starting clatd on " + iface + ", lp=" + lp); try { @@ -125,7 +133,8 @@ public class Nat464Xlat extends BaseNetworkObserver { } mIsStarted = false; mIsRunning = false; - mTracker = null; + mNetworkMessenger = null; + mBaseLP = null; mLP.clear(); } else { Slog.e(TAG, "stopClat: already stopped"); @@ -140,6 +149,14 @@ public class Nat464Xlat extends BaseNetworkObserver { return mIsRunning; } + private void updateConnectivityService() { + Message msg = mHandler.obtainMessage( + NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, mBaseLP); + msg.replyTo = mNetworkMessenger; + Slog.i(TAG, "sending message to ConnectivityService: " + msg); + msg.sendToTarget(); + } + @Override public void interfaceAdded(String iface) { if (iface.equals(CLAT_INTERFACE_NAME)) { @@ -165,19 +182,12 @@ public class Nat464Xlat extends BaseNetworkObserver { clatAddress.getAddress(), iface); mLP.addRoute(ipv4Default); mLP.addLinkAddress(clatAddress); - mTracker.addStackedLink(mLP); - Slog.i(TAG, "Adding stacked link. tracker LP: " + - mTracker.getLinkProperties()); + mBaseLP.addStackedLink(mLP); + Slog.i(TAG, "Adding stacked link. tracker LP: " + mBaseLP); + updateConnectivityService(); } catch(RemoteException e) { Slog.e(TAG, "Error getting link properties: " + e); } - - // Inform ConnectivityService that things have changed. - Message msg = mHandler.obtainMessage( - NetworkStateTracker.EVENT_CONFIGURATION_CHANGED, - mTracker.getNetworkInfo()); - Slog.i(TAG, "sending message to ConnectivityService: " + msg); - msg.sendToTarget(); } } @@ -192,8 +202,9 @@ public class Nat464Xlat extends BaseNetworkObserver { Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + " removed, mIsRunning = " + mIsRunning + " -> false"); mIsRunning = false; - mTracker.removeStackedLink(mLP); + mBaseLP.removeStackedLink(mLP); mLP.clear(); + updateConnectivityService(); Slog.i(TAG, "mLP = " + mLP); } } From be46b75c3b18ddf9f993a56949187fc22871bb66 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 13 May 2014 21:41:06 -0700 Subject: [PATCH 234/296] Handle legacy synchronous inspectors getNetworkInfo, getActiveNetworkInfo, etc Conflicts: services/core/java/com/android/server/ConnectivityService.java Change-Id: I4611d6481b1a76fe4a4ce22232a2a329de2a6e0c --- .../android/server/ConnectivityService.java | 161 +++++++++++++----- 1 file changed, 120 insertions(+), 41 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 71977d38ee..71231200ff 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -25,6 +25,15 @@ import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_DUMMY; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; +import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; +import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; +import static android.net.ConnectivityManager.TYPE_MOBILE_DUN; +import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; +import static android.net.ConnectivityManager.TYPE_MOBILE_IMS; +import static android.net.ConnectivityManager.TYPE_MOBILE_CBS; +import static android.net.ConnectivityManager.TYPE_MOBILE_IA; +import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI; +import static android.net.ConnectivityManager.TYPE_NONE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.ConnectivityManager.TYPE_PROXY; @@ -248,6 +257,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private NetworkStateTracker mNetTrackers[]; + /** + * Holds references to all NetworkAgentInfos claiming to support the legacy + * NetworkType. We used to have a static set of of NetworkStateTrackers + * for each network type. This is the new model. + * Supports synchronous inspection of state. + * These are built out at startup such that an unsupported network + * doesn't get an ArrayList instance, making this a tristate: + * unsupported, supported but not active and active. + */ + private ArrayList mNetworkAgentInfoForType[]; + /* Handles captive portal check on a network */ private CaptivePortalTracker mCaptivePortalTracker; @@ -531,6 +551,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( com.android.internal.R.integer.config_networkTransitionTimeout); + mNetworkAgentInfoForType = (ArrayList[]) + new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1]; + mNetTrackers = new NetworkStateTracker[ ConnectivityManager.MAX_NETWORK_TYPE+1]; mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1]; @@ -585,6 +608,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { "radio " + n.radio + " in network type " + n.type); continue; } + mNetworkAgentInfoForType[n.type] = new ArrayList(); + mNetConfigs[n.type] = n; mNetworksDefined++; } catch(Exception e) { @@ -871,11 +896,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { * Check if UID should be blocked from using the network represented by the * given {@link NetworkStateTracker}. */ - private boolean isNetworkBlocked(NetworkStateTracker tracker, int uid) { - final String iface = tracker.getLinkProperties().getInterfaceName(); - + private boolean isNetworkBlocked(int networkType, int uid) { final boolean networkCostly; final int uidRules; + + LinkProperties lp = getLinkPropertiesForType(networkType); + final String iface = (lp == null ? "" : lp.getInterfaceName()); synchronized (mRulesLock) { networkCostly = mMeteredIfaces.contains(iface); uidRules = mUidRules.get(uid, RULE_ALLOW_ALL); @@ -892,11 +918,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * Return a filtered {@link NetworkInfo}, potentially marked * {@link DetailedState#BLOCKED} based on - * {@link #isNetworkBlocked(NetworkStateTracker, int)}. + * {@link #isNetworkBlocked}. */ - private NetworkInfo getFilteredNetworkInfo(NetworkStateTracker tracker, int uid) { - NetworkInfo info = tracker.getNetworkInfo(); - if (isNetworkBlocked(tracker, uid)) { + private NetworkInfo getFilteredNetworkInfo(int networkType, int uid) { + NetworkInfo info = getNetworkInfoForType(networkType); + if (isNetworkBlocked(networkType, uid)) { // network is blocked; clone and override state info = new NetworkInfo(info); info.setDetailedState(DetailedState.BLOCKED, null, null); @@ -921,6 +947,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { return getNetworkInfo(mActiveDefaultNetwork, uid); } + // only called when the default request is satisfied + private void updateActiveDefaultNetwork(NetworkAgentInfo nai) { + if (nai != null) { + mActiveDefaultNetwork = nai.networkInfo.getType(); + } else { + mActiveDefaultNetwork = TYPE_NONE; + } + } + /** * Find the first Provisioning network. * @@ -963,10 +998,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { public NetworkInfo getActiveNetworkInfoUnfiltered() { enforceAccessPermission(); if (isNetworkTypeValid(mActiveDefaultNetwork)) { - final NetworkStateTracker tracker = mNetTrackers[mActiveDefaultNetwork]; - if (tracker != null) { - return tracker.getNetworkInfo(); - } + return getNetworkInfoForType(mActiveDefaultNetwork); } return null; } @@ -987,9 +1019,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private NetworkInfo getNetworkInfo(int networkType, int uid) { NetworkInfo info = null; if (isNetworkTypeValid(networkType)) { - final NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - info = getFilteredNetworkInfo(tracker, uid); + if (getNetworkInfoForType(networkType) != null) { + info = getFilteredNetworkInfo(networkType, uid); } } return info; @@ -1001,9 +1032,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { final int uid = Binder.getCallingUid(); final ArrayList result = Lists.newArrayList(); synchronized (mRulesLock) { - for (NetworkStateTracker tracker : mNetTrackers) { - if (tracker != null) { - result.add(getFilteredNetworkInfo(tracker, uid)); + for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE; + networkType++) { + if (getNetworkInfoForType(networkType) != null) { + result.add(getFilteredNetworkInfo(networkType, uid)); } } } @@ -1013,7 +1045,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public boolean isNetworkSupported(int networkType) { enforceAccessPermission(); - return (isNetworkTypeValid(networkType) && (mNetTrackers[networkType] != null)); + return (isNetworkTypeValid(networkType) && (getNetworkInfoForType(networkType) != null)); } /** @@ -1033,25 +1065,25 @@ public class ConnectivityService extends IConnectivityManager.Stub { public LinkProperties getLinkProperties(int networkType) { enforceAccessPermission(); if (isNetworkTypeValid(networkType)) { - final NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - return tracker.getLinkProperties(); - } + return getLinkPropertiesForType(networkType); } return null; } + // TODO - this should be ALL networks @Override public NetworkState[] getAllNetworkState() { enforceAccessPermission(); final int uid = Binder.getCallingUid(); final ArrayList result = Lists.newArrayList(); synchronized (mRulesLock) { - for (NetworkStateTracker tracker : mNetTrackers) { - if (tracker != null) { - final NetworkInfo info = getFilteredNetworkInfo(tracker, uid); - result.add(new NetworkState( - info, tracker.getLinkProperties(), tracker.getNetworkCapabilities())); + for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE; + networkType++) { + if (getNetworkInfoForType(networkType) != null) { + final NetworkInfo info = getFilteredNetworkInfo(networkType, uid); + final LinkProperties lp = getLinkPropertiesForType(networkType); + final NetworkCapabilities netcap = getNetworkCapabilitiesForType(networkType); + result.add(new NetworkState(info, lp, netcap)); } } } @@ -1060,10 +1092,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { private NetworkState getNetworkStateUnchecked(int networkType) { if (isNetworkTypeValid(networkType)) { - final NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - return new NetworkState(tracker.getNetworkInfo(), tracker.getLinkProperties(), - tracker.getNetworkCapabilities()); + NetworkInfo info = getNetworkInfoForType(networkType); + if (info != null) { + return new NetworkState(info, + getLinkPropertiesForType(networkType), + getNetworkCapabilitiesForType(networkType)); } } return null; @@ -2308,7 +2341,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { public void captivePortalCheckCompleted(NetworkInfo info, boolean isCaptivePortal) { enforceConnectivityInternalPermission(); if (DBG) log("captivePortalCheckCompleted: ni=" + info + " captive=" + isCaptivePortal); - mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal); +// mNetTrackers[info.getType()].captivePortalCheckCompleted(isCaptivePortal); } /** @@ -3035,7 +3068,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION); } else { loge("Error connecting NetworkAgent"); - mNetworkAgentInfos.remove(msg.replyTo); + NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo); + try { + mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai); + } catch (NullPointerException e) {} } } } @@ -3055,6 +3091,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); mNetworkAgentInfos.remove(msg.replyTo); updateClat(null, nai.linkProperties, nai); + try { + mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai); + } catch (NullPointerException e) {} + // Since we've lost the network, go through all the requests that // it was satisfying and see if any other factory can satisfy them. final ArrayList toActivate = new ArrayList(); @@ -3082,6 +3122,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (nai.networkRequests.get(mDefaultRequest.requestId) != null) { removeDataActivityTracking(nai); + mActiveDefaultNetwork = ConnectivityManager.TYPE_NONE; } for (NetworkAgentInfo networkToActivate : toActivate) { networkToActivate.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); @@ -3396,7 +3437,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // if (DBG) log("no change in condition - aborting"); // return; //} - NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); + NetworkInfo networkInfo = getNetworkInfoForType(mActiveDefaultNetwork); if (networkInfo.isConnected() == false) { if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring"); return; @@ -4652,11 +4693,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // otherwise launch browser with the intent directly. if (mIsProvisioningNetwork.get()) { if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch"); - mIsStartingProvisioning.set(true); - MobileDataStateTracker mdst = (MobileDataStateTracker) - mNetTrackers[ConnectivityManager.TYPE_MOBILE]; - mdst.setEnableFailFastMobileData(DctConstants.ENABLED); - mdst.enableMobileProvisioning(url); +// mIsStartingProvisioning.set(true); +// MobileDataStateTracker mdst = (MobileDataStateTracker) +// mNetTrackers[ConnectivityManager.TYPE_MOBILE]; +// mdst.setEnableFailFastMobileData(DctConstants.ENABLED); +// mdst.enableMobileProvisioning(url); } else { if (DBG) log("handleMobileProvisioningAction: not prov network"); // Check for apps that can handle provisioning first @@ -4952,7 +4993,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public LinkQualityInfo getLinkQualityInfo(int networkType) { enforceAccessPermission(); - if (isNetworkTypeValid(networkType)) { + if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) { return mNetTrackers[networkType].getLinkQualityInfo(); } else { return null; @@ -4962,7 +5003,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public LinkQualityInfo getActiveLinkQualityInfo() { enforceAccessPermission(); - if (isNetworkTypeValid(mActiveDefaultNetwork)) { + if (isNetworkTypeValid(mActiveDefaultNetwork) && + mNetTrackers[mActiveDefaultNetwork] != null) { return mNetTrackers[mActiveDefaultNetwork].getLinkQualityInfo(); } else { return null; @@ -5084,6 +5126,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleRegisterNetworkAgent(NetworkAgentInfo na) { if (VDBG) log("Got NetworkAgent Messenger"); mNetworkAgentInfos.put(na.messenger, na); + try { + mNetworkAgentInfoForType[na.networkInfo.getType()].add(na); + } catch (NullPointerException e) { + loge("registered NetworkAgent for unsupported type: " + na); + } na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger); NetworkInfo networkInfo = na.networkInfo; na.networkInfo = null; @@ -5280,6 +5327,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { sendUpdatedScoreToFactories(nr, newNetwork.currentScore); if (mDefaultRequest.requestId == nr.requestId) { isNewDefault = true; + updateActiveDefaultNetwork(newNetwork); } } } @@ -5344,6 +5392,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { (oldInfo == null ? "null" : oldInfo.getState()) + " to " + state); } + if (state == NetworkInfo.State.CONNECTED) { // TODO - check if we want it (optimization) try { @@ -5415,4 +5464,34 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } + + private LinkProperties getLinkPropertiesForType(int networkType) { + ArrayList list = mNetworkAgentInfoForType[networkType]; + if (list == null) return null; + try { + return new LinkProperties(list.get(0).linkProperties); + } catch (IndexOutOfBoundsException e) { + return new LinkProperties(); + } + } + + private NetworkInfo getNetworkInfoForType(int networkType) { + ArrayList list = mNetworkAgentInfoForType[networkType]; + if (list == null) return null; + try { + return new NetworkInfo(list.get(0).networkInfo); + } catch (IndexOutOfBoundsException e) { + return new NetworkInfo(networkType, 0, "Unknown", ""); + } + } + + private NetworkCapabilities getNetworkCapabilitiesForType(int networkType) { + ArrayList list = mNetworkAgentInfoForType[networkType]; + if (list == null) return null; + try { + return new NetworkCapabilities(list.get(0).networkCapabilities); + } catch (IndexOutOfBoundsException e) { + return new NetworkCapabilities(); + } + } } From f99b8393d64b70fdd8afbdbf755a8dfffc9edce7 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 26 Mar 2014 16:47:06 -0700 Subject: [PATCH 235/296] Add Multinetwork API Change-Id: I3a9cef0d416db96d05098dd989ee3fef3b1e9274 (cherry picked from commit cc5e6afa1ba0bef099bcb21a64a36bc2bf7951db) --- .../java/android/net/ConnectivityManager.java | 411 ++++++++++++++++- .../android/net/IConnectivityManager.aidl | 27 +- .../android/server/ConnectivityService.java | 429 ++++++++++++++++-- .../server/connectivity/NetworkAgentInfo.java | 3 +- 4 files changed, 809 insertions(+), 61 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1ee4ec0990..e14f555513 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -13,26 +13,35 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package android.net; import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.app.PendingIntent; import android.content.Context; import android.os.Binder; import android.os.Build.VERSION_CODES; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; import android.os.INetworkActivityListener; import android.os.INetworkManagementService; +import android.os.Looper; +import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; import android.util.ArrayMap; +import android.util.Log; import java.net.InetAddress; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.HashMap; + +import com.android.internal.util.Protocol; /** * Class that answers queries about the state of network connectivity. It also @@ -699,7 +708,25 @@ public class ConnectivityManager { */ public LinkProperties getLinkProperties(int networkType) { try { - return mService.getLinkProperties(networkType); + return mService.getLinkPropertiesForType(networkType); + } catch (RemoteException e) { + return null; + } + } + + /** {@hide} */ + public LinkProperties getLinkProperties(Network network) { + try { + return mService.getLinkProperties(network); + } catch (RemoteException e) { + return null; + } + } + + /** {@hide} */ + public NetworkCapabilities getNetworkCapabilities(Network network) { + try { + return mService.getNetworkCapabilities(network); } catch (RemoteException e) { return null; } @@ -1302,6 +1329,22 @@ public class ConnectivityManager { } } + /** + * Report a problem network to the framework. This will cause the framework + * to evaluate the situation and try to fix any problems. Note that false + * may be subsequently ignored. + * + * @param network The Network the application was attempting to use or null + * to indicate the current default network. + * {@hide} + */ + public void reportBadNetwork(Network network) { + try { + mService.reportBadNetwork(network); + } catch (RemoteException e) { + } + } + /** * Set a network-independent global http proxy. This is not normally what you want * for typical HTTP proxies - they are general network dependent. However if you're @@ -1599,15 +1642,27 @@ public class ConnectivityManager { } catch (RemoteException e) { } } - /** Interface for NetworkRequest callbacks {@hide} */ + /** + * Interface for NetworkRequest callbacks. Used for notifications about network + * changes. + * @hide + */ public static class NetworkCallbacks { + /** @hide */ public static final int PRECHECK = 1; + /** @hide */ public static final int AVAILABLE = 2; + /** @hide */ public static final int LOSING = 3; + /** @hide */ public static final int LOST = 4; + /** @hide */ public static final int UNAVAIL = 5; + /** @hide */ public static final int CAP_CHANGED = 6; + /** @hide */ public static final int PROP_CHANGED = 7; + /** @hide */ public static final int CANCELED = 8; /** @@ -1650,21 +1705,361 @@ public class ConnectivityManager { * Called when the network the framework connected to for this request * changes capabilities but still satisfies the stated need. */ - public void onCapabilitiesChanged(NetworkRequest networkRequest, Network network, + public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network, NetworkCapabilities networkCapabilities) {} /** * Called when the network the framework connected to for this request - * changes properties. + * changes LinkProperties. */ - public void onPropertiesChanged(NetworkRequest networkRequest, Network network, + public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network, LinkProperties linkProperties) {} /** - * Called when a CancelRequest call concludes and the registered callbacks will + * Called when a releaseNetworkRequest call concludes and the registered callbacks will * no longer be used. */ - public void onCanceled(NetworkRequest networkRequest) {} + public void onReleased(NetworkRequest networkRequest) {} } + private static final int BASE = Protocol.BASE_CONNECTIVITY_MANAGER; + /** @hide obj = pair(NetworkRequest, Network) */ + public static final int CALLBACK_PRECHECK = BASE + 1; + /** @hide obj = pair(NetworkRequest, Network) */ + public static final int CALLBACK_AVAILABLE = BASE + 2; + /** @hide obj = pair(NetworkRequest, Network), arg1 = ttl */ + public static final int CALLBACK_LOSING = BASE + 3; + /** @hide obj = pair(NetworkRequest, Network) */ + public static final int CALLBACK_LOST = BASE + 4; + /** @hide obj = NetworkRequest */ + public static final int CALLBACK_UNAVAIL = BASE + 5; + /** @hide obj = pair(NetworkRequest, Network) */ + public static final int CALLBACK_CAP_CHANGED = BASE + 6; + /** @hide obj = pair(NetworkRequest, Network) */ + public static final int CALLBACK_IP_CHANGED = BASE + 7; + /** @hide obj = NetworkRequest */ + public static final int CALLBACK_RELEASED = BASE + 8; + /** @hide */ + public static final int CALLBACK_EXIT = BASE + 9; + + private static class CallbackHandler extends Handler { + private final HashMapmCallbackMap; + private final AtomicInteger mRefCount; + private static final String TAG = "ConnectivityManager.CallbackHandler"; + private final ConnectivityManager mCm; + + CallbackHandler(Looper looper, HashMapcallbackMap, + AtomicInteger refCount, ConnectivityManager cm) { + super(looper); + mCallbackMap = callbackMap; + mRefCount = refCount; + mCm = cm; + } + + @Override + public void handleMessage(Message message) { + Log.d(TAG, "CM callback handler got msg " + message.what); + switch (message.what) { + case CALLBACK_PRECHECK: { + NetworkRequest request = getNetworkRequest(message); + NetworkCallbacks callbacks = getCallbacks(request); + if (callbacks != null) { + callbacks.onPreCheck(request, getNetwork(message)); + } else { + Log.e(TAG, "callback not found for PRECHECK message"); + } + break; + } + case CALLBACK_AVAILABLE: { + NetworkRequest request = getNetworkRequest(message); + NetworkCallbacks callbacks = getCallbacks(request); + if (callbacks != null) { + callbacks.onAvailable(request, getNetwork(message)); + } else { + Log.e(TAG, "callback not found for AVAILABLE message"); + } + break; + } + case CALLBACK_LOSING: { + NetworkRequest request = getNetworkRequest(message); + NetworkCallbacks callbacks = getCallbacks(request); + if (callbacks != null) { + callbacks.onLosing(request, getNetwork(message), message.arg1); + } else { + Log.e(TAG, "callback not found for LOSING message"); + } + break; + } + case CALLBACK_LOST: { + NetworkRequest request = getNetworkRequest(message); + NetworkCallbacks callbacks = getCallbacks(request); + if (callbacks != null) { + callbacks.onLost(request, getNetwork(message)); + } else { + Log.e(TAG, "callback not found for LOST message"); + } + break; + } + case CALLBACK_UNAVAIL: { + NetworkRequest req = (NetworkRequest)message.obj; + NetworkCallbacks callbacks = null; + synchronized(mCallbackMap) { + callbacks = mCallbackMap.get(req); + } + if (callbacks != null) { + callbacks.onUnavailable(req); + } else { + Log.e(TAG, "callback not found for UNAVAIL message"); + } + break; + } + case CALLBACK_CAP_CHANGED: { + NetworkRequest request = getNetworkRequest(message); + NetworkCallbacks callbacks = getCallbacks(request); + if (callbacks != null) { + Network network = getNetwork(message); + NetworkCapabilities cap = mCm.getNetworkCapabilities(network); + + callbacks.onNetworkCapabilitiesChanged(request, network, cap); + } else { + Log.e(TAG, "callback not found for CHANGED message"); + } + break; + } + case CALLBACK_IP_CHANGED: { + NetworkRequest request = getNetworkRequest(message); + NetworkCallbacks callbacks = getCallbacks(request); + if (callbacks != null) { + Network network = getNetwork(message); + LinkProperties lp = mCm.getLinkProperties(network); + + callbacks.onLinkPropertiesChanged(request, network, lp); + } else { + Log.e(TAG, "callback not found for CHANGED message"); + } + break; + } + case CALLBACK_RELEASED: { + NetworkRequest req = (NetworkRequest)message.obj; + NetworkCallbacks callbacks = null; + synchronized(mCallbackMap) { + callbacks = mCallbackMap.remove(req); + } + if (callbacks != null) { + callbacks.onReleased(req); + } else { + Log.e(TAG, "callback not found for CANCELED message"); + } + synchronized(mRefCount) { + if (mRefCount.decrementAndGet() == 0) { + getLooper().quit(); + } + } + break; + } + case CALLBACK_EXIT: { + Log.d(TAG, "Listener quiting"); + getLooper().quit(); + break; + } + } + } + + private NetworkRequest getNetworkRequest(Message msg) { + return (NetworkRequest)(msg.obj); + } + private NetworkCallbacks getCallbacks(NetworkRequest req) { + synchronized(mCallbackMap) { + return mCallbackMap.get(req); + } + } + private Network getNetwork(Message msg) { + return new Network(msg.arg2); + } + private NetworkCallbacks removeCallbacks(Message msg) { + NetworkRequest req = (NetworkRequest)msg.obj; + synchronized(mCallbackMap) { + return mCallbackMap.remove(req); + } + } + } + + private void addCallbackListener() { + synchronized(sCallbackRefCount) { + if (sCallbackRefCount.incrementAndGet() == 1) { + // TODO - switch this over to a ManagerThread or expire it when done + HandlerThread callbackThread = new HandlerThread("ConnectivityManager"); + callbackThread.start(); + sCallbackHandler = new CallbackHandler(callbackThread.getLooper(), + sNetworkCallbacks, sCallbackRefCount, this); + } + } + } + + private void removeCallbackListener() { + synchronized(sCallbackRefCount) { + if (sCallbackRefCount.decrementAndGet() == 0) { + sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget(); + sCallbackHandler = null; + } + } + } + + static final HashMap sNetworkCallbacks = + new HashMap(); + static final AtomicInteger sCallbackRefCount = new AtomicInteger(0); + static CallbackHandler sCallbackHandler = null; + + private final static int LISTEN = 1; + private final static int REQUEST = 2; + + private NetworkRequest somethingForNetwork(NetworkCapabilities need, + NetworkCallbacks networkCallbacks, int timeoutSec, int action) { + NetworkRequest networkRequest = null; + if (networkCallbacks == null) throw new IllegalArgumentException("null NetworkCallbacks"); + if (need == null) throw new IllegalArgumentException("null NetworkCapabilities"); + try { + addCallbackListener(); + if (action == LISTEN) { + networkRequest = mService.listenForNetwork(need, new Messenger(sCallbackHandler), + new Binder()); + } else { + networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler), + timeoutSec, new Binder()); + } + if (networkRequest != null) { + synchronized(sNetworkCallbacks) { + sNetworkCallbacks.put(networkRequest, networkCallbacks); + } + } + } catch (RemoteException e) {} + if (networkRequest == null) removeCallbackListener(); + return networkRequest; + } + + /** + * Request a network to satisfy a set of {@link NetworkCapabilities}. + * + * This {@link NetworkRequest} will live until released via + * {@link releaseNetworkRequest} or the calling application exits. + * Status of the request can be follwed by listening to the various + * callbacks described in {@link NetworkCallbacks}. The {@link Network} + * can be used by using the {@link bindSocketToNetwork}, + * {@link bindApplicationToNetwork} and {@link getAddrInfoOnNetwork} functions. + * + * @param need {@link NetworkCapabilities} required by this request. + * @param networkCallbacks The callbacks to be utilized for this request. Note + * the callbacks can be shared by multiple requests and + * the NetworkRequest token utilized to determine to which + * request the callback relates. + * @return A {@link NetworkRequest} object identifying the request. + * @hide + */ + public NetworkRequest requestNetwork(NetworkCapabilities need, + NetworkCallbacks networkCallbacks) { + return somethingForNetwork(need, networkCallbacks, 0, REQUEST); + } + + /** + * Request a network to satisfy a set of {@link NetworkCapabilities}, limited + * by a timeout. + * + * This function behaves identically, but if a suitable network is not found + * within the given time (in Seconds) the {@link NetworkCallbacks#unavailable} + * callback is called. The request must still be released normally by + * calling {@link releaseNetworkRequest}. + * @param need {@link NetworkCapabilities} required by this request. + * @param networkCallbacks The callbacks to be utilized for this request. Note + * the callbacks can be shared by multiple requests and + * the NetworkRequest token utilized to determine to which + * request the callback relates. + * @param timeoutSec The time in seconds to attempt looking for a suitable network + * before {@link NetworkCallbacks#unavailable} is called. + * @return A {@link NetworkRequest} object identifying the request. + * @hide + */ + public NetworkRequest requestNetwork(NetworkCapabilities need, + NetworkCallbacks networkCallbacks, int timeoutSec) { + return somethingForNetwork(need, networkCallbacks, timeoutSec, REQUEST); + } + + /** + * The maximum number of seconds the framework will look for a suitable network + * during a timeout-equiped call to {@link requestNetwork}. + * {@hide} + */ + public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60; + + /** + * Request a network to satisfy a set of {@link NetworkCapabilities}. + * + * This function behavies identically, but instead of {@link NetworkCallbacks} + * a {@link PendingIntent} is used. This means the request may outlive the + * calling application and get called back when a suitable network is found. + *

      + * The operation is an Intent broadcast that goes to a broadcast receiver that + * you registered with {@link Context#registerReceiver} or through the + * <receiver> tag in an AndroidManifest.xml file + *

      + * The operation Intent is delivered with two extras, a {@link Network} typed + * extra called {@link EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities} + * typed extra called {@link EXTRA_NETWORK_REQUEST_NETWORK_CAPABILTIES} containing + * the original requests parameters. It is important to create a new, + * {@link NetworkCallbacks} based request before completing the processing of the + * Intent to reserve the network or it will be released shortly after the Intent + * is processed. + *

      + * If there is already an request for this Intent registered (with the equality of + * two Intents defined by {@link Intent#filterEquals}), then it will be removed and + * replace by this one, effectively releasing the previous {@link NetworkRequest}. + *

      + * The request may be released normally by calling {@link releaseNetworkRequest}. + * + * @param need {@link NetworkCapabilties} required by this request. + * @param operation Action to perform when the network is available (corresponds + * to the {@link NetworkCallbacks#onAvailable} call. Typically + * comes from {@link PendingIntent#getBroadcast}. + * @return A {@link NetworkRequest} object identifying the request. + * @hide + */ + public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) { + try { + return mService.pendingRequestForNetwork(need, operation); + } catch (RemoteException e) {} + return null; + } + + /** + * Registers to receive notifications about all networks which satisfy the given + * {@link NetworkCapabilities}. The callbacks will continue to be called until + * either the application exits or the request is released using + * {@link releaseNetworkRequest}. + * + * @param need {@link NetworkCapabilities} required by this request. + * @param networkCallbacks The {@link NetworkCallbacks} to be called as suitable + * networks change state. + * @return A {@link NetworkRequest} object identifying the request. + * @hide + */ + public NetworkRequest listenForNetwork(NetworkCapabilities need, + NetworkCallbacks networkCallbacks) { + return somethingForNetwork(need, networkCallbacks, 0, LISTEN); + } + + /** + * Releases a {NetworkRequest} generated either through a {@link requestNetwork} + * or a {@link listenForNetwork} call. The {@link NetworkCallbacks} given in the + * earlier call may continue receiving calls until the {@link NetworkCallbacks#onReleased} + * function is called, signifiying the end of the request. + * + * @param networkRequest The {@link NetworkRequest} generated by an earlier call to + * {@link requestNetwork} or {@link listenForNetwork}. + * @hide + */ + public void releaseNetworkRequest(NetworkRequest networkRequest) { + if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest"); + try { + mService.releaseNetworkRequest(networkRequest); + } catch (RemoteException e) {} + } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 0d2e14db16..885b8b6891 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -16,11 +16,14 @@ package android.net; +import android.app.PendingIntent; import android.net.LinkQualityInfo; import android.net.LinkProperties; +import android.net.Network; import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkQuotaInfo; +import android.net.NetworkRequest; import android.net.NetworkState; import android.net.ProxyInfo; import android.os.IBinder; @@ -52,7 +55,10 @@ interface IConnectivityManager boolean isNetworkSupported(int networkType); LinkProperties getActiveLinkProperties(); - LinkProperties getLinkProperties(int networkType); + LinkProperties getLinkPropertiesForType(int networkType); + LinkProperties getLinkProperties(in Network network); + + NetworkCapabilities getNetworkCapabilities(in Network network); NetworkState[] getAllNetworkState(); @@ -100,6 +106,8 @@ interface IConnectivityManager void reportInetCondition(int networkType, int percentage); + void reportBadNetwork(in Network network); + ProxyInfo getGlobalProxy(); void setGlobalProxy(in ProxyInfo p); @@ -147,5 +155,20 @@ interface IConnectivityManager void registerNetworkFactory(in Messenger messenger); - void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score); + void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, + in NetworkCapabilities nc, int score); + + NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, + in Messenger messenger, int timeoutSec, in IBinder binder); + + NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, + in PendingIntent operation); + + NetworkRequest listenForNetwork(in NetworkCapabilities networkCapabilities, + in Messenger messenger, in IBinder binder); + + void pendingListenForNetwork(in NetworkCapabilities networkCapabilities, + in PendingIntent operation); + + void releaseNetworkRequest(in NetworkRequest networkRequest); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 71231200ff..c8fa7ae839 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -384,7 +384,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14; /** - * user internally to indicate that data sampling interval is up + * used internally to indicate that data sampling interval is up */ private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15; @@ -405,6 +405,32 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_REGISTER_NETWORK_AGENT = 18; + /** + * used to add a network request + * includes a NetworkRequestInfo + */ + private static final int EVENT_REGISTER_NETWORK_REQUEST = 19; + + /** + * indicates a timeout period is over - check if we had a network yet or not + * and if not, call the timeout calback (but leave the request live until they + * cancel it. + * includes a NetworkRequestInfo + */ + private static final int EVENT_TIMEOUT_NETWORK_REQUEST = 20; + + /** + * used to add a network listener - no request + * includes a NetworkRequestInfo + */ + private static final int EVENT_REGISTER_NETWORK_LISTENER = 21; + + /** + * used to remove a network request, either a listener or a real request + * includes a NetworkRequest + */ + private static final int EVENT_RELEASE_NETWORK_REQUEST = 22; + /** Handler used for internal events. */ final private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -498,7 +524,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); mDefaultRequest = new NetworkRequest(netCap, true); - mNetworkRequests.append(mDefaultRequest.requestId, mDefaultRequest); + NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(), + NetworkRequestInfo.REQUEST); + mNetworkRequests.put(mDefaultRequest, nri); HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); handlerThread.start(); @@ -1058,19 +1086,35 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ @Override public LinkProperties getActiveLinkProperties() { - return getLinkProperties(mActiveDefaultNetwork); + return getLinkPropertiesForType(mActiveDefaultNetwork); } @Override - public LinkProperties getLinkProperties(int networkType) { + public LinkProperties getLinkPropertiesForType(int networkType) { enforceAccessPermission(); if (isNetworkTypeValid(networkType)) { - return getLinkPropertiesForType(networkType); + return getLinkPropertiesForTypeInternal(networkType); } return null; } // TODO - this should be ALL networks + @Override + public LinkProperties getLinkProperties(Network network) { + enforceAccessPermission(); + NetworkAgentInfo nai = mNetworkForNetId.get(network.netId); + if (nai != null) return new LinkProperties(nai.linkProperties); + return null; + } + + @Override + public NetworkCapabilities getNetworkCapabilities(Network network) { + enforceAccessPermission(); + NetworkAgentInfo nai = mNetworkForNetId.get(network.netId); + if (nai != null) return new NetworkCapabilities(nai.networkCapabilities); + return null; + } + @Override public NetworkState[] getAllNetworkState() { enforceAccessPermission(); @@ -1081,7 +1125,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { networkType++) { if (getNetworkInfoForType(networkType) != null) { final NetworkInfo info = getFilteredNetworkInfo(networkType, uid); - final LinkProperties lp = getLinkPropertiesForType(networkType); + final LinkProperties lp = getLinkPropertiesForTypeInternal(networkType); final NetworkCapabilities netcap = getNetworkCapabilitiesForType(networkType); result.add(new NetworkState(info, lp, netcap)); } @@ -1095,7 +1139,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkInfo info = getNetworkInfoForType(networkType); if (info != null) { return new NetworkState(info, - getLinkPropertiesForType(networkType), + getLinkPropertiesForTypeInternal(networkType), getNetworkCapabilitiesForType(networkType)); } } @@ -3002,7 +3046,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { * to the link that may have incorrectly setup by the lower * levels. */ - LinkProperties lp = getLinkProperties(info.getType()); + LinkProperties lp = getLinkPropertiesForTypeInternal(info.getType()); if (DBG) { log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp); } @@ -3050,11 +3094,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); // A network factory has connected. Send it all current NetworkRequests. - for (int i = 0; i < mNetworkRequests.size(); i++) { - NetworkRequest request = mNetworkRequests.valueAt(i); - NetworkAgentInfo nai = mNetworkForRequestId.get(request.requestId); + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, - (nai != null ? nai.currentScore : 0), 0, request); + (nai != null ? nai.currentScore : 0), 0, nri.request); } } else { loge("Error connecting NetworkFactory"); @@ -3072,13 +3115,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { try { mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai); } catch (NullPointerException e) {} + if (nai != null) { + mNetworkForNetId.remove(nai.network.netId); + } } } } private void handleAsyncChannelDisconnected(Message msg) { NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); if (nai != null) { - if (DBG) log(nai.name() + " got DISCONNECTED"); + if (DBG) { + log(nai.name() + " got DISCONNECTED, was satisfying " + nai.networkRequests.size()); + } // A network agent has disconnected. // Tell netd to clean up the configuration for this network // (routing rules, DNS, etc). @@ -3087,7 +3135,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (Exception e) { loge("Exception removing network: " + e); } - notifyNetworkCallbacks(nai, NetworkCallbacks.LOST); + notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST); nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); mNetworkAgentInfos.remove(msg.replyTo); updateClat(null, nai.linkProperties, nai); @@ -3095,12 +3143,17 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai); } catch (NullPointerException e) {} + mNetworkForNetId.remove(nai.network.netId); // Since we've lost the network, go through all the requests that // it was satisfying and see if any other factory can satisfy them. final ArrayList toActivate = new ArrayList(); for (int i = 0; i < nai.networkRequests.size(); i++) { NetworkRequest request = nai.networkRequests.valueAt(i); NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId); + if (VDBG) { + log(" checking request " + request + ", currentNetwork = " + + currentNetwork != null ? currentNetwork.name() : "null"); + } if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { mNetworkForRequestId.remove(request.requestId); sendUpdatedScoreToFactories(request, 0); @@ -3130,6 +3183,77 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + private void handleRegisterNetworkRequest(Message msg) { + final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj); + final NetworkCapabilities newCap = nri.request.networkCapabilities; + int score = 0; + + // Check for the best currently alive network that satisfies this request + NetworkAgentInfo bestNetwork = null; + for (NetworkAgentInfo network : mNetworkAgentInfos.values()) { + if (VDBG) log("handleRegisterNetworkRequest checking " + network.name()); + if (newCap.satisfiedByNetworkCapabilities(network.networkCapabilities)) { + if (VDBG) log("apparently satisfied. currentScore=" + network.currentScore); + if ((bestNetwork == null) || bestNetwork.currentScore < network.currentScore) { + bestNetwork = network; + } + } + } + if (bestNetwork != null) { + if (VDBG) log("using " + bestNetwork.name()); + bestNetwork.networkRequests.put(nri.request.requestId, nri.request); + notifyNetworkCallback(bestNetwork, nri); + score = bestNetwork.currentScore; + } + mNetworkRequests.put(nri.request, nri); + if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) { + if (DBG) log("sending new NetworkRequest to factories"); + for (AsyncChannel ac : mNetworkFactories) { + ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); + } + } + } + + private void handleReleaseNetworkRequest(NetworkRequest request) { + if (DBG) log("releasing NetworkRequest " + request); + NetworkRequestInfo nri = mNetworkRequests.remove(request); + if (nri != null) { + // tell the network currently servicing this that it's no longer interested + NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId); + if (affectedNetwork != null) { + affectedNetwork.networkRequests.remove(nri.request.requestId); + if (VDBG) { + log(" Removing from current network " + affectedNetwork.name() + ", leaving " + + affectedNetwork.networkRequests.size() + " requests."); + } + } + + if (nri.isRequest) { + for (AsyncChannel factory : mNetworkFactories) { + factory.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); + } + + if (affectedNetwork != null) { + // check if this network still has live requests - otherwise, tear down + // TODO - probably push this to the NF/NA + boolean keep = false; + for (int i = 0; i < affectedNetwork.networkRequests.size(); i++) { + NetworkRequest r = affectedNetwork.networkRequests.valueAt(i); + if (mNetworkRequests.get(r).isRequest) { + keep = true; + break; + } + } + if (keep == false) { + if (DBG) log("no live requests for " + affectedNetwork.name() + + "; disconnecting"); + affectedNetwork.asyncChannel.disconnect(); + } + } + } + callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_RELEASED); + } + } private class InternalHandler extends Handler { public InternalHandler(Looper looper) { @@ -3232,6 +3356,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleRegisterNetworkAgent((NetworkAgentInfo)msg.obj); break; } + case EVENT_REGISTER_NETWORK_REQUEST: + case EVENT_REGISTER_NETWORK_LISTENER: { + handleRegisterNetworkRequest(msg); + break; + } + case EVENT_RELEASE_NETWORK_REQUEST: { + handleReleaseNetworkRequest((NetworkRequest) msg.obj); + break; + } } } } @@ -3378,6 +3511,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { EVENT_INET_CONDITION_CHANGE, networkType, percentage)); } + public void reportBadNetwork(Network network) { + //TODO + } + private void handleInetConditionChange(int netType, int condition) { if (mActiveDefaultNetwork == -1) { if (DBG) log("handleInetConditionChange: no active default network - ignore"); @@ -4448,7 +4585,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { log("isMobileOk: addresses=" + inetAddressesToString(addresses)); // Get the type of addresses supported by this link - LinkProperties lp = mCs.getLinkProperties( + LinkProperties lp = mCs.getLinkPropertiesForTypeInternal( ConnectivityManager.TYPE_MOBILE_HIPRI); boolean linkHasIpv4 = lp.hasIPv4Address(); boolean linkHasIpv6 = lp.hasIPv6Address(); @@ -5079,7 +5216,109 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private final ArrayList mNetworkFactories = new ArrayList(); + private final HashMap mNetworkRequests = + new HashMap(); + + private class NetworkRequestInfo implements IBinder.DeathRecipient { + static final boolean REQUEST = true; + static final boolean LISTEN = false; + + final NetworkRequest request; + IBinder mBinder; + final int mPid; + final int mUid; + final Messenger messenger; + final boolean isRequest; + + NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, boolean isRequest) { + super(); + messenger = m; + request = r; + mBinder = binder; + mPid = getCallingPid(); + mUid = getCallingUid(); + this.isRequest = isRequest; + + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + binderDied(); + } + } + + void unlinkDeathRecipient() { + mBinder.unlinkToDeath(this, 0); + } + + public void binderDied() { + log("ConnectivityService NetworkRequestInfo binderDied(" + + request + ", " + mBinder + ")"); + releaseNetworkRequest(request); + } + } + + @Override + public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, + Messenger messenger, int timeoutSec, IBinder binder) { + if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) + == false) { + enforceConnectivityInternalPermission(); + } else { + enforceChangePermission(); + } + + if (timeoutSec < 0 || timeoutSec > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_SEC) { + throw new IllegalArgumentException("Bad timeout specified"); + } + NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( + networkCapabilities)); + if (DBG) log("requestNetwork for " + networkRequest); + NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, + NetworkRequestInfo.REQUEST); + + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_REQUEST, nri)); + if (timeoutSec > 0) { + mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_TIMEOUT_NETWORK_REQUEST, + nri), timeoutSec * 1000); + } + return networkRequest; + } + + @Override + public NetworkRequest pendingRequestForNetwork(NetworkCapabilities networkCapabilities, + PendingIntent operation) { + // TODO + return null; + } + + @Override + public NetworkRequest listenForNetwork(NetworkCapabilities networkCapabilities, + Messenger messenger, IBinder binder) { + enforceAccessPermission(); + + NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( + networkCapabilities)); + if (DBG) log("listenForNetwork for " + networkRequest); + NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, + NetworkRequestInfo.LISTEN); + + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_LISTENER, nri)); + return networkRequest; + } + + @Override + public void pendingListenForNetwork(NetworkCapabilities networkCapabilities, + PendingIntent operation) { + } + + @Override + public void releaseNetworkRequest(NetworkRequest networkRequest) { + mHandler.sendMessage(mHandler.obtainMessage(EVENT_RELEASE_NETWORK_REQUEST, + networkRequest)); + } + + @Override public void registerNetworkFactory(Messenger messenger) { enforceConnectivityInternalPermission(); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger)); @@ -5090,11 +5329,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { AsyncChannel ac = new AsyncChannel(); mNetworkFactories.add(ac); ac.connect(mContext, mTrackerHandler, messenger); + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + if (nri.isRequest) { + int score = 0; + NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); + if (currentNetwork != null) score = currentNetwork.currentScore; + ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); + } + } } - // NetworkRequest by requestId - private final SparseArray mNetworkRequests = new SparseArray(); - /** * NetworkAgentInfo supporting a request by requestId. * These have already been vetted (their Capabilities satisfy the request) @@ -5104,6 +5348,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private final SparseArray mNetworkForRequestId = new SparseArray(); + private final SparseArray mNetworkForNetId = + new SparseArray(); + // NetworkAgentInfo keyed off its connecting messenger // TODO - eval if we can reduce the number of lists/hashmaps/sparsearrays private final HashMap mNetworkAgentInfos = @@ -5131,6 +5378,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (NullPointerException e) { loge("registered NetworkAgent for unsupported type: " + na); } + mNetworkForNetId.put(na.network.netId, na); na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger); NetworkInfo networkInfo = na.networkInfo; na.networkInfo = null; @@ -5266,9 +5514,47 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void callCallbackForRequest(NetworkRequest networkRequest, + private void callCallbackForRequest(NetworkRequestInfo nri, NetworkAgentInfo networkAgent, int notificationType) { - // TODO + if (nri.messenger == null) return; // Default request has no msgr + Object o; + int a1 = 0; + int a2 = 0; + switch (notificationType) { + case ConnectivityManager.CALLBACK_LOSING: + a1 = 30; // TODO - read this from NetworkMonitor + // fall through + case ConnectivityManager.CALLBACK_PRECHECK: + case ConnectivityManager.CALLBACK_AVAILABLE: + case ConnectivityManager.CALLBACK_LOST: + case ConnectivityManager.CALLBACK_CAP_CHANGED: + case ConnectivityManager.CALLBACK_IP_CHANGED: { + o = new NetworkRequest(nri.request); + a2 = networkAgent.network.netId; + break; + } + case ConnectivityManager.CALLBACK_UNAVAIL: + case ConnectivityManager.CALLBACK_RELEASED: { + o = new NetworkRequest(nri.request); + break; + } + default: { + loge("Unknown notificationType " + notificationType); + return; + } + } + Message msg = Message.obtain(); + msg.arg1 = a1; + msg.arg2 = a2; + msg.obj = o; + msg.what = notificationType; + try { + if (VDBG) log("sending notification " + notificationType + " for " + nri.request); + nri.messenger.send(msg); + } catch (RemoteException e) { + // may occur naturally in the race of binder death. + loge("RemoteException caught trying to send a callback msg for " + nri.request); + } } private void handleLingerComplete(NetworkAgentInfo oldNetwork) { @@ -5295,13 +5581,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) log("handleConnectionValidated for "+newNetwork.name()); // check if any NetworkRequest wants this NetworkAgent // first check if it satisfies the NetworkCapabilities - for (int i = 0; i < mNetworkRequests.size(); i++) { - NetworkRequest nr = mNetworkRequests.valueAt(i); - if (nr.networkCapabilities.satisfiedByNetworkCapabilities( + ArrayList affectedNetworks = new ArrayList(); + if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities); + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + if (VDBG) log(" checking if request is satisfied: " + nri.request); + if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities( newNetwork.networkCapabilities)) { // next check if it's better than any current network we're using for // this request - NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nr.requestId); + NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); if (VDBG) { log("currentScore = " + (currentNetwork != null ? currentNetwork.currentScore : 0) + @@ -5310,28 +5598,52 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (currentNetwork == null || currentNetwork.currentScore < newNetwork.currentScore) { if (currentNetwork != null) { - currentNetwork.networkRequests.remove(nr.requestId); - currentNetwork.networkListens.add(nr); - if (currentNetwork.networkRequests.size() == 0) { - currentNetwork.networkMonitor.sendMessage( - NetworkMonitor.CMD_NETWORK_LINGER); - notifyNetworkCallbacks(currentNetwork, NetworkCallbacks.LOSING); - } + if (VDBG) log(" accepting network in place of " + currentNetwork.name()); + currentNetwork.networkRequests.remove(nri.request.requestId); + currentNetwork.networkLingered.add(nri.request); + affectedNetworks.add(currentNetwork); + } else { + if (VDBG) log(" accepting network in place of null"); } - mNetworkForRequestId.put(nr.requestId, newNetwork); - newNetwork.networkRequests.put(nr.requestId, nr); + mNetworkForRequestId.put(nri.request.requestId, newNetwork); + newNetwork.networkRequests.put(nri.request.requestId, nri.request); keep = true; // TODO - this could get expensive if we have alot of requests for this // network. Think about if there is a way to reduce this. Push // netid->request mapping to each factory? - sendUpdatedScoreToFactories(nr, newNetwork.currentScore); - if (mDefaultRequest.requestId == nr.requestId) { + sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore); + if (mDefaultRequest.requestId == nri.request.requestId) { isNewDefault = true; updateActiveDefaultNetwork(newNetwork); } } } } + for (NetworkAgentInfo nai : affectedNetworks) { + boolean teardown = true; + for (int i = 0; i < nai.networkRequests.size(); i++) { + NetworkRequest nr = nai.networkRequests.valueAt(i); + try { + if (mNetworkRequests.get(nr).isRequest) { + teardown = false; + } + } catch (Exception e) { + loge("Request " + nr + " not found in mNetworkRequests."); + loge(" it came from request list of " + nai.name()); + } + } + if (teardown) { + nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_LINGER); + notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING); + } else { + // not going to linger, so kill the list of linger networks.. only + // notify them of linger if it happens as the result of gaining another, + // but if they transition and old network stays up, don't tell them of linger + // or very delayed loss + nai.networkLingered.clear(); + if (VDBG) log("Lingered for " + nai.name() + " cleared"); + } + } if (keep) { if (isNewDefault) { if (VDBG) log("Switching to new default network: " + newNetwork); @@ -5370,8 +5682,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { // TODO //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType); // } catch (RemoteException e) { } - notifyNetworkCallbacks(newNetwork, NetworkCallbacks.AVAILABLE); - } else if (newNetwork.networkRequests.size() == 0) { + notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE); + } else { + if (DBG && newNetwork.networkRequests.size() != 0) { + loge("tearing down network with live requests:"); + for (int i=0; i < newNetwork.networkRequests.size(); i++) { + loge(" " + newNetwork.networkRequests.valueAt(i)); + } + } if (VDBG) log("Validated network turns out to be unwanted. Tear it down."); newNetwork.asyncChannel.disconnect(); } @@ -5401,7 +5719,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { loge("Error creating Network " + networkAgent.network.netId); } updateLinkProperties(networkAgent, null); - notifyNetworkCallbacks(networkAgent, NetworkCallbacks.PRECHECK); + notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); } else if (state == NetworkInfo.State.DISCONNECTED || state == NetworkInfo.State.SUSPENDED) { @@ -5409,24 +5727,37 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + // notify only this one new request of the current state + protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) { + int notifyType = ConnectivityManager.CALLBACK_AVAILABLE; + // TODO - read state from monitor to decide what to send. +// if (nai.networkMonitor.isLingering()) { +// notifyType = NetworkCallbacks.LOSING; +// } else if (nai.networkMonitor.isEvaluating()) { +// notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType); +// } + if (nri.request.needsBroadcasts) { + // TODO +// sendNetworkBroadcast(nai, notifyType); + } + callCallbackForRequest(nri, nai, notifyType); + } + protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) { if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name()); boolean needsBroadcasts = false; for (int i = 0; i < networkAgent.networkRequests.size(); i++) { - NetworkRequest request = networkAgent.networkRequests.valueAt(i); - if (request == null) continue; - if (request.needsBroadcasts) needsBroadcasts = true; - callCallbackForRequest(request, networkAgent, notifyType); - } - for (NetworkRequest request : networkAgent.networkListens) { - if (request.needsBroadcasts) needsBroadcasts = true; - callCallbackForRequest(request, networkAgent, notifyType); + NetworkRequest nr = networkAgent.networkRequests.valueAt(i); + NetworkRequestInfo nri = mNetworkRequests.get(nr); + if (VDBG) log(" sending notification for " + nr); + if (nr.needsBroadcasts) needsBroadcasts = true; + callCallbackForRequest(nri, networkAgent, notifyType); } if (needsBroadcasts) { - if (notifyType == NetworkCallbacks.AVAILABLE) { + if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) { sendConnectedBroadcastDelayed(networkAgent.networkInfo, getConnectivityChangeDelay()); - } else if (notifyType == NetworkCallbacks.LOST) { + } else if (notifyType == ConnectivityManager.CALLBACK_LOST) { NetworkInfo info = new NetworkInfo(networkAgent.networkInfo); Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); @@ -5465,7 +5796,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private LinkProperties getLinkPropertiesForType(int networkType) { + private LinkProperties getLinkPropertiesForTypeInternal(int networkType) { ArrayList list = mNetworkAgentInfoForType[networkType]; if (list == null) return null; try { diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 0c568b73f9..8102591ea9 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -48,9 +48,8 @@ public class NetworkAgentInfo { // The list of NetworkRequests being satisfied by this Network. public final SparseArray networkRequests = new SparseArray(); + public final ArrayList networkLingered = new ArrayList(); - // The list of NetworkListens listening for changes on this Network. - public final ArrayList networkListens = new ArrayList(); public final Messenger messenger; public final AsyncChannel asyncChannel; From a6d85c8ea100a1e4f39c06ea38ec7792be5623b3 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 13 May 2014 15:36:27 -0700 Subject: [PATCH 236/296] Add networks and requests to CS.dump Adds debugging. Change-Id: I352dfe970c990fd210f3d1598519e321bbdd6ed5 (cherry picked from commit 9bdf6bd99db56c652ba9a62d91f258d11d19ca9f) --- .../java/android/net/NetworkCapabilities.java | 2 +- core/java/android/net/NetworkInfo.java | 5 +- .../android/server/ConnectivityService.java | 53 +++++++++---------- 3 files changed, 28 insertions(+), 32 deletions(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index b783046c5c..8005e5ca7e 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -323,6 +323,6 @@ public final class NetworkCapabilities implements Parcelable { String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" + mLinkDownBandwidthKbps + "Kbps" : ""); - return "NetworkCapabilities: [" + transports + capabilities + upBand + dnBand + "]"; + return "[" + transports + capabilities + upBand + dnBand + "]"; } } diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 53b1308db6..9e656eecbe 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -420,7 +420,7 @@ public class NetworkInfo implements Parcelable { @Override public String toString() { synchronized (this) { - StringBuilder builder = new StringBuilder("NetworkInfo: "); + StringBuilder builder = new StringBuilder("["); builder.append("type: ").append(getTypeName()).append("[").append(getSubtypeName()). append("], state: ").append(mState).append("/").append(mDetailedState). append(", reason: ").append(mReason == null ? "(unspecified)" : mReason). @@ -429,7 +429,8 @@ public class NetworkInfo implements Parcelable { append(", failover: ").append(mIsFailover). append(", isAvailable: ").append(mIsAvailable). append(", isConnectedToProvisioningNetwork: "). - append(mIsConnectedToProvisioningNetwork); + append(mIsConnectedToProvisioningNetwork). + append("]"); return builder.toString(); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 71231200ff..1857aa9df1 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2834,44 +2834,39 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } - // TODO: add locking to get atomic snapshot - pw.println(); - for (int i = 0; i < mNetTrackers.length; i++) { - final NetworkStateTracker nst = mNetTrackers[i]; - if (nst != null) { - pw.println("NetworkStateTracker for " + getNetworkTypeName(i) + ":"); - pw.increaseIndent(); - if (nst.getNetworkInfo().isConnected()) { - pw.println("Active network: " + nst.getNetworkInfo(). - getTypeName()); - } - pw.println(nst.getNetworkInfo()); - pw.println(nst.getLinkProperties()); - pw.println(nst); - pw.println(); - pw.decreaseIndent(); - } + NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId); + pw.print("Active default network: "); + if (defaultNai == null) { + pw.println("none"); + } else { + pw.println(defaultNai.network.netId); } - - pw.print("Active default network: "); pw.println(getNetworkTypeName(mActiveDefaultNetwork)); pw.println(); - pw.println("Network Requester Pids:"); + pw.println("Current Networks:"); pw.increaseIndent(); - for (int net : mPriorityList) { - String pidString = net + ": "; - for (Integer pid : mNetRequestersPids[net]) { - pidString = pidString + pid.toString() + ", "; + for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { + pw.println(nai.toString()); + pw.increaseIndent(); + pw.println("Requests:"); + pw.increaseIndent(); + for (int i = 0; i < nai.networkRequests.size(); i++) { + pw.println(nai.networkRequests.valueAt(i).toString()); } - pw.println(pidString); + pw.decreaseIndent(); + pw.println("Lingered:"); + pw.increaseIndent(); + for (NetworkRequest nr : nai.networkLingered) pw.println(nr.toString()); + pw.decreaseIndent(); + pw.decreaseIndent(); } - pw.println(); pw.decreaseIndent(); + pw.println(); - pw.println("FeatureUsers:"); + pw.println("Network Requests:"); pw.increaseIndent(); - for (Object requester : mFeatureUsers) { - pw.println(requester.toString()); + for (NetworkRequestInfo nri : mNetworkRequests.values()) { + pw.println(nri.toString()); } pw.println(); pw.decreaseIndent(); From 563d6320408cc2fb5512e82c4acb60675be401bf Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 14 May 2014 07:50:11 -0700 Subject: [PATCH 237/296] Fix Javadoc It's Deprecated for an annotation, but deprecated for a javadoc and case is important. Fix build Change-Id: I355dc1660196c09530b58386f401a85a74d16476 --- core/java/android/net/ConnectivityManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index e14f555513..5c1c2b1d9e 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -547,7 +547,7 @@ public class ConnectivityManager { * @param preference the network type to prefer over all others. It is * unspecified what happens to the old preferred network in the * overall ordering. - * @Deprecated Functionality has been removed as it no longer makes sense, + * @deprecated Functionality has been removed as it no longer makes sense, * with many more than two networks - we'd need an array to express * preference. Instead we use dynamic network properties of * the networks to describe their precedence. @@ -562,7 +562,7 @@ public class ConnectivityManager { * *

      This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. - * @Deprecated Functionality has been removed as it no longer makes sense, + * @deprecated Functionality has been removed as it no longer makes sense, * with many more than two networks - we'd need an array to express * preference. Instead we use dynamic network properties of * the networks to describe their precedence. From 00a2f34c9a56abb1743e298753c881e8cee8efed Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 14 May 2014 08:45:02 -0700 Subject: [PATCH 238/296] Undeprecate funcs until we're ready for api-review Fixing javadoc deprecated tags to fix a checkbuild error breaks the current/api.txt. We're not ready for the api change yet, so back out the comments. Change-Id: Ia95e394da7329c1b9e3876e589c3c2137ba18048 --- core/java/android/net/ConnectivityManager.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 5c1c2b1d9e..a414421aee 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -547,12 +547,13 @@ public class ConnectivityManager { * @param preference the network type to prefer over all others. It is * unspecified what happens to the old preferred network in the * overall ordering. - * @deprecated Functionality has been removed as it no longer makes sense, - * with many more than two networks - we'd need an array to express - * preference. Instead we use dynamic network properties of - * the networks to describe their precedence. */ public void setNetworkPreference(int preference) { + // TODO - deprecate with: + // @deprecated Functionality has been removed as it no longer makes sense, + // with many more than two networks - we'd need an array to express + // preference. Instead we use dynamic network properties of + // the networks to describe their precedence. } /** @@ -562,12 +563,13 @@ public class ConnectivityManager { * *

      This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. - * @deprecated Functionality has been removed as it no longer makes sense, - * with many more than two networks - we'd need an array to express - * preference. Instead we use dynamic network properties of - * the networks to describe their precedence. */ public int getNetworkPreference() { + // TODO - deprecate with: + // @deprecated Functionality has been removed as it no longer makes sense, + // with many more than two networks - we'd need an array to express + // preference. Instead we use dynamic network properties of + // the networks to describe their precedence. return -1; } From 44a242a81dadd2397a362c9d85195d7b4a770597 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Wed, 14 May 2014 14:45:00 -0700 Subject: [PATCH 239/296] Fix reboot loop due to NPE. All that's old is new again: http://ag/63748. Change-Id: I83df48447dbcb7f6edf02bd07abf721b009afa49 --- core/java/android/net/ProxyInfo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 991d9dacd7..ceedd98e77 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -160,6 +160,8 @@ public class ProxyInfo implements Parcelable { } mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; + } else { + mPacFileUrl = Uri.EMPTY; } } From c63e50cd55b1da8ef11857e578c96bc2d2aed74c Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Wed, 14 May 2014 14:45:00 -0700 Subject: [PATCH 240/296] Fix reboot loop due to NPE. All that's old is new again: http://ag/63748. Change-Id: I83df48447dbcb7f6edf02bd07abf721b009afa49 --- core/java/android/net/ProxyInfo.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 991d9dacd7..ceedd98e77 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -160,6 +160,8 @@ public class ProxyInfo implements Parcelable { } mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; + } else { + mPacFileUrl = Uri.EMPTY; } } From ef72c1b9dde311c7d06129dc0383e696032fd7b1 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 14 May 2014 17:37:10 -0700 Subject: [PATCH 241/296] Remove unneed clear in constructor. Keeps all constructors on equal footing. Change-Id: I316d2b058cc2230ff6aa25a6c8785b42b460438d --- core/java/android/net/LinkProperties.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 0a09fcba4e..489b8a51f1 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -89,7 +89,6 @@ public class LinkProperties implements Parcelable { } public LinkProperties() { - clear(); } // copy constructor instead of clone From b1bc7c18748eeab0d08a0660d86917dad7bf1e2d Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Thu, 15 May 2014 12:07:29 -0400 Subject: [PATCH 242/296] Fix reference to ProxyInfo extra Also remove unneeded null check. Change-Id: Ic25d1087f93632a24755b284ede41d870492e25d --- core/java/android/net/ProxyInfo.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index ceedd98e77..7ea6bae83d 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -155,9 +155,6 @@ public class ProxyInfo implements Parcelable { mHost = source.getHost(); mPort = source.getPort(); mPacFileUrl = source.mPacFileUrl; - if (mPacFileUrl == null) { - mPacFileUrl = Uri.EMPTY; - } mExclusionList = source.getExclusionListAsString(); mParsedExclusionList = source.mParsedExclusionList; } else { From fbd7364a0d7f74ed190b3575285ea31f351e499f Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 15 May 2014 15:27:13 -0700 Subject: [PATCH 243/296] Add net.dns system properties Some apps rely on them. bug: 14992618 Change-Id: I5766f26b77004e9cfcc90fac657817eab67f9ac7 --- .../android/server/ConnectivityService.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0708e55d4a..982dce0a73 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5491,10 +5491,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (Exception e) { loge("Exception in setDnsServersForNetwork: " + e); } - // TODO - setprop "net.dnsX" + NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId); + if (defaultNai != null && defaultNai.network.netId == netId) { + setDefaultDnsSystemProperties(dnses); + } } } + private void setDefaultDnsSystemProperties(Collection dnses) { + int last = 0; + for (InetAddress dns : dnses) { + ++last; + String key = "net.dns" + last; + String value = dns.getHostAddress(); + SystemProperties.set(key, value); + } + for (int i = last + 1; i <= mNumDnsEntries; ++i) { + String key = "net.dns" + i; + SystemProperties.set(key, ""); + } + mNumDnsEntries = last; + } + + private void updateCapabilities(NetworkAgentInfo networkAgent, NetworkCapabilities networkCapabilities) { // TODO - what else here? Verify still satisfies everybody? @@ -5610,6 +5629,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mDefaultRequest.requestId == nri.request.requestId) { isNewDefault = true; updateActiveDefaultNetwork(newNetwork); + if (newNetwork.linkProperties != null) { + setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnses()); + } else { + setDefaultDnsSystemProperties(new ArrayList()); + } } } } From 837da9fd5917e863b5bea4269c7f86d056054228 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 15 May 2014 15:27:13 -0700 Subject: [PATCH 244/296] Add net.dns system properties Some apps rely on them. bug: 14992618 Change-Id: I5766f26b77004e9cfcc90fac657817eab67f9ac7 --- .../android/server/ConnectivityService.java | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0708e55d4a..982dce0a73 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5491,10 +5491,29 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (Exception e) { loge("Exception in setDnsServersForNetwork: " + e); } - // TODO - setprop "net.dnsX" + NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId); + if (defaultNai != null && defaultNai.network.netId == netId) { + setDefaultDnsSystemProperties(dnses); + } } } + private void setDefaultDnsSystemProperties(Collection dnses) { + int last = 0; + for (InetAddress dns : dnses) { + ++last; + String key = "net.dns" + last; + String value = dns.getHostAddress(); + SystemProperties.set(key, value); + } + for (int i = last + 1; i <= mNumDnsEntries; ++i) { + String key = "net.dns" + i; + SystemProperties.set(key, ""); + } + mNumDnsEntries = last; + } + + private void updateCapabilities(NetworkAgentInfo networkAgent, NetworkCapabilities networkCapabilities) { // TODO - what else here? Verify still satisfies everybody? @@ -5610,6 +5629,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mDefaultRequest.requestId == nri.request.requestId) { isNewDefault = true; updateActiveDefaultNetwork(newNetwork); + if (newNetwork.linkProperties != null) { + setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnses()); + } else { + setDefaultDnsSystemProperties(new ArrayList()); + } } } } From 09f5803344ed5aaba79bb5155da95cccaeab4988 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 16 May 2014 08:54:07 -0700 Subject: [PATCH 245/296] Clean up when we switch networks. Need to unhitch mNetworkForRequestId when a network is no longer satisfying a request. Change-Id: I3b3cde7dd92ec87a76ae7a0825ad22e892fa8fd5 --- core/java/android/net/NetworkAgent.java | 4 ++++ .../core/java/com/android/server/ConnectivityService.java | 1 + 2 files changed, 5 insertions(+) diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 4b853987c9..c2b06a297f 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -66,6 +66,7 @@ public abstract class NetworkAgent extends Handler { private AsyncChannel mAsyncChannel; private final String LOG_TAG; private static final boolean DBG = true; + private static final boolean VDBG = true; // TODO - this class shouldn't cache data or it runs the risk of getting out of sync // Make the API require each of these when any is updated so we have the data we need, // without caching. @@ -266,11 +267,14 @@ public abstract class NetworkAgent extends Handler { */ private void evalScores() { if (mConnectionRequested) { + if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size()); // already trying return; } + if (VDBG) log("evalScores!"); for (int i=0; i < mNetworkRequests.size(); i++) { int score = mNetworkRequests.valueAt(i).score; + if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore); if (score < mNetworkScore) { // have a request that has a lower scored network servicing it // (or no network) than we could provide, so lets connect! diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0708e55d4a..3f4f295aaf 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3216,6 +3216,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { // tell the network currently servicing this that it's no longer interested NetworkAgentInfo affectedNetwork = mNetworkForRequestId.get(nri.request.requestId); if (affectedNetwork != null) { + mNetworkForRequestId.remove(nri.request.requestId); affectedNetwork.networkRequests.remove(nri.request.requestId); if (VDBG) { log(" Removing from current network " + affectedNetwork.name() + ", leaving " + From c050e7b9358ea252374388564d2fa325bb908883 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Fri, 16 May 2014 12:10:32 -0700 Subject: [PATCH 246/296] Stop clatd when starting the Nat464Xlat service. If a runtime restart happens while clatd was running, we try to start clatd, which causes a fatal exception because netd returns a 400 error (clatd already started. Bug: 13450716 Bug: 15012035 Change-Id: I102a06d6193fb5f4a1ebe5ad52e5647ff72ca0da --- .../com/android/server/connectivity/Nat464Xlat.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index 3884ab057b..096ab66b42 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -74,6 +74,14 @@ public class Nat464Xlat extends BaseNetworkObserver { mIsStarted = false; mIsRunning = false; mLP = new LinkProperties(); + + // If this is a runtime restart, it's possible that clatd is already + // running, but we don't know about it. If so, stop it. + try { + if (mNMService.isClatdStarted()) { + mNMService.stopClatd(); + } + } catch(RemoteException e) {} // Well, we tried. } /** @@ -198,13 +206,13 @@ public class Nat464Xlat extends BaseNetworkObserver { NetworkUtils.resetConnections( CLAT_INTERFACE_NAME, NetworkUtils.RESET_IPV4_ADDRESSES); + mBaseLP.removeStackedLink(mLP); + updateConnectivityService(); } Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + " removed, mIsRunning = " + mIsRunning + " -> false"); mIsRunning = false; - mBaseLP.removeStackedLink(mLP); mLP.clear(); - updateConnectivityService(); Slog.i(TAG, "mLP = " + mLP); } } From 2a1bbad562ec81503ceee022cc6ec0a3636501d2 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 16 May 2014 17:19:24 -0700 Subject: [PATCH 247/296] Decouple network_sampling frequency from VDBG Add a special debug flag for testing network sampling. Change-Id: Ibe572c3b5648ca25f1e5be2c61e5c5ad2979b2cb --- .../core/java/com/android/server/ConnectivityService.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 2d0f6d19bd..5f53e4946d 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -193,6 +193,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final boolean DBG = true; private static final boolean VDBG = true; // STOPSHIP + // network sampling debugging + private static final boolean SAMPLE_DBG = false; + private static final boolean LOGD_RULES = false; // TODO: create better separation between radio types and network types @@ -219,10 +222,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Set network sampling interval at 12 minutes, this way, even if the timers get // aggregated, it will fire at around 15 minutes, which should allow us to // aggregate this timer with other timers (specially the socket keep alive timers) - private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 12 * 60); + private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 12 * 60); // start network sampling a minute after booting ... - private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (VDBG ? 30 : 60); + private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 60); AlarmManager mAlarmManager; From 7d8949fc2dcc108045661afac34eebe7a36fd4b2 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 18 May 2014 09:39:18 -0700 Subject: [PATCH 248/296] Update comments for LinkAddress In preparation for CS api review. Change-Id: Ib933e905846ebd039d96a523946dd8fdb10f3ff1 --- core/java/android/net/LinkAddress.java | 32 +++++++++++++++++--------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index a725becd74..d07c0b61a1 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -39,7 +39,8 @@ import static android.system.OsConstants.RT_SCOPE_UNIVERSE; *

        *
      • An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}). * The address must be unicast, as multicast addresses cannot be assigned to interfaces. - *
      • Address flags: A bitmask of {@code IFA_F_*} values representing properties of the address. + *
      • Address flags: A bitmask of {@code IFA_F_*} values representing properties + * of the address. *
      • Address scope: An integer defining the scope in which the address is unique (e.g., * {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}). *
          @@ -47,10 +48,9 @@ import static android.system.OsConstants.RT_SCOPE_UNIVERSE; * When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and * scope are optional. If they are not specified, the flags are set to zero, and the scope will be * determined based on the IP address (e.g., link-local addresses will be created with a scope of - * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, etc.) If they are - * specified, they are not checked for validity. + * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, + * etc.) If they are specified, they are not checked for validity. * - * @hide */ public class LinkAddress implements Parcelable { /** @@ -119,6 +119,10 @@ public class LinkAddress implements Parcelable { * the specified flags and scope. Flags and scope are not checked for validity. * @param address The IP address. * @param prefixLength The prefix length. + * @param flags A bitmask of {@code IFA_F_*} values representing properties of the address. + * @param scope An integer defining the scope in which the address is unique (e.g., + * {@link OsConstants#RT_SCOPE_LINK} or {@link OsConstants#RT_SCOPE_SITE}). + * @hide */ public LinkAddress(InetAddress address, int prefixLength, int flags, int scope) { init(address, prefixLength, flags, scope); @@ -129,6 +133,7 @@ public class LinkAddress implements Parcelable { * The flags are set to zero and the scope is determined from the address. * @param address The IP address. * @param prefixLength The prefix length. + * @hide */ public LinkAddress(InetAddress address, int prefixLength) { this(address, prefixLength, 0, 0); @@ -139,6 +144,7 @@ public class LinkAddress implements Parcelable { * Constructs a new {@code LinkAddress} from an {@code InterfaceAddress}. * The flags are set to zero and the scope is determined from the address. * @param interfaceAddress The interface address. + * @hide */ public LinkAddress(InterfaceAddress interfaceAddress) { this(interfaceAddress.getAddress(), @@ -149,6 +155,7 @@ public class LinkAddress implements Parcelable { * Constructs a new {@code LinkAddress} from a string such as "192.0.2.5/24" or * "2001:db8::1/64". The flags are set to zero and the scope is determined from the address. * @param string The string to parse. + * @hide */ public LinkAddress(String address) { this(address, 0, 0); @@ -161,6 +168,7 @@ public class LinkAddress implements Parcelable { * @param string The string to parse. * @param flags The address flags. * @param scope The address scope. + * @hide */ public LinkAddress(String address, int flags, int scope) { InetAddress inetAddress = null; @@ -220,9 +228,10 @@ public class LinkAddress implements Parcelable { } /** - * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} represent - * the same address. Two LinkAddresses represent the same address if they have the same IP - * address and prefix length, even if their properties are different. + * Determines whether this {@code LinkAddress} and the provided {@code LinkAddress} + * represent the same address. Two {@code LinkAddresses} represent the same address + * if they have the same IP address and prefix length, even if their properties are + * different. * * @param other the {@code LinkAddress} to compare to. * @return {@code true} if both objects have the same address and prefix length, {@code false} @@ -233,28 +242,28 @@ public class LinkAddress implements Parcelable { } /** - * Returns the InetAddress of this address. + * Returns the {@link InetAddress} of this {@code LinkAddress}. */ public InetAddress getAddress() { return address; } /** - * Returns the prefix length of this address. + * Returns the prefix length of this {@code LinkAddress}. */ public int getNetworkPrefixLength() { return prefixLength; } /** - * Returns the flags of this address. + * Returns the flags of this {@code LinkAddress}. */ public int getFlags() { return flags; } /** - * Returns the scope of this address. + * Returns the scope of this {@code LinkAddress}. */ public int getScope() { return scope; @@ -262,6 +271,7 @@ public class LinkAddress implements Parcelable { /** * Returns true if this {@code LinkAddress} is global scope and preferred. + * @hide */ public boolean isGlobalPreferred() { return (scope == RT_SCOPE_UNIVERSE && From 1aacd72db227791c4ed424b3d30cf8e7b71eae07 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 18 May 2014 12:05:05 -0700 Subject: [PATCH 249/296] Update RouteInfo docs and make public. Change-Id: I1a8fe04022ea8291076af166f09112d19114ee16 --- core/java/android/net/RouteInfo.java | 232 ++++++++++++++++++--------- 1 file changed, 154 insertions(+), 78 deletions(-) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index 1d051dde49..e566549b24 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -28,19 +28,18 @@ import java.util.Collection; /** * A simple container for route information. + *

          + * This is used both to describe static network configuration and live network + * configuration information. In the static case the interface name (retrieved + * via {@link #getInterface}) should be {@code null} as that information will not + * yet be known. * - * In order to be used, a route must have a destination prefix and: - * - * - A gateway address (next-hop, for gatewayed routes), or - * - An interface (for directly-connected routes), or - * - Both a gateway and an interface. - * - * This class does not enforce these constraints because there is code that - * uses RouteInfo objects to store directly-connected routes without interfaces. - * Such objects cannot be used directly, but can be put into a LinkProperties - * object which then specifies the interface. - * - * @hide + * A route may be configured with: + *

            + *
          • a destination {@link LinkAddress} for directly-connected subnets, + *
          • a gateway {@link InetAddress} for default routes, + *
          • or both for a subnet. + *
          */ public class RouteInfo implements Parcelable { /** @@ -67,7 +66,7 @@ public class RouteInfo implements Parcelable { * * If destination is null, then gateway must be specified and the * constructed route is either the IPv4 default route 0.0.0.0 - * if @gateway is an instance of {@link Inet4Address}, or the IPv6 default + * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default * route ::/0 if gateway is an instance of * {@link Inet6Address}. * @@ -76,6 +75,8 @@ public class RouteInfo implements Parcelable { * @param destination the destination prefix * @param gateway the IP address to route packets through * @param iface the interface name to send packets on + * + * @hide */ public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { if (destination == null) { @@ -108,22 +109,51 @@ public class RouteInfo implements Parcelable { mIsHost = isHost(); } + /** + * Constructs a {@code RouteInfo} object. + * + * If destination is null, then gateway must be specified and the + * constructed route is either the IPv4 default route 0.0.0.0 + * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default + * route ::/0 if gateway is an instance of {@link Inet6Address}. + *

          + * Destination and gateway may not both be null. + * + * @param destination the destination address and prefix in a {@link LinkAddress} + * @param gateway the {@link InetAddress} to route packets through + */ public RouteInfo(LinkAddress destination, InetAddress gateway) { this(destination, gateway, null); } + /** + * Constructs a default {@code RouteInfo} object. + * + * @param gateway the {@link InetAddress} to route packets through + */ public RouteInfo(InetAddress gateway) { this(null, gateway, null); } + /** + * Constructs a {@code RouteInfo} object representing a direct connected subnet. + * + * @param host the {@link LinkAddress} describing the address and prefix length of the subnet. + */ public RouteInfo(LinkAddress host) { this(host, null, null); } + /** + * @hide + */ public static RouteInfo makeHostRoute(InetAddress host, String iface) { return makeHostRoute(host, null, iface); } + /** + * @hide + */ public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway, String iface) { if (host == null) return null; @@ -153,31 +183,102 @@ public class RouteInfo implements Parcelable { return val; } - + /** + * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}. + * + * @return {@link LinkAddress} specifying the destination. + */ public LinkAddress getDestination() { return mDestination; } + /** + * Retrieves the gateway or next hop {@link InetAddress} for this route. + * + * @return {@link InetAddress} specifying the gateway or next hop. + */ public InetAddress getGateway() { return mGateway; } + /** + * Retrieves the interface used for this route, if known. Note that for static + * network configurations, this won't be set. + * + * @return The name of the interface used for this route. + */ public String getInterface() { return mInterface; } + /** + * Indicates if this route is a default route (ie, has no destination specified). + * + * @return {@code true} if the destination is null or has a prefix length of 0. + */ public boolean isDefaultRoute() { return mIsDefault; } + /** + * Indicates if this route is a host route (ie, matches only a single host address). + * + * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6. + */ public boolean isHostRoute() { return mIsHost; } + /** + * Indicates if this route has a next hop ({@code true}) or is directly-connected + * ({@code false}). + * + * @return {@code true} if a gateway is specified + */ public boolean hasGateway() { return mHasGateway; } + /** + * @hide + */ + protected boolean matches(InetAddress destination) { + if (destination == null) return false; + + // match the route destination and destination with prefix length + InetAddress dstNet = NetworkUtils.getNetworkPart(destination, + mDestination.getNetworkPrefixLength()); + + return mDestination.getAddress().equals(dstNet); + } + + /** + * Find the route from a Collection of routes that best matches a given address. + * May return null if no routes are applicable. + * @param routes a Collection of RouteInfos to chose from + * @param dest the InetAddress your trying to get to + * @return the RouteInfo from the Collection that best fits the given address + * + * @hide + */ + public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { + if ((routes == null) || (dest == null)) return null; + + RouteInfo bestRoute = null; + // pick a longest prefix match under same address type + for (RouteInfo route : routes) { + if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { + if ((bestRoute != null) && + (bestRoute.mDestination.getNetworkPrefixLength() >= + route.mDestination.getNetworkPrefixLength())) { + continue; + } + if (route.matches(dest)) bestRoute = route; + } + } + return bestRoute; + } + public String toString() { String val = ""; if (mDestination != null) val = mDestination.toString(); @@ -185,30 +286,6 @@ public class RouteInfo implements Parcelable { return val; } - public int describeContents() { - return 0; - } - - public void writeToParcel(Parcel dest, int flags) { - if (mDestination == null) { - dest.writeByte((byte) 0); - } else { - dest.writeByte((byte) 1); - dest.writeByteArray(mDestination.getAddress().getAddress()); - dest.writeInt(mDestination.getNetworkPrefixLength()); - } - - if (mGateway == null) { - dest.writeByte((byte) 0); - } else { - dest.writeByte((byte) 1); - dest.writeByteArray(mGateway.getAddress()); - } - - dest.writeString(mInterface); - } - - @Override public boolean equals(Object obj) { if (this == obj) return true; @@ -229,17 +306,51 @@ public class RouteInfo implements Parcelable { : mInterface.equals(target.getInterface()); return sameDestination && sameAddress && sameInterface - && mIsDefault == target.mIsDefault; + && mIsDefault == target.mIsDefault; } - @Override public int hashCode() { return (mDestination == null ? 0 : mDestination.hashCode() * 41) - + (mGateway == null ? 0 :mGateway.hashCode() * 47) - + (mInterface == null ? 0 :mInterface.hashCode() * 67) - + (mIsDefault ? 3 : 7); + + (mGateway == null ? 0 :mGateway.hashCode() * 47) + + (mInterface == null ? 0 :mInterface.hashCode() * 67) + + (mIsDefault ? 3 : 7); } + /** + * Implement the Parcelable interface + * @hide + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface + * @hide + */ + public void writeToParcel(Parcel dest, int flags) { + if (mDestination == null) { + dest.writeByte((byte) 0); + } else { + dest.writeByte((byte) 1); + dest.writeByteArray(mDestination.getAddress().getAddress()); + dest.writeInt(mDestination.getNetworkPrefixLength()); + } + + if (mGateway == null) { + dest.writeByte((byte) 0); + } else { + dest.writeByte((byte) 1); + dest.writeByteArray(mGateway.getAddress()); + } + + dest.writeString(mInterface); + } + + /** + * Implement the Parcelable interface. + * @hide + */ public static final Creator CREATOR = new Creator() { public RouteInfo createFromParcel(Parcel in) { @@ -279,39 +390,4 @@ public class RouteInfo implements Parcelable { return new RouteInfo[size]; } }; - - protected boolean matches(InetAddress destination) { - if (destination == null) return false; - - // match the route destination and destination with prefix length - InetAddress dstNet = NetworkUtils.getNetworkPart(destination, - mDestination.getNetworkPrefixLength()); - - return mDestination.getAddress().equals(dstNet); - } - - /** - * Find the route from a Collection of routes that best matches a given address. - * May return null if no routes are applicable. - * @param routes a Collection of RouteInfos to chose from - * @param dest the InetAddress your trying to get to - * @return the RouteInfo from the Collection that best fits the given address - */ - public static RouteInfo selectBestRoute(Collection routes, InetAddress dest) { - if ((routes == null) || (dest == null)) return null; - - RouteInfo bestRoute = null; - // pick a longest prefix match under same address type - for (RouteInfo route : routes) { - if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { - if ((bestRoute != null) && - (bestRoute.mDestination.getNetworkPrefixLength() >= - route.mDestination.getNetworkPrefixLength())) { - continue; - } - if (route.matches(dest)) bestRoute = route; - } - } - return bestRoute; - } } From 05d3bc2fd597893ebd33ae525c07c828797416ae Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 18 May 2014 15:24:21 -0700 Subject: [PATCH 250/296] Update the docs for NetworkCapabilities Preparing for ConnectivityService API update Change-Id: I397e375b9254d4271183cf34c4a689deea1e198e --- .../java/android/net/NetworkCapabilities.java | 220 ++++++++++++++++-- 1 file changed, 201 insertions(+), 19 deletions(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 8005e5ca7e..35274f1e7e 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -30,13 +30,31 @@ import java.util.Map.Entry; import java.util.Set; /** - * A class representing the capabilities of a network - * @hide + * This class represents the capabilities of a network. This is used both to specify + * needs to {@link ConnectivityManager} and when inspecting a network. + * + * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method + * of network selection. Rather than indicate a need for Wi-Fi because an application + * needs high bandwidth and risk obselence when a new, fast network appears (like LTE), + * the application should specify it needs high bandwidth. Similarly if an application + * needs an unmetered network for a bulk transfer it can specify that rather than assuming + * all cellular based connections are metered and all Wi-Fi based connections are not. */ public final class NetworkCapabilities implements Parcelable { private static final String TAG = "NetworkCapabilities"; private static final boolean DBG = false; + public NetworkCapabilities() { + } + + public NetworkCapabilities(NetworkCapabilities nc) { + if (nc != null) { + mNetworkCapabilities = nc.mNetworkCapabilities; + mTransportTypes = nc.mTransportTypes; + mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; + mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; + } + } /** * Represents the network's capabilities. If any are specified they will be satisfied @@ -45,28 +63,99 @@ public final class NetworkCapabilities implements Parcelable { private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED); /** - * Values for NetworkCapabilities. Roughly matches/extends deprecated - * ConnectivityManager TYPE_* + * Indicates this is a network that has the ability to reach the + * carrier's MMSC for sending and receiving MMS messages. */ public static final int NET_CAPABILITY_MMS = 0; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * SUPL server, used to retrieve GPS information. + */ public static final int NET_CAPABILITY_SUPL = 1; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * DUN or tethering gateway. + */ public static final int NET_CAPABILITY_DUN = 2; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * FOTA portal, used for over the air updates. + */ public static final int NET_CAPABILITY_FOTA = 3; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * IMS servers, used for network registration and signaling. + */ public static final int NET_CAPABILITY_IMS = 4; + + /** + * Indicates this is a network that has the ability to reach the carrier's + * CBS servers, used for carrier specific services. + */ public static final int NET_CAPABILITY_CBS = 5; + + /** + * Indicates this is a network that has the ability to reach a Wi-Fi direct + * peer. + */ public static final int NET_CAPABILITY_WIFI_P2P = 6; + + /** + * Indicates this is a network that has the ability to reach a carrier's + * Initial Attach servers. + */ public static final int NET_CAPABILITY_IA = 7; + + /** + * Indicates this is a network that has the ability to reach a carrier's + * RCS servers, used for Rich Communication Services. + */ public static final int NET_CAPABILITY_RCS = 8; + + /** + * Indicates this is a network that has the ability to reach a carrier's + * XCAP servers, used for configuration and control. + */ public static final int NET_CAPABILITY_XCAP = 9; + + /** + * Indicates this is a network that has the ability to reach a carrier's + * Emergency IMS servers, used for network signaling during emergency calls. + */ public static final int NET_CAPABILITY_EIMS = 10; + + /** + * Indicates that this network is unmetered. + */ public static final int NET_CAPABILITY_NOT_METERED = 11; + + /** + * Indicates that this network should be able to reach the internet. + */ public static final int NET_CAPABILITY_INTERNET = 12; - /** Set by default */ + + /** + * Indicates that this network is available for general use. If this is not set + * applications should not attempt to communicate on this network. Note that this + * is simply informative and not enforcement - enforcement is handled via other means. + * Set by default. + */ public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_RESTRICTED; + /** + * Adds the given capability to this {@code NetworkCapability} instance. + * Multiple capabilities may be applied sequentially. Note that when searching + * for a network to satisfy a request, all capabilities requested must be satisfied. + * + * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added. + */ public void addNetworkCapability(int networkCapability) { if (networkCapability < MIN_NET_CAPABILITY || networkCapability > MAX_NET_CAPABILITY) { @@ -74,6 +163,12 @@ public final class NetworkCapabilities implements Parcelable { } mNetworkCapabilities |= 1 << networkCapability; } + + /** + * Removes (if found) the given capability from this {@code NetworkCapability} instance. + * + * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed. + */ public void removeNetworkCapability(int networkCapability) { if (networkCapability < MIN_NET_CAPABILITY || networkCapability > MAX_NET_CAPABILITY) { @@ -81,9 +176,23 @@ public final class NetworkCapabilities implements Parcelable { } mNetworkCapabilities &= ~(1 << networkCapability); } + + /** + * Gets all the capabilities set on this {@code NetworkCapability} instance. + * + * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values + * for this instance. + */ public Collection getNetworkCapabilities() { return enumerateBits(mNetworkCapabilities); } + + /** + * Tests for the presence of a capabilitity on this instance. + * + * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for. + * @return {@code true} if set on this instance. + */ public boolean hasCapability(int networkCapability) { if (networkCapability < MIN_NET_CAPABILITY || networkCapability > MAX_NET_CAPABILITY) { @@ -124,31 +233,74 @@ public final class NetworkCapabilities implements Parcelable { private long mTransportTypes; /** - * Values for TransportType + * Indicates this network uses a Cellular transport. */ public static final int TRANSPORT_CELLULAR = 0; + + /** + * Indicates this network uses a Wi-Fi transport. + */ public static final int TRANSPORT_WIFI = 1; + + /** + * Indicates this network uses a Bluetooth transport. + */ public static final int TRANSPORT_BLUETOOTH = 2; + + /** + * Indicates this network uses an Ethernet transport. + */ public static final int TRANSPORT_ETHERNET = 3; private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR; private static final int MAX_TRANSPORT = TRANSPORT_ETHERNET; + /** + * Adds the given transport type to this {@code NetworkCapability} instance. + * Multiple transports may be applied sequentially. Note that when searching + * for a network to satisfy a request, any listed in the request will satisfy the request. + * For example {@code TRANSPORT_WIFI} and {@code TRANSPORT_ETHERNET} added to a + * {@code NetworkCapabilities} would cause either a Wi-Fi network or an Ethernet network + * to be selected. This is logically different than + * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above. + * + * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added. + */ public void addTransportType(int transportType) { if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { throw new IllegalArgumentException("TransportType out of range"); } mTransportTypes |= 1 << transportType; } + + /** + * Removes (if found) the given transport from this {@code NetworkCapability} instance. + * + * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed. + */ public void removeTransportType(int transportType) { if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { throw new IllegalArgumentException("TransportType out of range"); } mTransportTypes &= ~(1 << transportType); } + + /** + * Gets all the transports set on this {@code NetworkCapability} instance. + * + * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values + * for this instance. + */ public Collection getTransportTypes() { return enumerateBits(mTransportTypes); } + + /** + * Tests for the presence of a transport on this instance. + * + * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be tested for. + * @return {@code true} if set on this instance. + */ public boolean hasTransport(int transportType) { if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { return false; @@ -175,15 +327,58 @@ public final class NetworkCapabilities implements Parcelable { private int mLinkUpBandwidthKbps; private int mLinkDownBandwidthKbps; + /** + * Sets the upstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + *

          + * Note that when used to request a network, this specifies the minimum acceptable. + * When received as the state of an existing network this specifies the typical + * first hop bandwidth expected. This is never measured, but rather is inferred + * from technology type and other link parameters. It could be used to differentiate + * between very slow 1xRTT cellular links and other faster networks or even between + * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between + * fast backhauls and slow backhauls. + * + * @param upKbps the estimated first hop upstream (device to network) bandwidth. + */ public void setLinkUpstreamBandwidthKbps(int upKbps) { mLinkUpBandwidthKbps = upKbps; } + + /** + * Retrieves the upstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + * + * @return The estimated first hop upstream (device to network) bandwidth. + */ public int getLinkUpstreamBandwidthKbps() { return mLinkUpBandwidthKbps; } + + /** + * Sets the downstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + *

          + * Note that when used to request a network, this specifies the minimum acceptable. + * When received as the state of an existing network this specifies the typical + * first hop bandwidth expected. This is never measured, but rather is inferred + * from technology type and other link parameters. It could be used to differentiate + * between very slow 1xRTT cellular links and other faster networks or even between + * 802.11b vs 802.11AC wifi technologies. It should not be used to differentiate between + * fast backhauls and slow backhauls. + * + * @param downKbps the estimated first hop downstream (network to device) bandwidth. + */ public void setLinkDownstreamBandwidthKbps(int downKbps) { mLinkDownBandwidthKbps = downKbps; } + + /** + * Retrieves the downstream bandwidth for this network in Kbps. This always only refers to + * the estimated first hop transport bandwidth. + * + * @return The estimated first hop downstream (network to device) bandwidth. + */ public int getLinkDownstreamBandwidthKbps() { return mLinkDownBandwidthKbps; } @@ -243,19 +438,6 @@ public final class NetworkCapabilities implements Parcelable { (mLinkDownBandwidthKbps * 13)); } - public NetworkCapabilities() { - } - - public NetworkCapabilities(NetworkCapabilities nc) { - if (nc != null) { - mNetworkCapabilities = nc.mNetworkCapabilities; - mTransportTypes = nc.mTransportTypes; - mLinkUpBandwidthKbps = nc.mLinkUpBandwidthKbps; - mLinkDownBandwidthKbps = nc.mLinkDownBandwidthKbps; - } - } - - // Parcelable public int describeContents() { return 0; } From 223a6bd58df9fcbf5eb95b61624af39d406385dd Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 18 May 2014 23:33:07 -0700 Subject: [PATCH 251/296] Apply Doc fixes to RouteInfo Change-Id: Ib76df135d5514f7b8baafbbe91fa3d1cdd632f00 --- core/java/android/net/RouteInfo.java | 75 +++++++++++++++------------- 1 file changed, 40 insertions(+), 35 deletions(-) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index e566549b24..ad8e4f7eec 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -25,21 +25,26 @@ import java.net.Inet4Address; import java.net.Inet6Address; import java.util.Collection; +import java.util.Objects; /** - * A simple container for route information. + * Represents a network route. *

          * This is used both to describe static network configuration and live network - * configuration information. In the static case the interface name (retrieved - * via {@link #getInterface}) should be {@code null} as that information will not - * yet be known. + * configuration information. * - * A route may be configured with: + * A route contains three pieces of information: *

            - *
          • a destination {@link LinkAddress} for directly-connected subnets, - *
          • a gateway {@link InetAddress} for default routes, - *
          • or both for a subnet. + *
          • a destination {@link LinkAddress} for directly-connected subnets. If this is + * {@code null} it indicates a default route of the address family (IPv4 or IPv6) + * implied by the gateway IP address. + *
          • a gateway {@link InetAddress} for default routes. If this is {@code null} it + * indicates a directly-connected route. + *
          • an interface (which may be unspecified). *
          + * Either the destination or the gateway may be {@code null}, but not both. If the + * destination and gateway are both specified, they must be of the same address family + * (IPv4 or IPv6). */ public class RouteInfo implements Parcelable { /** @@ -69,14 +74,12 @@ public class RouteInfo implements Parcelable { * if the gateway is an instance of {@link Inet4Address}, or the IPv6 default * route ::/0 if gateway is an instance of * {@link Inet6Address}. - * + *

          * destination and gateway may not both be null. * * @param destination the destination prefix * @param gateway the IP address to route packets through * @param iface the interface name to send packets on - * - * @hide */ public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { if (destination == null) { @@ -103,6 +106,12 @@ public class RouteInfo implements Parcelable { mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); + if ((destination.getAddress() instanceof Inet4Address && + (gateway instanceof Inet4Address == false)) || + (destination.getAddress() instanceof Inet6Address && + (gateway instanceof Inet6Address == false))) { + throw new IllegalArgumentException("address family mismatch in RouteInfo constructor"); + } mGateway = gateway; mInterface = iface; mIsDefault = isDefault(); @@ -138,10 +147,11 @@ public class RouteInfo implements Parcelable { /** * Constructs a {@code RouteInfo} object representing a direct connected subnet. * - * @param host the {@link LinkAddress} describing the address and prefix length of the subnet. + * @param destination the {@link LinkAddress} describing the address and prefix + * length of the subnet. */ - public RouteInfo(LinkAddress host) { - this(host, null, null); + public RouteInfo(LinkAddress destination) { + this(destination, null, null); } /** @@ -186,7 +196,7 @@ public class RouteInfo implements Parcelable { /** * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}. * - * @return {@link LinkAddress} specifying the destination. + * @return {@link LinkAddress} specifying the destination. This is never {@code null}. */ public LinkAddress getDestination() { return mDestination; @@ -195,15 +205,15 @@ public class RouteInfo implements Parcelable { /** * Retrieves the gateway or next hop {@link InetAddress} for this route. * - * @return {@link InetAddress} specifying the gateway or next hop. + * @return {@link InetAddress} specifying the gateway or next hop. This may be + & {@code null} for a directly-connected route." */ public InetAddress getGateway() { return mGateway; } /** - * Retrieves the interface used for this route, if known. Note that for static - * network configurations, this won't be set. + * Retrieves the interface used for this route if specified, else {@code null}. * * @return The name of the interface used for this route. */ @@ -214,7 +224,7 @@ public class RouteInfo implements Parcelable { /** * Indicates if this route is a default route (ie, has no destination specified). * - * @return {@code true} if the destination is null or has a prefix length of 0. + * @return {@code true} if the destination has a prefix length of 0. */ public boolean isDefaultRoute() { return mIsDefault; @@ -224,6 +234,7 @@ public class RouteInfo implements Parcelable { * Indicates if this route is a host route (ie, matches only a single host address). * * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6. + * @hide */ public boolean isHostRoute() { return mIsHost; @@ -234,15 +245,20 @@ public class RouteInfo implements Parcelable { * ({@code false}). * * @return {@code true} if a gateway is specified + * @hide */ public boolean hasGateway() { return mHasGateway; } /** - * @hide + * Determines whether the destination and prefix of this route includes the specified + * address. + * + * @param destination A {@link InetAddress} to test to see if it would match this route. + * @return {@code true} if the destination and prefix length cover the given address. */ - protected boolean matches(InetAddress destination) { + public boolean matches(InetAddress destination) { if (destination == null) return false; // match the route destination and destination with prefix length @@ -293,20 +309,9 @@ public class RouteInfo implements Parcelable { RouteInfo target = (RouteInfo) obj; - boolean sameDestination = ( mDestination == null) ? - target.getDestination() == null - : mDestination.equals(target.getDestination()); - - boolean sameAddress = (mGateway == null) ? - target.getGateway() == null - : mGateway.equals(target.getGateway()); - - boolean sameInterface = (mInterface == null) ? - target.getInterface() == null - : mInterface.equals(target.getInterface()); - - return sameDestination && sameAddress && sameInterface - && mIsDefault == target.mIsDefault; + return Objects.equals(mDestination, target.getDestination()) && + Objects.equals(mGateway, target.getGateway()) && + Objects.equals(mInterface, target.getInterface()); } public int hashCode() { From 783dc0fef894b9dd541d13188631d77ffa6992e5 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 18 May 2014 20:29:39 -0700 Subject: [PATCH 252/296] Add docs to Network Still must be hidden until we unhide the new API in ConnectivityManager. Change-Id: I4749e56777199093cdba9223eb3d721c3174047d --- core/java/android/net/Network.java | 66 +++++++++++++++++++++++++++++- 1 file changed, 65 insertions(+), 1 deletion(-) diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index ac1289b93a..a99da789f3 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -20,20 +20,35 @@ import android.os.Parcelable; import android.os.Parcel; import java.net.InetAddress; +import java.net.Socket; import java.net.UnknownHostException; +import javax.net.SocketFactory; /** - * Identifies the Network. + * Identifies a {@code Network}. This is supplied to applications via + * {@link ConnectivityManager#NetworkCallbacks} in response to + * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}. + * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis + * through a targeted {@link SocketFactory} or process-wide via {@link #bindProcess}. * @hide */ public class Network implements Parcelable { + /** + * @hide + */ public final int netId; + /** + * @hide + */ public Network(int netId) { this.netId = netId; } + /** + * @hide + */ public Network(Network that) { this.netId = that.netId; } @@ -64,6 +79,45 @@ public class Network implements Parcelable { return InetAddress.getByNameOnNet(host, netId); } + /** + * Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by + * this factory will have its traffic sent over this {@code Network}. Note that if this + * {@code Network} ever disconnects, this factory and any {@link Socket} it produced in the + * past or future will cease to work. + * + * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this + * {@code Network}. + */ + public SocketFactory socketFactory() { + return null; + } + + /** + * Binds the current process to this network. All sockets created in the future (and not + * explicitly bound via a bound {@link SocketFactory} (see {@link Network#socketFactory}) + * will be bound to this network. Note that if this {@code Network} ever disconnects + * all sockets created in this way will cease to work. This is by design so an application + * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}. + */ + public void bindProcess() { + } + + /** + * A static utility method to return any {@code Network} currently bound by this process. + * + * @return {@code Network} to which this process is bound. + */ + public static Network getProcessBoundNetwork() { + return null; + } + + /** + * Clear any process specific {@code Network} binding. This reverts a call to + * {@link Network#bindProcess}. + */ + public static void unbindProcess() { + } + // implement the Parcelable interface public int describeContents() { return 0; @@ -84,4 +138,14 @@ public class Network implements Parcelable { return new Network[size]; } }; + + public boolean equals(Object obj) { + if (obj instanceof Network == false) return false; + Network other = (Network)obj; + return this.netId == other.netId; + } + + public int hashCode() { + return netId * 11; + } } From 0eb55c16c4bce94c9b714783e1168c8898392a7b Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 18 May 2014 16:22:10 -0700 Subject: [PATCH 253/296] Add javadoc for NetworkRequest. Also moved the requestId serial number out of this public class into CS. Had to leave NetworkRequest hidden for now because the docs refer to things still hidden in ConnectivityManager. Change-Id: I14d1fe52d992adf5e4dc197b8f5433e40b0adfe6 --- core/java/android/net/NetworkRequest.java | 33 ++++++++----------- .../android/server/ConnectivityService.java | 14 ++++++-- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index b3ae3f51e8..80074a5e7a 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -22,11 +22,19 @@ import android.os.Parcelable; import java.util.concurrent.atomic.AtomicInteger; /** + * Defines a request for a network, made by calling {@link ConnectivityManager.requestNetwork}. + * + * This token records the {@link NetworkCapabilities} used to make the request and identifies + * the request. It should be used to release the request via + * {@link ConnectivityManager.releaseNetworkRequest} when the network is no longer desired. * @hide */ public class NetworkRequest implements Parcelable { /** - * The NetworkCapabilities that define this request + * The {@link NetworkCapabilities} that define this request. This should not be modified. + * The networkCapabilities of the request are set when + * {@link ConnectivityManager.requestNetwork} is called and the value is presented here + * as a convenient reminder of what was requested. */ public final NetworkCapabilities networkCapabilities; @@ -34,7 +42,7 @@ public class NetworkRequest implements Parcelable { * Identifies the request. NetworkRequests should only be constructed by * the Framework and given out to applications as tokens to be used to identify * the request. - * TODO - make sure this input is checked whenever a NR is passed in a public API + * @hide */ public final int requestId; @@ -45,31 +53,18 @@ public class NetworkRequest implements Parcelable { */ public final boolean needsBroadcasts; - private static final AtomicInteger sNextRequestId = new AtomicInteger(1); - /** * @hide */ - public NetworkRequest(NetworkCapabilities nc) { - this(nc, false, sNextRequestId.getAndIncrement()); - } - - /** - * @hide - */ - public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts) { - this(nc, needsBroadcasts, sNextRequestId.getAndIncrement()); - } - - /** - * @hide - */ - private NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) { + public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) { requestId = rId; networkCapabilities = nc; this.needsBroadcasts = needsBroadcasts; } + /** + * @hide + */ public NetworkRequest(NetworkRequest that) { networkCapabilities = new NetworkCapabilities(that.networkCapabilities); requestId = that.requestId; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5f53e4946d..01af753b90 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -507,10 +507,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { TelephonyManager mTelephonyManager; + // sequence number for Networks private final static int MIN_NET_ID = 10; // some reserved marks private final static int MAX_NET_ID = 65535; private int mNextNetId = MIN_NET_ID; + // sequence number of NetworkRequests + private int mNextNetworkRequestId = 1; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -526,7 +530,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - mDefaultRequest = new NetworkRequest(netCap, true); + mDefaultRequest = new NetworkRequest(netCap, true, nextNetworkRequestId()); NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(), NetworkRequestInfo.REQUEST); mNetworkRequests.put(mDefaultRequest, nri); @@ -773,6 +777,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); } + private synchronized int nextNetworkRequestId() { + return mNextNetworkRequestId++; + } + private synchronized int nextNetId() { int netId = mNextNetId; if (++mNextNetId > MAX_NET_ID) mNextNetId = MIN_NET_ID; @@ -5271,7 +5279,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities)); + networkCapabilities), false, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); @@ -5297,7 +5305,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { enforceAccessPermission(); NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities)); + networkCapabilities), false, nextNetworkRequestId()); if (DBG) log("listenForNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.LISTEN); From eaa84d5dda4537f8dde87be273e92b374d6b15f1 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 18 May 2014 22:01:38 -0700 Subject: [PATCH 254/296] Add docs for Linkproperties and unhide it. Preperation for ConnectivityManager API reveal. Change-Id: Id2addf424213e796c6077def0b7f30cac9a0f75f --- core/java/android/net/LinkProperties.java | 167 +++++++++++++++++----- 1 file changed, 130 insertions(+), 37 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 489b8a51f1..3c366799f6 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -36,27 +36,12 @@ import java.util.Hashtable; * * A link represents a connection to a network. * It may have multiple addresses and multiple gateways, - * multiple dns servers but only one http proxy. + * multiple dns servers but only one http proxy and one + * network interface. * - * Because it's a single network, the dns's - * are interchangeable and don't need associating with - * particular addresses. The gateways similarly don't - * need associating with particular addresses. + * Note that this is just a holder of data. Modifying it + * does not affect live networks. * - * A dual stack interface works fine in this model: - * each address has it's own prefix length to describe - * the local network. The dns servers all return - * both v4 addresses and v6 addresses regardless of the - * address family of the server itself (rfc4213) and we - * don't care which is used. The gateways will be - * selected based on the destination address and the - * source address has no relavence. - * - * Links can also be stacked on top of each other. - * This can be used, for example, to represent a tunnel - * interface that runs on top of a physical interface. - * - * @hide */ public class LinkProperties implements Parcelable { // The interface described by the network link. @@ -73,6 +58,7 @@ public class LinkProperties implements Parcelable { private Hashtable mStackedLinks = new Hashtable(); + // @hide public static class CompareResult { public Collection removed = new ArrayList(); public Collection added = new ArrayList(); @@ -91,7 +77,6 @@ public class LinkProperties implements Parcelable { public LinkProperties() { } - // copy constructor instead of clone public LinkProperties(LinkProperties source) { if (source != null) { mIfaceName = source.getInterfaceName(); @@ -108,6 +93,12 @@ public class LinkProperties implements Parcelable { } } + /** + * Sets the interface name for this link. All {@link RouteInfo} already set for this + * will have their interface changed to match this new value. + * + * @param iface The name of the network interface used for this link. + */ public void setInterfaceName(String iface) { mIfaceName = iface; ArrayList newRoutes = new ArrayList(mRoutes.size()); @@ -117,10 +108,16 @@ public class LinkProperties implements Parcelable { mRoutes = newRoutes; } + /** + * Gets the interface name for this link. May be {@code null} if not set. + * + * @return The interface name set for this link or {@code null}. + */ public String getInterfaceName() { return mIfaceName; } + // @hide public Collection getAllInterfaceNames() { Collection interfaceNames = new ArrayList(mStackedLinks.size() + 1); if (mIfaceName != null) interfaceNames.add(new String(mIfaceName)); @@ -131,7 +128,14 @@ public class LinkProperties implements Parcelable { } /** - * Returns all the addresses on this link. + * Returns all the addresses on this link. We often think of a link having a single address, + * however, particularly with Ipv6 several addresses are typical. Note that the + * {@code LinkProperties} actually contains {@link LinkAddress} objects which also include + * prefix lengths for each address. This is a simplified utility alternative to + * {@link LinkProperties#getLinkAddresses}. + * + * @return An umodifiable {@link Collection} of {@link InetAddress} for this link. + * @hide */ public Collection getAddresses() { Collection addresses = new ArrayList(); @@ -143,6 +147,7 @@ public class LinkProperties implements Parcelable { /** * Returns all the addresses on this link and all the links stacked above it. + * @hide */ public Collection getAllAddresses() { Collection addresses = new ArrayList(); @@ -165,7 +170,8 @@ public class LinkProperties implements Parcelable { } /** - * Adds a link address if it does not exist, or updates it if it does. + * Adds a {@link LinkAddress} to this {@code LinkProperties} if a {@link LinkAddress} of the + * same address/prefix does not already exist. If it does exist it is replaced. * @param address The {@code LinkAddress} to add. * @return true if {@code address} was added or updated, false otherwise. */ @@ -189,9 +195,10 @@ public class LinkProperties implements Parcelable { } /** - * Removes a link address. Specifically, removes the link address, if any, for which - * {@code isSameAddressAs(toRemove)} returns true. - * @param address A {@code LinkAddress} specifying the address to remove. + * Removes a {@link LinkAddress} from this {@code LinkProperties}. Specifically, matches + * and {@link LinkAddress} with the same address and prefix. + * + * @param toRemove A {@link LinkAddress} specifying the address to remove. * @return true if the address was removed, false if it did not exist. */ public boolean removeLinkAddress(LinkAddress toRemove) { @@ -204,7 +211,10 @@ public class LinkProperties implements Parcelable { } /** - * Returns all the addresses on this link. + * Returns all the {@link LinkAddress} on this link. Typically a link will have + * one IPv4 address and one or more IPv6 addresses. + * + * @return An unmodifiable {@link Collection} of {@link LinkAddress} for this link. */ public Collection getLinkAddresses() { return Collections.unmodifiableCollection(mLinkAddresses); @@ -212,6 +222,7 @@ public class LinkProperties implements Parcelable { /** * Returns all the addresses on this link and all the links stacked above it. + * @hide */ public Collection getAllLinkAddresses() { Collection addresses = new ArrayList(); @@ -223,7 +234,11 @@ public class LinkProperties implements Parcelable { } /** - * Replaces the LinkAddresses on this link with the given collection of addresses. + * Replaces the {@link LinkAddress} in this {@code LinkProperties} with + * the given {@link Collection} of {@link LinkAddress}. + * + * @param addresses The {@link Collection} of {@link LinkAddress} to set in this + * object. */ public void setLinkAddresses(Collection addresses) { mLinkAddresses.clear(); @@ -232,26 +247,64 @@ public class LinkProperties implements Parcelable { } } + /** + * Adds the given {@link InetAddress} to the list of DNS servers. + * + * @param dns The {@link InetAddress} to add to the list of DNS servers. + */ public void addDns(InetAddress dns) { if (dns != null) mDnses.add(dns); } + /** + * Returns all the {@link LinkAddress} for DNS servers on this link. + * + * @return An umodifiable {@link Collection} of {@link InetAddress} for DNS servers on + * this link. + */ public Collection getDnses() { return Collections.unmodifiableCollection(mDnses); } - public String getDomains() { - return mDomains; - } - + /** + * Sets the DNS domain search path used on this link. + * + * @param domains A {@link String} listing in priority order the comma separated + * domains to search when resolving host names on this link. + */ public void setDomains(String domains) { mDomains = domains; } + /** + * Get the DNS domains search path set for this link. + * + * @return A {@link String} containing the comma separated domains to search when resolving + * host names on this link. + */ + public String getDomains() { + return mDomains; + } + + /** + * Sets the Maximum Transmission Unit size to use on this link. This should not be used + * unless the system default (1500) is incorrect. Values less than 68 or greater than + * 10000 will be ignored. + * + * @param mtu The MTU to use for this link. + * @hide + */ public void setMtu(int mtu) { mMtu = mtu; } + /** + * Gets any non-default MTU size set for this link. Note that if the default is being used + * this will return 0. + * + * @return The mtu value set for this link. + * @hide + */ public int getMtu() { return mMtu; } @@ -263,6 +316,14 @@ public class LinkProperties implements Parcelable { mIfaceName); } + /** + * Adds a {@link RouteInfo} to this {@code LinkProperties}. If the {@link RouteInfo} + * had an interface name set and that differs from the interface set for this + * {@code LinkProperties} an {@link IllegalArgumentException} will be thrown. The + * proper course is to add either un-named or properly named {@link RouteInfo}. + * + * @param route A {@link RouteInfo} to add to this object. + */ public void addRoute(RouteInfo route) { if (route != null) { String routeIface = route.getInterface(); @@ -276,7 +337,9 @@ public class LinkProperties implements Parcelable { } /** - * Returns all the routes on this link. + * Returns all the {@link RouteInfo} set on this link. + * + * @return An unmodifiable {@link Collection} of {@link RouteInfo} for this link. */ public Collection getRoutes() { return Collections.unmodifiableCollection(mRoutes); @@ -284,6 +347,7 @@ public class LinkProperties implements Parcelable { /** * Returns all the routes on this link and all the links stacked above it. + * @hide */ public Collection getAllRoutes() { Collection routes = new ArrayList(); @@ -294,9 +358,22 @@ public class LinkProperties implements Parcelable { return routes; } + /** + * Sets the recommended {@link ProxyInfo} to use on this link, or {@code null} for none. + * Note that Http Proxies are only a hint - the system recommends their use, but it does + * not enforce it and applications may ignore them. + * + * @param proxy A {@link ProxyInfo} defining the Http Proxy to use on this link. + */ public void setHttpProxy(ProxyInfo proxy) { mHttpProxy = proxy; } + + /** + * Gets the recommended {@link ProxyInfo} (or {@code null}) set on this link. + * + * @return The {@link ProxyInfo} set on this link + */ public ProxyInfo getHttpProxy() { return mHttpProxy; } @@ -310,6 +387,7 @@ public class LinkProperties implements Parcelable { * * @param link The link to add. * @return true if the link was stacked, false otherwise. + * @hide */ public boolean addStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { @@ -327,6 +405,7 @@ public class LinkProperties implements Parcelable { * * @param link The link to remove. * @return true if the link was removed, false otherwise. + * @hide */ public boolean removeStackedLink(LinkProperties link) { if (link != null && link.getInterfaceName() != null) { @@ -338,6 +417,7 @@ public class LinkProperties implements Parcelable { /** * Returns all the links stacked on top of this link. + * @hide */ public Collection getStackedLinks() { Collection stacked = new ArrayList(); @@ -347,6 +427,9 @@ public class LinkProperties implements Parcelable { return Collections.unmodifiableCollection(stacked); } + /** + * Clears this object to its initial state. + */ public void clear() { mIfaceName = null; mLinkAddresses.clear(); @@ -432,6 +515,7 @@ public class LinkProperties implements Parcelable { * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. + * @hide */ public boolean isIdenticalInterfaceName(LinkProperties target) { return TextUtils.equals(getInterfaceName(), target.getInterfaceName()); @@ -442,6 +526,7 @@ public class LinkProperties implements Parcelable { * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. + * @hide */ public boolean isIdenticalAddresses(LinkProperties target) { Collection targetAddresses = target.getAddresses(); @@ -455,6 +540,7 @@ public class LinkProperties implements Parcelable { * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. + * @hide */ public boolean isIdenticalDnses(LinkProperties target) { Collection targetDnses = target.getDnses(); @@ -473,6 +559,7 @@ public class LinkProperties implements Parcelable { * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. + * @hide */ public boolean isIdenticalRoutes(LinkProperties target) { Collection targetRoutes = target.getRoutes(); @@ -485,6 +572,7 @@ public class LinkProperties implements Parcelable { * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. + * @hide */ public boolean isIdenticalHttpProxy(LinkProperties target) { return getHttpProxy() == null ? target.getHttpProxy() == null : @@ -496,6 +584,7 @@ public class LinkProperties implements Parcelable { * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. + * @hide */ public boolean isIdenticalStackedLinks(LinkProperties target) { if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { @@ -516,6 +605,7 @@ public class LinkProperties implements Parcelable { * * @param target LinkProperties to compare. * @return {@code true} if both are identical, {@code false} otherwise. + * @hide */ public boolean isIdenticalMtu(LinkProperties target) { return getMtu() == target.getMtu(); @@ -533,10 +623,6 @@ public class LinkProperties implements Parcelable { * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. * 2. Worst case performance is O(n^2). * - * This method does not check that stacked interfaces are equal, because - * stacked interfaces are not so much a property of the link as a - * description of connections between links. - * * @param obj the object to be tested for equality. * @return {@code true} if both objects are equal, {@code false} otherwise. */ @@ -546,7 +632,11 @@ public class LinkProperties implements Parcelable { if (!(obj instanceof LinkProperties)) return false; LinkProperties target = (LinkProperties) obj; - + /** + * This method does not check that stacked interfaces are equal, because + * stacked interfaces are not so much a property of the link as a + * description of connections between links. + */ return isIdenticalInterfaceName(target) && isIdenticalAddresses(target) && isIdenticalDnses(target) && @@ -562,6 +652,7 @@ public class LinkProperties implements Parcelable { * * @param target a LinkProperties with the new list of addresses * @return the differences between the addresses. + * @hide */ public CompareResult compareAddresses(LinkProperties target) { /* @@ -590,6 +681,7 @@ public class LinkProperties implements Parcelable { * * @param target a LinkProperties with the new list of dns addresses * @return the differences between the DNS addresses. + * @hide */ public CompareResult compareDnses(LinkProperties target) { /* @@ -619,6 +711,7 @@ public class LinkProperties implements Parcelable { * * @param target a LinkProperties with the new list of routes * @return the differences between the routes. + * @hide */ public CompareResult compareAllRoutes(LinkProperties target) { /* From f3017f74a0c06323ef34631a6697fbdcd94a425c Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 18 May 2014 23:07:25 -0700 Subject: [PATCH 255/296] Add javadoc and unhide new API Change-Id: I12e475bbf4000c7acec4ca27b1d3bf8f870cc2cf --- .../java/android/net/ConnectivityManager.java | 257 +++++++++++------- core/java/android/net/Network.java | 3 +- core/java/android/net/NetworkRequest.java | 8 +- 3 files changed, 164 insertions(+), 104 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index a414421aee..1837335615 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -21,6 +21,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.PendingIntent; import android.content.Context; +import android.content.Intent; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Handler; @@ -57,13 +58,15 @@ import com.android.internal.util.Protocol; * is lost *

        • Provide an API that allows applications to query the coarse-grained or fine-grained * state of the available networks
        • + *
        • Provide an API that allows applications to request and select networks for their data + * traffic
        • * */ public class ConnectivityManager { private static final String TAG = "ConnectivityManager"; /** - * A change in network connectivity has occurred. A connection has either + * A change in network connectivity has occurred. A default connection has either * been established or lost. The NetworkInfo for the affected network is * sent as an extra; it should be consulted to see what kind of * connectivity event occurred. @@ -547,13 +550,12 @@ public class ConnectivityManager { * @param preference the network type to prefer over all others. It is * unspecified what happens to the old preferred network in the * overall ordering. + * @deprecated Functionality has been removed as it no longer makes sense, + * with many more than two networks - we'd need an array to express + * preference. Instead we use dynamic network properties of + * the networks to describe their precedence. */ public void setNetworkPreference(int preference) { - // TODO - deprecate with: - // @deprecated Functionality has been removed as it no longer makes sense, - // with many more than two networks - we'd need an array to express - // preference. Instead we use dynamic network properties of - // the networks to describe their precedence. } /** @@ -563,14 +565,13 @@ public class ConnectivityManager { * *

          This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * @deprecated Functionality has been removed as it no longer makes sense, + * with many more than two networks - we'd need an array to express + * preference. Instead we use dynamic network properties of + * the networks to describe their precedence. */ public int getNetworkPreference() { - // TODO - deprecate with: - // @deprecated Functionality has been removed as it no longer makes sense, - // with many more than two networks - we'd need an array to express - // preference. Instead we use dynamic network properties of - // the networks to describe their precedence. - return -1; + return TYPE_NONE; } /** @@ -716,7 +717,13 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * Get the {@link LinkProperties} for the given {@link Network}. This + * will return {@code null} if the network is unknown. + * + * @param network The {@link Network} object identifying the network in question. + * @return The {@link LinkProperties} for the network, or {@code null}. + **/ public LinkProperties getLinkProperties(Network network) { try { return mService.getLinkProperties(network); @@ -725,7 +732,13 @@ public class ConnectivityManager { } } - /** {@hide} */ + /** + * Get the {@link NetworkCapabilities} for the given {@link Network}. This + * will return {@code null} if the network is unknown. + * + * @param network The {@link Network} object identifying the network in question. + * @return The {@link NetworkCapabilities} for the network, or {@code null}. + */ public NetworkCapabilities getNetworkCapabilities(Network network) { try { return mService.getNetworkCapabilities(network); @@ -788,6 +801,8 @@ public class ConnectivityManager { * The interpretation of this value is specific to each networking * implementation+feature combination, except that the value {@code -1} * always indicates failure. + * + * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api. */ public int startUsingNetworkFeature(int networkType, String feature) { try { @@ -810,6 +825,8 @@ public class ConnectivityManager { * The interpretation of this value is specific to each networking * implementation+feature combination, except that the value {@code -1} * always indicates failure. + * + * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api. */ public int stopUsingNetworkFeature(int networkType, String feature) { try { @@ -829,6 +846,9 @@ public class ConnectivityManager { * host is to be routed * @param hostAddress the IP address of the host to which the route is desired * @return {@code true} on success, {@code false} on failure + * + * @deprecated Deprecated in favor of the {@link #requestNetwork}, + * {@link Network#bindProcess} and {@link Network#socketFactory} api. */ public boolean requestRouteToHost(int networkType, int hostAddress) { InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); @@ -851,6 +871,8 @@ public class ConnectivityManager { * @param hostAddress the IP address of the host to which the route is desired * @return {@code true} on success, {@code false} on failure * @hide + * @deprecated Deprecated in favor of the {@link #requestNetwork} and + * {@link Network#bindProcess} api. */ public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { byte[] address = hostAddress.getAddress(); @@ -1332,13 +1354,13 @@ public class ConnectivityManager { } /** - * Report a problem network to the framework. This will cause the framework - * to evaluate the situation and try to fix any problems. Note that false - * may be subsequently ignored. + * Report a problem network to the framework. This provides a hint to the system + * that there might be connectivity problems on this network and may cause + * the framework to re-evaluate network connectivity and/or switch to another + * network. * - * @param network The Network the application was attempting to use or null - * to indicate the current default network. - * {@hide} + * @param network The {@link Network} the application was attempting to use + * or {@code null} to indicate the current default network. */ public void reportBadNetwork(Network network) { try { @@ -1358,6 +1380,7 @@ public class ConnectivityManager { * *

          This method requires the call to hold the permission * android.Manifest.permission#CONNECTIVITY_INTERNAL. + * @hide */ public void setGlobalProxy(ProxyInfo p) { try { @@ -1374,6 +1397,7 @@ public class ConnectivityManager { * *

          This method requires the call to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. + * @hide */ public ProxyInfo getGlobalProxy() { try { @@ -1393,6 +1417,7 @@ public class ConnectivityManager { *

          This method requires the call to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} + * @deprecated Deprecated in favor of {@link #getLinkProperties} */ public ProxyInfo getProxy() { try { @@ -1645,11 +1670,10 @@ public class ConnectivityManager { } /** - * Interface for NetworkRequest callbacks. Used for notifications about network - * changes. - * @hide + * Base class for NetworkRequest callbacks. Used for notifications about network + * changes. Should be extended by applications wanting notifications. */ - public static class NetworkCallbacks { + public static class NetworkCallbackListener { /** @hide */ public static final int PRECHECK = 1; /** @hide */ @@ -1675,51 +1699,73 @@ public class ConnectivityManager { public void onPreCheck(NetworkRequest networkRequest, Network network) {} /** - * Called when the framework connects and has validated the new network. + * Called when the framework connects and has declared new network ready for use. + * + * @param networkRequest The {@link NetworkRequest} used to initiate the request. + * @param network The {@link Network} of the satisfying network. */ public void onAvailable(NetworkRequest networkRequest, Network network) {} /** - * Called when the framework is losing the network. Often paired with an - * onAvailable call with the new replacement network for graceful handover. - * This may not be called if we have a hard loss (loss without warning). - * This may be followed by either an onLost call or an onAvailable call for this - * network depending on if we lose or regain it. + * Called when the network is about to be disconnected. Often paired with an + * {@link NetworkCallbackListener#onAvailable} call with the new replacement network + * for graceful handover. This may not be called if we have a hard loss + * (loss without warning). This may be followed by either a + * {@link NetworkCallbackListener#onLost} call or a + * {@link NetworkCallbackListener#onAvailable} call for this network depending + * on whether we lose or regain it. + * + * @param networkRequest The {@link NetworkRequest} used to initiate the request. + * @param network The {@link Network} of the failing network. + * @param maxSecToLive The time in seconds the framework will attempt to keep the + * network connected. Note that the network may suffers a + * hard loss at any time. */ public void onLosing(NetworkRequest networkRequest, Network network, int maxSecToLive) {} /** * Called when the framework has a hard loss of the network or when the - * graceful failure ends. Note applications should only request this callback - * if the application is willing to track the Available and Lost callbacks - * together, else the application may think it has no network when it - * really does (A Avail, B Avail, A Lost.. still have B). + * graceful failure ends. + * + * @param networkRequest The {@link NetworkRequest} used to initiate the request. + * @param network The {@link Network} lost. */ public void onLost(NetworkRequest networkRequest, Network network) {} /** * Called if no network is found in the given timeout time. If no timeout is given, * this will not be called. + * @hide */ public void onUnavailable(NetworkRequest networkRequest) {} /** * Called when the network the framework connected to for this request * changes capabilities but still satisfies the stated need. + * + * @param networkRequest The {@link NetworkRequest} used to initiate the request. + * @param network The {@link Network} whose capabilities have changed. + * @param networkCapabilities The new {@link NetworkCapabilities} for this network. */ public void onNetworkCapabilitiesChanged(NetworkRequest networkRequest, Network network, NetworkCapabilities networkCapabilities) {} /** * Called when the network the framework connected to for this request - * changes LinkProperties. + * changes {@link LinkProperties}. + * + * @param networkRequest The {@link NetworkRequest} used to initiate the request. + * @param network The {@link Network} whose link properties have changed. + * @param linkProperties The new {@link LinkProperties} for this network. */ public void onLinkPropertiesChanged(NetworkRequest networkRequest, Network network, LinkProperties linkProperties) {} /** - * Called when a releaseNetworkRequest call concludes and the registered callbacks will - * no longer be used. + * Called when a {@link #releaseNetworkRequest} call concludes and the registered + * callbacks will no longer be used. + * + * @param networkRequest The {@link NetworkRequest} used to initiate the request. */ public void onReleased(NetworkRequest networkRequest) {} } @@ -1745,12 +1791,12 @@ public class ConnectivityManager { public static final int CALLBACK_EXIT = BASE + 9; private static class CallbackHandler extends Handler { - private final HashMapmCallbackMap; + private final HashMapmCallbackMap; private final AtomicInteger mRefCount; private static final String TAG = "ConnectivityManager.CallbackHandler"; private final ConnectivityManager mCm; - CallbackHandler(Looper looper, HashMapcallbackMap, + CallbackHandler(Looper looper, HashMapcallbackMap, AtomicInteger refCount, ConnectivityManager cm) { super(looper); mCallbackMap = callbackMap; @@ -1764,7 +1810,7 @@ public class ConnectivityManager { switch (message.what) { case CALLBACK_PRECHECK: { NetworkRequest request = getNetworkRequest(message); - NetworkCallbacks callbacks = getCallbacks(request); + NetworkCallbackListener callbacks = getCallbacks(request); if (callbacks != null) { callbacks.onPreCheck(request, getNetwork(message)); } else { @@ -1774,7 +1820,7 @@ public class ConnectivityManager { } case CALLBACK_AVAILABLE: { NetworkRequest request = getNetworkRequest(message); - NetworkCallbacks callbacks = getCallbacks(request); + NetworkCallbackListener callbacks = getCallbacks(request); if (callbacks != null) { callbacks.onAvailable(request, getNetwork(message)); } else { @@ -1784,7 +1830,7 @@ public class ConnectivityManager { } case CALLBACK_LOSING: { NetworkRequest request = getNetworkRequest(message); - NetworkCallbacks callbacks = getCallbacks(request); + NetworkCallbackListener callbacks = getCallbacks(request); if (callbacks != null) { callbacks.onLosing(request, getNetwork(message), message.arg1); } else { @@ -1794,7 +1840,7 @@ public class ConnectivityManager { } case CALLBACK_LOST: { NetworkRequest request = getNetworkRequest(message); - NetworkCallbacks callbacks = getCallbacks(request); + NetworkCallbackListener callbacks = getCallbacks(request); if (callbacks != null) { callbacks.onLost(request, getNetwork(message)); } else { @@ -1804,7 +1850,7 @@ public class ConnectivityManager { } case CALLBACK_UNAVAIL: { NetworkRequest req = (NetworkRequest)message.obj; - NetworkCallbacks callbacks = null; + NetworkCallbackListener callbacks = null; synchronized(mCallbackMap) { callbacks = mCallbackMap.get(req); } @@ -1817,7 +1863,7 @@ public class ConnectivityManager { } case CALLBACK_CAP_CHANGED: { NetworkRequest request = getNetworkRequest(message); - NetworkCallbacks callbacks = getCallbacks(request); + NetworkCallbackListener callbacks = getCallbacks(request); if (callbacks != null) { Network network = getNetwork(message); NetworkCapabilities cap = mCm.getNetworkCapabilities(network); @@ -1830,7 +1876,7 @@ public class ConnectivityManager { } case CALLBACK_IP_CHANGED: { NetworkRequest request = getNetworkRequest(message); - NetworkCallbacks callbacks = getCallbacks(request); + NetworkCallbackListener callbacks = getCallbacks(request); if (callbacks != null) { Network network = getNetwork(message); LinkProperties lp = mCm.getLinkProperties(network); @@ -1843,7 +1889,7 @@ public class ConnectivityManager { } case CALLBACK_RELEASED: { NetworkRequest req = (NetworkRequest)message.obj; - NetworkCallbacks callbacks = null; + NetworkCallbackListener callbacks = null; synchronized(mCallbackMap) { callbacks = mCallbackMap.remove(req); } @@ -1870,7 +1916,7 @@ public class ConnectivityManager { private NetworkRequest getNetworkRequest(Message msg) { return (NetworkRequest)(msg.obj); } - private NetworkCallbacks getCallbacks(NetworkRequest req) { + private NetworkCallbackListener getCallbacks(NetworkRequest req) { synchronized(mCallbackMap) { return mCallbackMap.get(req); } @@ -1878,7 +1924,7 @@ public class ConnectivityManager { private Network getNetwork(Message msg) { return new Network(msg.arg2); } - private NetworkCallbacks removeCallbacks(Message msg) { + private NetworkCallbackListener removeCallbacks(Message msg) { NetworkRequest req = (NetworkRequest)msg.obj; synchronized(mCallbackMap) { return mCallbackMap.remove(req); @@ -1893,7 +1939,7 @@ public class ConnectivityManager { HandlerThread callbackThread = new HandlerThread("ConnectivityManager"); callbackThread.start(); sCallbackHandler = new CallbackHandler(callbackThread.getLooper(), - sNetworkCallbacks, sCallbackRefCount, this); + sNetworkCallbackListener, sCallbackRefCount, this); } } } @@ -1907,8 +1953,8 @@ public class ConnectivityManager { } } - static final HashMap sNetworkCallbacks = - new HashMap(); + static final HashMap sNetworkCallbackListener = + new HashMap(); static final AtomicInteger sCallbackRefCount = new AtomicInteger(0); static CallbackHandler sCallbackHandler = null; @@ -1916,9 +1962,11 @@ public class ConnectivityManager { private final static int REQUEST = 2; private NetworkRequest somethingForNetwork(NetworkCapabilities need, - NetworkCallbacks networkCallbacks, int timeoutSec, int action) { + NetworkCallbackListener networkCallbackListener, int timeoutSec, int action) { NetworkRequest networkRequest = null; - if (networkCallbacks == null) throw new IllegalArgumentException("null NetworkCallbacks"); + if (networkCallbackListener == null) { + throw new IllegalArgumentException("null NetworkCallbackListener"); + } if (need == null) throw new IllegalArgumentException("null NetworkCapabilities"); try { addCallbackListener(); @@ -1930,8 +1978,8 @@ public class ConnectivityManager { timeoutSec, new Binder()); } if (networkRequest != null) { - synchronized(sNetworkCallbacks) { - sNetworkCallbacks.put(networkRequest, networkCallbacks); + synchronized(sNetworkCallbackListener) { + sNetworkCallbackListener.put(networkRequest, networkCallbackListener); } } } catch (RemoteException e) {} @@ -1943,46 +1991,44 @@ public class ConnectivityManager { * Request a network to satisfy a set of {@link NetworkCapabilities}. * * This {@link NetworkRequest} will live until released via - * {@link releaseNetworkRequest} or the calling application exits. - * Status of the request can be follwed by listening to the various - * callbacks described in {@link NetworkCallbacks}. The {@link Network} - * can be used by using the {@link bindSocketToNetwork}, - * {@link bindApplicationToNetwork} and {@link getAddrInfoOnNetwork} functions. + * {@link #releaseNetworkRequest} or the calling application exits. + * Status of the request can be followed by listening to the various + * callbacks described in {@link NetworkCallbackListener}. The {@link Network} + * can be used to direct traffic to the network. * * @param need {@link NetworkCapabilities} required by this request. - * @param networkCallbacks The callbacks to be utilized for this request. Note - * the callbacks can be shared by multiple requests and - * the NetworkRequest token utilized to determine to which - * request the callback relates. + * @param networkCallbackListener The {@link NetworkCallbackListener} to be utilized for this + * request. Note the callbacks can be shared by multiple + * requests and the NetworkRequest token utilized to + * determine to which request the callback relates. * @return A {@link NetworkRequest} object identifying the request. - * @hide */ public NetworkRequest requestNetwork(NetworkCapabilities need, - NetworkCallbacks networkCallbacks) { - return somethingForNetwork(need, networkCallbacks, 0, REQUEST); + NetworkCallbackListener networkCallbackListener) { + return somethingForNetwork(need, networkCallbackListener, 0, REQUEST); } /** * Request a network to satisfy a set of {@link NetworkCapabilities}, limited * by a timeout. * - * This function behaves identically, but if a suitable network is not found - * within the given time (in Seconds) the {@link NetworkCallbacks#unavailable} - * callback is called. The request must still be released normally by - * calling {@link releaseNetworkRequest}. + * This function behaves identically to the non-timedout version, but if a suitable + * network is not found within the given time (in Seconds) the + * {@link NetworkCallbackListener#unavailable} callback is called. The request must + * still be released normally by calling {@link releaseNetworkRequest}. * @param need {@link NetworkCapabilities} required by this request. - * @param networkCallbacks The callbacks to be utilized for this request. Note + * @param networkCallbackListener The callbacks to be utilized for this request. Note * the callbacks can be shared by multiple requests and * the NetworkRequest token utilized to determine to which * request the callback relates. * @param timeoutSec The time in seconds to attempt looking for a suitable network - * before {@link NetworkCallbacks#unavailable} is called. + * before {@link NetworkCallbackListener#unavailable} is called. * @return A {@link NetworkRequest} object identifying the request. * @hide */ public NetworkRequest requestNetwork(NetworkCapabilities need, - NetworkCallbacks networkCallbacks, int timeoutSec) { - return somethingForNetwork(need, networkCallbacks, timeoutSec, REQUEST); + NetworkCallbackListener networkCallbackListener, int timeoutSec) { + return somethingForNetwork(need, networkCallbackListener, timeoutSec, REQUEST); } /** @@ -1992,37 +2038,53 @@ public class ConnectivityManager { */ public final static int MAX_NETWORK_REQUEST_TIMEOUT_SEC = 100 * 60; + /** + * The lookup key for a {@link Network} object included with the intent after + * succesfully finding a network for the applications request. Retrieve it with + * {@link android.content.Intent#getParcelableExtra(String)}. + */ + public static final String EXTRA_NETWORK_REQUEST_NETWORK = "networkRequestNetwork"; + + /** + * The lookup key for a {@link NetworkCapabilities} object included with the intent after + * succesfully finding a network for the applications request. Retrieve it with + * {@link android.content.Intent#getParcelableExtra(String)}. + */ + public static final String EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES = + "networkRequestNetworkCapabilities"; + + /** * Request a network to satisfy a set of {@link NetworkCapabilities}. * - * This function behavies identically, but instead of {@link NetworkCallbacks} - * a {@link PendingIntent} is used. This means the request may outlive the - * calling application and get called back when a suitable network is found. + * This function behavies identically to the callback-equiped version, but instead + * of {@link NetworkCallbackListener} a {@link PendingIntent} is used. This means + * the request may outlive the calling application and get called back when a suitable + * network is found. *

          * The operation is an Intent broadcast that goes to a broadcast receiver that * you registered with {@link Context#registerReceiver} or through the * <receiver> tag in an AndroidManifest.xml file *

          * The operation Intent is delivered with two extras, a {@link Network} typed - * extra called {@link EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities} - * typed extra called {@link EXTRA_NETWORK_REQUEST_NETWORK_CAPABILTIES} containing + * extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK} and a {@link NetworkCapabilities} + * typed extra called {@link #EXTRA_NETWORK_REQUEST_NETWORK_CAPABILITIES} containing * the original requests parameters. It is important to create a new, - * {@link NetworkCallbacks} based request before completing the processing of the + * {@link NetworkCallbackListener} based request before completing the processing of the * Intent to reserve the network or it will be released shortly after the Intent * is processed. *

          * If there is already an request for this Intent registered (with the equality of * two Intents defined by {@link Intent#filterEquals}), then it will be removed and - * replace by this one, effectively releasing the previous {@link NetworkRequest}. + * replaced by this one, effectively releasing the previous {@link NetworkRequest}. *

          - * The request may be released normally by calling {@link releaseNetworkRequest}. + * The request may be released normally by calling {@link #releaseNetworkRequest}. * - * @param need {@link NetworkCapabilties} required by this request. + * @param need {@link NetworkCapabilities} required by this request. * @param operation Action to perform when the network is available (corresponds - * to the {@link NetworkCallbacks#onAvailable} call. Typically + * to the {@link NetworkCallbackListener#onAvailable} call. Typically * comes from {@link PendingIntent#getBroadcast}. * @return A {@link NetworkRequest} object identifying the request. - * @hide */ public NetworkRequest requestNetwork(NetworkCapabilities need, PendingIntent operation) { try { @@ -2035,28 +2097,27 @@ public class ConnectivityManager { * Registers to receive notifications about all networks which satisfy the given * {@link NetworkCapabilities}. The callbacks will continue to be called until * either the application exits or the request is released using - * {@link releaseNetworkRequest}. + * {@link #releaseNetworkRequest}. * * @param need {@link NetworkCapabilities} required by this request. - * @param networkCallbacks The {@link NetworkCallbacks} to be called as suitable + * @param networkCallbackListener The {@link NetworkCallbackListener} to be called as suitable * networks change state. * @return A {@link NetworkRequest} object identifying the request. - * @hide */ public NetworkRequest listenForNetwork(NetworkCapabilities need, - NetworkCallbacks networkCallbacks) { - return somethingForNetwork(need, networkCallbacks, 0, LISTEN); + NetworkCallbackListener networkCallbackListener) { + return somethingForNetwork(need, networkCallbackListener, 0, LISTEN); } /** - * Releases a {NetworkRequest} generated either through a {@link requestNetwork} - * or a {@link listenForNetwork} call. The {@link NetworkCallbacks} given in the - * earlier call may continue receiving calls until the {@link NetworkCallbacks#onReleased} - * function is called, signifiying the end of the request. + * Releases a {@link NetworkRequest} generated either through a {@link #requestNetwork} + * or a {@link #listenForNetwork} call. The {@link NetworkCallbackListener} given in the + * earlier call may continue receiving calls until the + * {@link NetworkCallbackListener#onReleased} function is called, signifying the end + * of the request. * * @param networkRequest The {@link NetworkRequest} generated by an earlier call to - * {@link requestNetwork} or {@link listenForNetwork}. - * @hide + * {@link #requestNetwork} or {@link #listenForNetwork}. */ public void releaseNetworkRequest(NetworkRequest networkRequest) { if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest"); diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index a99da789f3..e0d69e372c 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -26,11 +26,10 @@ import javax.net.SocketFactory; /** * Identifies a {@code Network}. This is supplied to applications via - * {@link ConnectivityManager#NetworkCallbacks} in response to + * {@link ConnectivityManager.NetworkCallbackListener} in response to * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}. * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis * through a targeted {@link SocketFactory} or process-wide via {@link #bindProcess}. - * @hide */ public class Network implements Parcelable { diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 80074a5e7a..480cb057b0 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -22,18 +22,18 @@ import android.os.Parcelable; import java.util.concurrent.atomic.AtomicInteger; /** - * Defines a request for a network, made by calling {@link ConnectivityManager.requestNetwork}. + * Defines a request for a network, made by calling {@link ConnectivityManager#requestNetwork} + * or {@link ConnectivityManager#listenForNetwork}. * * This token records the {@link NetworkCapabilities} used to make the request and identifies * the request. It should be used to release the request via - * {@link ConnectivityManager.releaseNetworkRequest} when the network is no longer desired. - * @hide + * {@link ConnectivityManager#releaseNetworkRequest} when the network is no longer desired. */ public class NetworkRequest implements Parcelable { /** * The {@link NetworkCapabilities} that define this request. This should not be modified. * The networkCapabilities of the request are set when - * {@link ConnectivityManager.requestNetwork} is called and the value is presented here + * {@link ConnectivityManager#requestNetwork} is called and the value is presented here * as a convenient reminder of what was requested. */ public final NetworkCapabilities networkCapabilities; From cf81de2b0dba802c7220121ba65ee5ca5a69b161 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 19 May 2014 11:00:12 -0700 Subject: [PATCH 256/296] Fix the build Change-Id: I18f78f6055f6f9c14571058d6834c8dec01aa732 --- services/core/java/com/android/server/ConnectivityService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 01af753b90..cc132bed27 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -20,7 +20,7 @@ import static android.Manifest.permission.MANAGE_NETWORK_POLICY; import static android.Manifest.permission.RECEIVE_DATA_ACTIVITY_CHANGE; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; -import static android.net.ConnectivityManager.NetworkCallbacks; +import static android.net.ConnectivityManager.NetworkCallbackListener; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_DUMMY; import static android.net.ConnectivityManager.TYPE_ETHERNET; From 46dcbab0a261ff5f735c11a9edfe051d802eb532 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 16 May 2014 15:49:14 -0700 Subject: [PATCH 257/296] Add NetworkFactory names and unregistration. Some Factories come and go (Telephony) and so they need to be able to unregister. Also, debugging is tough when the factories are anonymous, so add names for logging. Lastly, only send single set of NetworkRequests to a newly registered NetworkFactory and only send the requests. Change-Id: I717d63363f25c446f8ecf38d933b1a35d744af6e --- .../java/android/net/ConnectivityManager.java | 11 ++- .../android/net/IConnectivityManager.aidl | 4 +- .../android/server/ConnectivityService.java | 95 ++++++++++++++----- 3 files changed, 82 insertions(+), 28 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1837335615..80a9598ada 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1655,9 +1655,16 @@ public class ConnectivityManager { } /** {@hide} */ - public void registerNetworkFactory(Messenger messenger) { + public void registerNetworkFactory(Messenger messenger, String name) { try { - mService.registerNetworkFactory(messenger); + mService.registerNetworkFactory(messenger, name); + } catch (RemoteException e) { } + } + + /** {@hide} */ + public void unregisterNetworkFactory(Messenger messenger) { + try { + mService.unregisterNetworkFactory(messenger); } catch (RemoteException e) { } } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 885b8b6891..d97b1e95bd 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -153,7 +153,9 @@ interface IConnectivityManager void setAirplaneMode(boolean enable); - void registerNetworkFactory(in Messenger messenger); + void registerNetworkFactory(in Messenger messenger, in String name); + + void unregisterNetworkFactory(in Messenger messenger); void registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp, in NetworkCapabilities nc, int score); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index cc132bed27..af53fef0ca 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -398,7 +398,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { /** * used internally when registering NetworkFactories - * obj = Messenger + * obj = NetworkFactoryInfo */ private static final int EVENT_REGISTER_NETWORK_FACTORY = 17; @@ -434,6 +434,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_RELEASE_NETWORK_REQUEST = 22; + /** + * used internally when registering NetworkFactories + * obj = Messenger + */ + private static final int EVENT_UNREGISTER_NETWORK_FACTORY = 23; + + /** Handler used for internal events. */ final private InternalHandler mHandler; /** Handler used for incoming {@link NetworkStateTracker} events. */ @@ -2889,6 +2896,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { return; } + pw.println("NetworkFactories for:"); + pw.increaseIndent(); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + pw.println(nfi.name); + } + pw.decreaseIndent(); + pw.println(); + NetworkAgentInfo defaultNai = mNetworkForRequestId.get(mDefaultRequest.requestId); pw.print("Active default network: "); if (defaultNai == null) { @@ -2983,6 +2998,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (nai == null) { loge("NetworkAgent not found for EVENT_NETWORK_PROPERTIES_CHANGED"); } else { + if (VDBG) log("Update of Linkproperties for " + nai.name()); LinkProperties oldLp = nai.linkProperties; nai.linkProperties = (LinkProperties)msg.obj; updateLinkProperties(nai, oldLp); @@ -3096,18 +3112,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleAsyncChannelHalfConnect(Message msg) { AsyncChannel ac = (AsyncChannel) msg.obj; - if (mNetworkFactories.contains(ac)) { + if (mNetworkFactoryInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { if (VDBG) log("NetworkFactory connected"); // A network factory has connected. Send it all current NetworkRequests. for (NetworkRequestInfo nri : mNetworkRequests.values()) { + if (nri.isRequest == false) continue; NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, (nai != null ? nai.currentScore : 0), 0, nri.request); } } else { loge("Error connecting NetworkFactory"); - mNetworkFactories.remove(ac); + mNetworkFactoryInfos.remove(msg.obj); } } else if (mNetworkAgentInfos.containsKey(msg.replyTo)) { if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { @@ -3214,8 +3231,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetworkRequests.put(nri.request, nri); if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) { if (DBG) log("sending new NetworkRequest to factories"); - for (AsyncChannel ac : mNetworkFactories) { - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); } } } @@ -3236,8 +3253,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (nri.isRequest) { - for (AsyncChannel factory : mNetworkFactories) { - factory.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); } if (affectedNetwork != null) { @@ -3356,7 +3373,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } case EVENT_REGISTER_NETWORK_FACTORY: { - handleRegisterNetworkFactory((Messenger)msg.obj); + handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj); + break; + } + case EVENT_UNREGISTER_NETWORK_FACTORY: { + handleUnregisterNetworkFactory((Messenger)msg.obj); break; } case EVENT_REGISTER_NETWORK_AGENT: { @@ -5222,10 +5243,22 @@ public class ConnectivityService extends IConnectivityManager.Stub { mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, wakeupTime, intent); } - private final ArrayList mNetworkFactories = new ArrayList(); + private final HashMap mNetworkFactoryInfos = + new HashMap(); private final HashMap mNetworkRequests = new HashMap(); + private static class NetworkFactoryInfo { + public final String name; + public final Messenger messenger; + public final AsyncChannel asyncChannel; + + public NetworkFactoryInfo(String name, Messenger messenger, AsyncChannel asyncChannel) { + this.name = name; + this.messenger = messenger; + this.asyncChannel = asyncChannel; + } + } private class NetworkRequestInfo implements IBinder.DeathRecipient { static final boolean REQUEST = true; @@ -5263,6 +5296,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { request + ", " + mBinder + ")"); releaseNetworkRequest(request); } + + public String toString() { + return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" + + mPid + " for " + request; + } } @Override @@ -5326,24 +5364,31 @@ public class ConnectivityService extends IConnectivityManager.Stub { } @Override - public void registerNetworkFactory(Messenger messenger) { + public void registerNetworkFactory(Messenger messenger, String name) { enforceConnectivityInternalPermission(); - mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, messenger)); + NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel()); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); } - private void handleRegisterNetworkFactory(Messenger messenger) { - if (VDBG) log("Got NetworkFactory Messenger"); - AsyncChannel ac = new AsyncChannel(); - mNetworkFactories.add(ac); - ac.connect(mContext, mTrackerHandler, messenger); - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - if (nri.isRequest) { - int score = 0; - NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); - if (currentNetwork != null) score = currentNetwork.currentScore; - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); - } + private void handleRegisterNetworkFactory(NetworkFactoryInfo nfi) { + if (VDBG) log("Got NetworkFactory Messenger for " + nfi.name); + mNetworkFactoryInfos.put(nfi.messenger, nfi); + nfi.asyncChannel.connect(mContext, mTrackerHandler, nfi.messenger); + } + + @Override + public void unregisterNetworkFactory(Messenger messenger) { + enforceConnectivityInternalPermission(); + mHandler.sendMessage(mHandler.obtainMessage(EVENT_UNREGISTER_NETWORK_FACTORY, messenger)); + } + + private void handleUnregisterNetworkFactory(Messenger messenger) { + NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(messenger); + if (nfi == null) { + if (VDBG) log("Failed to find Messenger in unregisterNetworkFactory"); + return; } + if (VDBG) log("unregisterNetworkFactory for " + nfi.name); } /** @@ -5535,8 +5580,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); - for (AsyncChannel ac : mNetworkFactories) { - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); + for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); } } From 6d8dcb76d87743bca8f75680b887a42ee7afebbb Mon Sep 17 00:00:00 2001 From: Jaewan Kim Date: Mon, 10 Mar 2014 17:10:51 +0900 Subject: [PATCH 258/296] Move IP config from WifiConfiguration to IpConfiguration. This is so that Ethernet can use it in the future. Bug: 7606609 Bug: 8687763 Change-Id: I5d1189682b13f1088848809604690648d8d9ecca --- core/java/android/net/IpConfiguration.java | 151 +++++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 core/java/android/net/IpConfiguration.java diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java new file mode 100644 index 0000000000..4730bab38c --- /dev/null +++ b/core/java/android/net/IpConfiguration.java @@ -0,0 +1,151 @@ +/* + * 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; + +import android.net.LinkProperties; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Objects; + +/** + * A class representing a configured network. + * @hide + */ +public class IpConfiguration implements Parcelable { + private static final String TAG = "IpConfiguration"; + + public enum IpAssignment { + /* Use statically configured IP settings. Configuration can be accessed + * with linkProperties */ + STATIC, + /* Use dynamically configured IP settigns */ + DHCP, + /* no IP details are assigned, this is used to indicate + * that any existing IP settings should be retained */ + UNASSIGNED + } + + public IpAssignment ipAssignment; + + public enum ProxySettings { + /* No proxy is to be used. Any existing proxy settings + * should be cleared. */ + NONE, + /* Use statically configured proxy. Configuration can be accessed + * with linkProperties */ + STATIC, + /* no proxy details are assigned, this is used to indicate + * that any existing proxy settings should be retained */ + UNASSIGNED, + /* Use a Pac based proxy. + */ + PAC + } + + public ProxySettings proxySettings; + + public LinkProperties linkProperties; + + public IpConfiguration(IpConfiguration source) { + if (source != null) { + ipAssignment = source.ipAssignment; + proxySettings = source.proxySettings; + linkProperties = new LinkProperties(source.linkProperties); + } else { + ipAssignment = IpAssignment.UNASSIGNED; + proxySettings = ProxySettings.UNASSIGNED; + linkProperties = new LinkProperties(); + } + } + + public IpConfiguration() { + this(null); + } + + public IpConfiguration(IpAssignment ipAssignment, + ProxySettings proxySettings, + LinkProperties linkProperties) { + this.ipAssignment = ipAssignment; + this.proxySettings = proxySettings; + this.linkProperties = new LinkProperties(linkProperties); + } + + @Override + public String toString() { + StringBuilder sbuf = new StringBuilder(); + sbuf.append("IP assignment: " + ipAssignment.toString()); + sbuf.append("\n"); + sbuf.append("Proxy settings: " + proxySettings.toString()); + sbuf.append("\n"); + sbuf.append(linkProperties.toString()); + sbuf.append("\n"); + + return sbuf.toString(); + } + + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + + if (!(o instanceof IpConfiguration)) { + return false; + } + + IpConfiguration other = (IpConfiguration) o; + return this.ipAssignment == other.ipAssignment && + this.proxySettings == other.proxySettings && + Objects.equals(this.linkProperties, other.linkProperties); + } + + @Override + public int hashCode() { + return 13 + (linkProperties != null ? linkProperties.hashCode() : 0) + + 17 * ipAssignment.ordinal() + + 47 * proxySettings.ordinal(); + } + + /** Implement the Parcelable interface */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(ipAssignment.name()); + dest.writeString(proxySettings.name()); + dest.writeParcelable(linkProperties, flags); + } + + /** Implement the Parcelable interface */ + public static final Creator CREATOR = + new Creator() { + public IpConfiguration createFromParcel(Parcel in) { + IpConfiguration config = new IpConfiguration(); + config.ipAssignment = IpAssignment.valueOf(in.readString()); + config.proxySettings = ProxySettings.valueOf(in.readString()); + config.linkProperties = in.readParcelable(null); + return config; + } + + public IpConfiguration[] newArray(int size) { + return new IpConfiguration[size]; + } + }; +} From 347122d2986c5f629b4c64583a6bf8165992ea81 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 21 May 2014 16:26:58 -0700 Subject: [PATCH 259/296] Delete the EthernetDataTracker. Code search says these are the only two files that use it. The tracker will be resurrected in a slightly different form in frameworks/opt/net/ethernet. Bug: 14993642 Bug: 14981801 Change-Id: I2477668ca78dfe46661dda1d97c7f786fd7eba35 --- .../core/java/com/android/server/ConnectivityService.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index af53fef0ca..0ad5ce269a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -23,7 +23,6 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.NetworkCallbackListener; import static android.net.ConnectivityManager.TYPE_BLUETOOTH; import static android.net.ConnectivityManager.TYPE_DUMMY; -import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_MMS; import static android.net.ConnectivityManager.TYPE_MOBILE_SUPL; @@ -65,7 +64,6 @@ import android.database.ContentObserver; import android.net.CaptivePortalTracker; import android.net.ConnectivityManager; import android.net.DummyDataStateTracker; -import android.net.EthernetDataTracker; import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkPolicyListener; @@ -824,8 +822,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return BluetoothTetheringDataTracker.getInstance(); case TYPE_WIMAX: return makeWimaxStateTracker(mContext, mTrackerHandler); - case TYPE_ETHERNET: - return EthernetDataTracker.getInstance(); case TYPE_PROXY: return new ProxyDataTracker(); default: From 9e66e881600bd5c74fdf60b26c99d348308604cb Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 20 May 2014 11:25:35 -0400 Subject: [PATCH 260/296] Implement bind-to-network functionality of android.net.Network. This is implemented by calling through to netd_client. Included are functions to bind-to-network-for-process strictly for DNS to facilitate startUsingNetworkFeature() reimplementation. Change-Id: Ib22c7d02ea81d251bdfeeb0f64a47ce32eefcb1b --- core/java/android/net/Network.java | 89 ++++++++++++++++++++++++- core/java/android/net/NetworkUtils.java | 44 ++++++++++++ core/jni/android_net_NetUtils.cpp | 38 +++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index e0d69e372c..e489e052d9 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -16,10 +16,13 @@ package android.net; +import android.net.NetworkUtils; import android.os.Parcelable; import android.os.Parcel; +import java.io.IOException; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import javax.net.SocketFactory; @@ -38,6 +41,8 @@ public class Network implements Parcelable { */ public final int netId; + private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; + /** * @hide */ @@ -78,6 +83,59 @@ public class Network implements Parcelable { return InetAddress.getByNameOnNet(host, netId); } + /** + * A {@code SocketFactory} that produces {@code Socket}'s bound to this network. + */ + private class NetworkBoundSocketFactory extends SocketFactory { + private final int mNetId; + + public NetworkBoundSocketFactory(int netId) { + super(); + mNetId = netId; + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + Socket socket = createSocket(); + socket.bind(new InetSocketAddress(localHost, localPort)); + socket.connect(new InetSocketAddress(host, port)); + return socket; + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, + int localPort) throws IOException { + Socket socket = createSocket(); + socket.bind(new InetSocketAddress(localAddress, localPort)); + socket.connect(new InetSocketAddress(address, port)); + return socket; + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + Socket socket = createSocket(); + socket.connect(new InetSocketAddress(host, port)); + return socket; + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + Socket socket = createSocket(); + socket.connect(new InetSocketAddress(host, port)); + return socket; + } + + @Override + public Socket createSocket() throws IOException { + Socket socket = new Socket(); + // Query a property of the underlying socket to ensure the underlying + // socket exists so a file descriptor is available to bind to a network. + socket.getReuseAddress(); + NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), mNetId); + return socket; + } + } + /** * Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by * this factory will have its traffic sent over this {@code Network}. Note that if this @@ -88,7 +146,10 @@ public class Network implements Parcelable { * {@code Network}. */ public SocketFactory socketFactory() { - return null; + if (mNetworkBoundSocketFactory == null) { + mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); + } + return mNetworkBoundSocketFactory; } /** @@ -99,6 +160,29 @@ public class Network implements Parcelable { * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}. */ public void bindProcess() { + NetworkUtils.bindProcessToNetwork(netId); + } + + /** + * Binds host resolutions performed by this process to this network. {@link #bindProcess} + * takes precedence over this setting. + * + * @hide + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + public void bindProcessForHostResolution() { + NetworkUtils.bindProcessToNetworkForHostResolution(netId); + } + + /** + * Clears any process specific {@link Network} binding for host resolution. This does + * not clear bindings enacted via {@link #bindProcess}. + * + * @hide + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + public void unbindProcessForHostResolution() { + NetworkUtils.unbindProcessToNetworkForHostResolution(); } /** @@ -107,7 +191,7 @@ public class Network implements Parcelable { * @return {@code Network} to which this process is bound. */ public static Network getProcessBoundNetwork() { - return null; + return new Network(NetworkUtils.getNetworkBoundToProcess()); } /** @@ -115,6 +199,7 @@ public class Network implements Parcelable { * {@link Network#bindProcess}. */ public static void unbindProcess() { + NetworkUtils.unbindProcessToNetwork(); } // implement the Parcelable interface diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index b24d3969f7..edb32866d3 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -108,6 +108,50 @@ public class NetworkUtils { */ public native static void markSocket(int socketfd, int mark); + /** + * Binds the current process to the network designated by {@code netId}. All sockets created + * in the future (and not explicitly bound via a bound {@link SocketFactory} (see + * {@link Network#socketFactory}) will be bound to this network. Note that if this + * {@code Network} ever disconnects all sockets created in this way will cease to work. This + * is by design so an application doesn't accidentally use sockets it thinks are still bound to + * a particular {@code Network}. + */ + public native static void bindProcessToNetwork(int netId); + + /** + * Clear any process specific {@code Network} binding. This reverts a call to + * {@link #bindProcessToNetwork}. + */ + public native static void unbindProcessToNetwork(); + + /** + * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if + * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}. + */ + public native static int getNetworkBoundToProcess(); + + /** + * Binds host resolutions performed by this process to the network designated by {@code netId}. + * {@link #bindProcessToNetwork} takes precedence over this setting. + * + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + public native static void bindProcessToNetworkForHostResolution(int netId); + + /** + * Clears any process specific {@link Network} binding for host resolution. This does + * not clear bindings enacted via {@link #bindProcessToNetwork}. + * + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + public native static void unbindProcessToNetworkForHostResolution(); + + /** + * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This + * overrides any binding via {@link #bindProcessToNetwork}. + */ + public native static void bindSocketToNetwork(int socketfd, int netId); + /** * Convert a IPv4 address from an integer to an InetAddress. * @param hostAddress an int corresponding to the IPv4 address in network byte order diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 6d23c32b33..bc5e1b3237 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -18,6 +18,8 @@ #include "jni.h" #include "JNIHelp.h" +#include "NetdClient.h" +#include "resolv_netid.h" #include #include #include @@ -250,6 +252,36 @@ static void android_net_utils_markSocket(JNIEnv *env, jobject thiz, jint socket, } } +static void android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId) +{ + setNetworkForProcess(netId); +} + +static void android_net_utils_unbindProcessToNetwork(JNIEnv *env, jobject thiz) +{ + setNetworkForProcess(NETID_UNSET); +} + +static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz) +{ + return getNetworkForProcess(); +} + +static void android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz, jint netId) +{ + setNetworkForResolv(netId); +} + +static void android_net_utils_unbindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz) +{ + setNetworkForResolv(NETID_UNSET); +} + +static void android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket, jint netId) +{ + setNetworkForSocket(netId, socket); +} + // ---------------------------------------------------------------------------- /* @@ -267,6 +299,12 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError }, { "markSocket", "(II)V", (void*) android_net_utils_markSocket }, + { "bindProcessToNetwork", "(I)V", (void*) android_net_utils_bindProcessToNetwork }, + { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess }, + { "unbindProcessToNetwork", "()V", (void*) android_net_utils_unbindProcessToNetwork }, + { "bindProcessToNetworkForHostResolution", "(I)V", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, + { "unbindProcessToNetworkForHostResolution", "()V", (void*) android_net_utils_unbindProcessToNetworkForHostResolution }, + { "bindSocketToNetwork", "(II)V", (void*) android_net_utils_bindSocketToNetwork }, }; int register_android_net_NetworkUtils(JNIEnv* env) From f5b09c82caab37f939fc9c9acb22c2f90836a02e Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 21 May 2014 20:04:36 -0700 Subject: [PATCH 261/296] Move dis/enable of mobile data to Telephony ConnectivityService doesn't do this anymore. bug:15077247 Change-Id: I3208c91b2c0369b594987f39ca29da7478435513 --- .../java/android/net/ConnectivityManager.java | 38 ++++++----------- .../android/net/IConnectivityManager.aidl | 3 -- .../android/server/ConnectivityService.java | 41 ------------------- 3 files changed, 12 insertions(+), 70 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 80a9598ada..2f2aba3286 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -35,15 +35,17 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; +import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.Log; +import com.android.internal.telephony.ITelephony; +import com.android.internal.util.Protocol; + import java.net.InetAddress; import java.util.concurrent.atomic.AtomicInteger; import java.util.HashMap; -import com.android.internal.util.Protocol; - /** * Class that answers queries about the state of network connectivity. It also * notifies applications when network connectivity changes. Get an instance @@ -940,34 +942,18 @@ public class ConnectivityManager { } /** - * Gets the value of the setting for enabling Mobile data. - * - * @return Whether mobile data is enabled. - * - *

          This method requires the call to hold the permission - * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * @hide + * @deprecated Talk to TelephonyManager directly */ public boolean getMobileDataEnabled() { - try { - return mService.getMobileDataEnabled(); - } catch (RemoteException e) { - return true; - } - } - - /** - * Sets the persisted value for enabling/disabling Mobile data. - * - * @param enabled Whether the user wants the mobile data connection used - * or not. - * @hide - */ - public void setMobileDataEnabled(boolean enabled) { - try { - mService.setMobileDataEnabled(enabled); - } catch (RemoteException e) { + IBinder b = ServiceManager.getService(Context.TELEPHONY_SERVICE); + if (b != null) { + try { + ITelephony it = ITelephony.Stub.asInterface(b); + return it.getDataEnabled(); + } catch (RemoteException e) { } } + return false; } /** diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index d97b1e95bd..baec36ad48 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -74,9 +74,6 @@ interface IConnectivityManager boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName); - boolean getMobileDataEnabled(); - void setMobileDataEnabled(boolean enabled); - /** Policy control over specific {@link NetworkStateTracker}. */ void setPolicyDataEnable(int networkType, boolean enabled); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0ad5ce269a..37b75d6877 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -342,12 +342,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_INET_CONDITION_HOLD_END = 5; - /** - * used internally to set enable/disable cellular data - * arg1 = ENBALED or DISABLED - */ - private static final int EVENT_SET_MOBILE_DATA = 7; - /** * used internally to clear a wakelock when transitioning * from one net to another @@ -1822,20 +1816,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return true; } - /** - * @see ConnectivityManager#getMobileDataEnabled() - */ - public boolean getMobileDataEnabled() { - // TODO: This detail should probably be in DataConnectionTracker's - // which is where we store the value and maybe make this - // asynchronous. - enforceAccessPermission(); - boolean retVal = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MOBILE_DATA, 1) == 1; - if (VDBG) log("getMobileDataEnabled returning " + retVal); - return retVal; - } - public void setDataDependency(int networkType, boolean met) { enforceConnectivityInternalPermission(); @@ -1908,22 +1888,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } }; - /** - * @see ConnectivityManager#setMobileDataEnabled(boolean) - */ - public void setMobileDataEnabled(boolean enabled) { - enforceChangePermission(); - if (DBG) log("setMobileDataEnabled(" + enabled + ")"); - - mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, - (enabled ? ENABLED : DISABLED), 0)); - } - - private void handleSetMobileData(boolean enabled) { - // TODO - handle this - probably generalize passing in a transport type and send to the - // factories? - } - @Override public void setPolicyDataEnable(int networkType, boolean enabled) { // only someone like NPMS should only be calling us @@ -3315,11 +3279,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleInetConditionHoldEnd(netType, sequence); break; } - case EVENT_SET_MOBILE_DATA: { - boolean enabled = (msg.arg1 == ENABLED); - handleSetMobileData(enabled); - break; - } case EVENT_APPLY_GLOBAL_HTTP_PROXY: { handleDeprecatedGlobalHttpProxy(); break; From 8cc6a4994ba900c71f319eebe77e31797b80dcb2 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 21 May 2014 15:01:03 -0700 Subject: [PATCH 262/296] Battery monitoring fixes: - Improve monitoring of level changes to not be confused when it goes up while draining or down while charging. - Put back in connectivity service code to tell battery stats about the interfaces. - Turn back on reporting of mobile radio active state from the RIL. - Fix bug in marshalling/unmarshalling that would cause the UI to show bad data. Change-Id: I733ef52702894cca81a0813eccdfc1023e546fce --- .../java/com/android/server/ConnectivityService.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index af53fef0ca..a300095c59 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5754,10 +5754,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // updateNetworkSettings(); } // notify battery stats service about this network -// try { - // TODO - //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType); -// } catch (RemoteException e) { } + try { + BatteryStatsService.getService().noteNetworkInterfaceType( + newNetwork.linkProperties.getInterfaceName(), + newNetwork.networkInfo.getType()); + } catch (RemoteException e) { } notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE); } else { if (DBG && newNetwork.networkRequests.size() != 0) { From 3508963dcf6b8c481ff007ac4928485466990e2f Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 21 May 2014 15:01:03 -0700 Subject: [PATCH 263/296] (DO NOT MERGE) Battery monitoring fixes: - Improve monitoring of level changes to not be confused when it goes up while draining or down while charging. - Put back in connectivity service code to tell battery stats about the interfaces. - Turn back on reporting of mobile radio active state from the RIL. - Fix bug in marshalling/unmarshalling that would cause the UI to show bad data. Change-Id: I733ef52702894cca81a0813eccdfc1023e546fce --- .../java/com/android/server/ConnectivityService.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0ad5ce269a..7ecf248291 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5750,10 +5750,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { // updateNetworkSettings(); } // notify battery stats service about this network -// try { - // TODO - //BatteryStatsService.getService().noteNetworkInterfaceType(iface, netType); -// } catch (RemoteException e) { } + try { + BatteryStatsService.getService().noteNetworkInterfaceType( + newNetwork.linkProperties.getInterfaceName(), + newNetwork.networkInfo.getType()); + } catch (RemoteException e) { } notifyNetworkCallbacks(newNetwork, ConnectivityManager.CALLBACK_AVAILABLE); } else { if (DBG && newNetwork.networkRequests.size() != 0) { From e11b6734e73e5f0e8baff6c43b216e01be061dcf Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 27 May 2014 10:19:39 -0400 Subject: [PATCH 264/296] Adjust Network's SocketFactory to restrict host name resolution to that Network Change-Id: Iab9a5a2e060fe261f4be9ba974c1a55fb6b9c98b --- core/java/android/net/Network.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index e489e052d9..64516e62d1 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -94,11 +94,26 @@ public class Network implements Parcelable { mNetId = netId; } + private void connectToHost(Socket socket, String host, int port) throws IOException { + // Lookup addresses only on this Network. + InetAddress[] hostAddresses = getAllByName(host); + // Try all but last address ignoring exceptions. + for (int i = 0; i < hostAddresses.length - 1; i++) { + try { + socket.connect(new InetSocketAddress(hostAddresses[i], port)); + return; + } catch (IOException e) { + } + } + // Try last address. Do throw exceptions. + socket.connect(new InetSocketAddress(hostAddresses[hostAddresses.length - 1], port)); + } + @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { Socket socket = createSocket(); socket.bind(new InetSocketAddress(localHost, localPort)); - socket.connect(new InetSocketAddress(host, port)); + connectToHost(socket, host, port); return socket; } @@ -121,7 +136,7 @@ public class Network implements Parcelable { @Override public Socket createSocket(String host, int port) throws IOException { Socket socket = createSocket(); - socket.connect(new InetSocketAddress(host, port)); + connectToHost(socket, host, port); return socket; } From 25ef738d75b3d38316c37d4cc068954716c26da5 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 15 May 2014 18:07:26 -0700 Subject: [PATCH 265/296] Rewrite startUsingNetworkFeature for new API bug:14993207 Change-Id: I041a80faa07bf3094af13a6c606f3b15aa03f789 --- .../java/android/net/ConnectivityManager.java | 219 ++++++++++++++++-- .../android/net/IConnectivityManager.aidl | 4 +- .../android/server/ConnectivityService.java | 30 ++- .../server/connectivity/NetworkAgentInfo.java | 17 ++ 4 files changed, 243 insertions(+), 27 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2f2aba3286..24844ba46c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -40,6 +40,7 @@ import android.util.ArrayMap; import android.util.Log; import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.Protocol; import java.net.InetAddress; @@ -807,11 +808,34 @@ public class ConnectivityManager { * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api. */ public int startUsingNetworkFeature(int networkType, String feature) { - try { - return mService.startUsingNetworkFeature(networkType, feature, - new Binder()); - } catch (RemoteException e) { - return -1; + NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); + if (netCap == null) { + Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " + + feature); + return PhoneConstants.APN_REQUEST_FAILED; + } + + NetworkRequest request = null; + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l != null) { + Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest); + renewRequestLocked(l); + if (l.currentNetwork != null) { + return PhoneConstants.APN_ALREADY_ACTIVE; + } else { + return PhoneConstants.APN_REQUEST_STARTED; + } + } + + request = requestNetworkForFeatureLocked(netCap); + } + if (request != null) { + Log.d(TAG, "starting startUsingNeworkFeature for request " + request); + return PhoneConstants.APN_REQUEST_STARTED; + } else { + Log.d(TAG, " request Failed"); + return PhoneConstants.APN_REQUEST_FAILED; } } @@ -831,11 +855,169 @@ public class ConnectivityManager { * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api. */ public int stopUsingNetworkFeature(int networkType, String feature) { - try { - return mService.stopUsingNetworkFeature(networkType, feature); - } catch (RemoteException e) { + NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); + if (netCap == null) { + Log.d(TAG, "Can't satisfy stopUsingNetworkFeature for " + networkType + ", " + + feature); return -1; } + + NetworkRequest request = removeRequestForFeature(netCap); + if (request != null) { + Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature); + releaseNetworkRequest(request); + } + return 1; + } + + private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { + if (networkType == TYPE_MOBILE) { + int cap = -1; + if ("enableMMS".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_MMS; + } else if ("enableSUPL".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_SUPL; + } else if ("enableDUN".equals(feature) || "enableDUNAlways".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_DUN; + } else if ("enableHIPRI".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_INTERNET; + } else if ("enableFOTA".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_FOTA; + } else if ("enableIMS".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_IMS; + } else if ("enableCBS".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_CBS; + } else { + return null; + } + NetworkCapabilities netCap = new NetworkCapabilities(); + netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + netCap.addNetworkCapability(cap); + return netCap; + } else if (networkType == TYPE_WIFI) { + if ("p2p".equals(feature)) { + NetworkCapabilities netCap = new NetworkCapabilities(); + netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); + return netCap; + } + } + return null; + } + + private int networkTypeForNetworkCapabilities(NetworkCapabilities netCap) { + if (netCap == null) return TYPE_NONE; + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { + return TYPE_MOBILE_CBS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) { + return TYPE_MOBILE_IMS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) { + return TYPE_MOBILE_FOTA; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { + return TYPE_MOBILE_DUN; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) { + return TYPE_MOBILE_SUPL; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { + return TYPE_MOBILE_MMS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + return TYPE_MOBILE_HIPRI; + } + return TYPE_NONE; + } + + private static class LegacyRequest { + NetworkCapabilities networkCapabilities; + NetworkRequest networkRequest; + int expireSequenceNumber; + Network currentNetwork; + int delay = -1; + NetworkCallbackListener networkCallbackListener = new NetworkCallbackListener() { + @Override + public void onAvailable(NetworkRequest request, Network network) { + currentNetwork = network; + Log.d(TAG, "startUsingNetworkFeature got Network:" + network); + network.bindProcessForHostResolution(); + } + @Override + public void onLost(NetworkRequest request, Network network) { + if (network.equals(currentNetwork)) { + currentNetwork = null; + network.unbindProcessForHostResolution(); + } + Log.d(TAG, "startUsingNetworkFeature lost Network:" + network); + } + }; + } + + private HashMap sLegacyRequests = + new HashMap(); + + private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) { + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l != null) return l.networkRequest; + } + return null; + } + + private void renewRequestLocked(LegacyRequest l) { + l.expireSequenceNumber++; + Log.d(TAG, "renewing request to seqNum " + l.expireSequenceNumber); + sendExpireMsgForFeature(l.networkCapabilities, l.expireSequenceNumber, l.delay); + } + + private void expireRequest(NetworkCapabilities netCap, int sequenceNum) { + int ourSeqNum = -1; + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l == null) return; + ourSeqNum = l.expireSequenceNumber; + if (l.expireSequenceNumber == sequenceNum) { + releaseNetworkRequest(l.networkRequest); + sLegacyRequests.remove(netCap); + } + } + Log.d(TAG, "expireRequest with " + ourSeqNum + ", " + sequenceNum); + } + + private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) { + int delay = -1; + int type = networkTypeForNetworkCapabilities(netCap); + try { + delay = mService.getRestoreDefaultNetworkDelay(type); + } catch (RemoteException e) {} + LegacyRequest l = new LegacyRequest(); + l.networkCapabilities = netCap; + l.delay = delay; + l.expireSequenceNumber = 0; + l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0, + REQUEST, true); + if (l.networkRequest == null) return null; + sLegacyRequests.put(netCap, l); + sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay); + return l.networkRequest; + } + + private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) { + if (delay >= 0) { + Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay); + Message msg = sCallbackHandler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap); + sCallbackHandler.sendMessageDelayed(msg, delay); + } + } + + private NetworkRequest removeRequestForFeature(NetworkCapabilities netCap) { + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.remove(netCap); + if (l == null) return null; + return l.networkRequest; + } } /** @@ -1782,8 +1964,10 @@ public class ConnectivityManager { public static final int CALLBACK_RELEASED = BASE + 8; /** @hide */ public static final int CALLBACK_EXIT = BASE + 9; + /** @hide obj = NetworkCapabilities, arg1 = seq number */ + private static final int EXPIRE_LEGACY_REQUEST = BASE + 10; - private static class CallbackHandler extends Handler { + private class CallbackHandler extends Handler { private final HashMapmCallbackMap; private final AtomicInteger mRefCount; private static final String TAG = "ConnectivityManager.CallbackHandler"; @@ -1903,6 +2087,10 @@ public class ConnectivityManager { getLooper().quit(); break; } + case EXPIRE_LEGACY_REQUEST: { + expireRequest((NetworkCapabilities)message.obj, message.arg1); + break; + } } } @@ -1954,8 +2142,9 @@ public class ConnectivityManager { private final static int LISTEN = 1; private final static int REQUEST = 2; - private NetworkRequest somethingForNetwork(NetworkCapabilities need, - NetworkCallbackListener networkCallbackListener, int timeoutSec, int action) { + private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, + NetworkCallbackListener networkCallbackListener, int timeoutSec, int action, + boolean legacy) { NetworkRequest networkRequest = null; if (networkCallbackListener == null) { throw new IllegalArgumentException("null NetworkCallbackListener"); @@ -1968,7 +2157,7 @@ public class ConnectivityManager { new Binder()); } else { networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler), - timeoutSec, new Binder()); + timeoutSec, new Binder(), legacy); } if (networkRequest != null) { synchronized(sNetworkCallbackListener) { @@ -1998,7 +2187,7 @@ public class ConnectivityManager { */ public NetworkRequest requestNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener) { - return somethingForNetwork(need, networkCallbackListener, 0, REQUEST); + return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, false); } /** @@ -2021,7 +2210,7 @@ public class ConnectivityManager { */ public NetworkRequest requestNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener, int timeoutSec) { - return somethingForNetwork(need, networkCallbackListener, timeoutSec, REQUEST); + return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, false); } /** @@ -2099,7 +2288,7 @@ public class ConnectivityManager { */ public NetworkRequest listenForNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener) { - return somethingForNetwork(need, networkCallbackListener, 0, LISTEN); + return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, false); } /** diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index baec36ad48..b67ae88c88 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -158,7 +158,7 @@ interface IConnectivityManager in NetworkCapabilities nc, int score); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, int timeoutSec, in IBinder binder); + in Messenger messenger, int timeoutSec, in IBinder binder, boolean legacy); NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, in PendingIntent operation); @@ -170,4 +170,6 @@ interface IConnectivityManager in PendingIntent operation); void releaseNetworkRequest(in NetworkRequest networkRequest); + + int getRestoreDefaultNetworkDelay(int networkType); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1e21e1cc51..a37ddd73b3 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2824,7 +2824,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private int getRestoreDefaultNetworkDelay(int networkType) { + @Override + public int getRestoreDefaultNetworkDelay(int networkType) { String restoreDefaultNetworkDelayStr = SystemProperties.get( NETWORK_RESTORE_DELAY_PROP_NAME); if(restoreDefaultNetworkDelayStr != null && @@ -3118,6 +3119,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (Exception e) { loge("Exception removing network: " + e); } + // TODO - if we move the logic to the network agent (have them disconnect + // because they lost all their requests or because their score isn't good) + // then they would disconnect organically, report their new state and then + // disconnect the channel. + if (nai.networkInfo.isConnected()) { + nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, + null, null); + } notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST); nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); mNetworkAgentInfos.remove(msg.replyTo); @@ -3184,7 +3193,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (bestNetwork != null) { if (VDBG) log("using " + bestNetwork.name()); - bestNetwork.networkRequests.put(nri.request.requestId, nri.request); + bestNetwork.addRequest(nri.request); notifyNetworkCallback(bestNetwork, nri); score = bestNetwork.currentScore; } @@ -3192,7 +3201,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) { if (DBG) log("sending new NetworkRequest to factories"); for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, + 0, nri.request); } } } @@ -5260,7 +5270,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, - Messenger messenger, int timeoutSec, IBinder binder) { + Messenger messenger, int timeoutSec, IBinder binder, boolean legacy) { if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { enforceConnectivityInternalPermission(); @@ -5272,7 +5282,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities), false, nextNetworkRequestId()); + networkCapabilities), legacy, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); @@ -5373,7 +5383,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(), new NetworkInfo(networkInfo), new LinkProperties(linkProperties), new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler); - + if (VDBG) log("registerNetworkAgent " + nai); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai)); } @@ -5420,7 +5430,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mClat.stopClat(); } // If the link requires clat to be running, then start the daemon now. - if (newLp != null && na.networkInfo.isConnected()) { + if (na.networkInfo.isConnected()) { mClat.startClat(na); } else { mClat.stopClat(); @@ -5632,7 +5642,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (VDBG) log(" accepting network in place of null"); } mNetworkForRequestId.put(nri.request.requestId, newNetwork); - newNetwork.networkRequests.put(nri.request.requestId, nri.request); + newNetwork.addRequest(nri.request); keep = true; // TODO - this could get expensive if we have alot of requests for this // network. Think about if there is a way to reduce this. Push @@ -5777,15 +5787,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) { if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name()); - boolean needsBroadcasts = false; for (int i = 0; i < networkAgent.networkRequests.size(); i++) { NetworkRequest nr = networkAgent.networkRequests.valueAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); if (VDBG) log(" sending notification for " + nr); - if (nr.needsBroadcasts) needsBroadcasts = true; callCallbackForRequest(nri, networkAgent, notifyType); } - if (needsBroadcasts) { + if (networkAgent.needsBroadcasts) { if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) { sendConnectedBroadcastDelayed(networkAgent.networkInfo, getConnectivityChangeDelay()); diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 8102591ea9..e9f968377f 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -45,6 +45,17 @@ public class NetworkAgentInfo { public int currentScore; public final NetworkMonitor networkMonitor; + /** + * Indicates we need to send CONNECTIVITY_ACTION broadcasts for this network. + * For example the built-in default network request and any requsts coming from + * the deprecated startUsingNetworkFeature API will have this set. Networks + * responding to the new requestNetwork API will rely on point to point callbacks. + * + * Gets set if any legacy requests get affiliated with this network and + * stays set for life so we send disconnected bcasts to match the connected, + * even if the legacy request has moved on. + */ + public boolean needsBroadcasts = false; // The list of NetworkRequests being satisfied by this Network. public final SparseArray networkRequests = new SparseArray(); @@ -66,6 +77,12 @@ public class NetworkAgentInfo { networkMonitor = new NetworkMonitor(context, handler, this); } + public void addRequest(NetworkRequest networkRequest) { + if (networkRequest.needsBroadcasts) needsBroadcasts = true; + + networkRequests.put(networkRequest.requestId, networkRequest); + } + public String toString() { return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" + network + "} lp{" + From 0c150c0082402f203a63e15b8f1f8183b7ab4b79 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Wed, 21 May 2014 20:04:36 -0700 Subject: [PATCH 266/296] Move dis/enable of mobile data to Telephony ConnectivityService doesn't do this anymore. bug:15077247 Change-Id: I3208c91b2c0369b594987f39ca29da7478435513 (cherry picked from commit 53013c87496980b534e447e717a32698fbd4bca0) --- .../java/android/net/ConnectivityManager.java | 38 ++++++----------- .../android/net/IConnectivityManager.aidl | 3 -- .../android/server/ConnectivityService.java | 41 ------------------- 3 files changed, 12 insertions(+), 70 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 80a9598ada..2f2aba3286 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -35,15 +35,17 @@ import android.os.Messenger; import android.os.RemoteException; import android.os.ServiceManager; import android.provider.Settings; +import android.telephony.TelephonyManager; import android.util.ArrayMap; import android.util.Log; +import com.android.internal.telephony.ITelephony; +import com.android.internal.util.Protocol; + import java.net.InetAddress; import java.util.concurrent.atomic.AtomicInteger; import java.util.HashMap; -import com.android.internal.util.Protocol; - /** * Class that answers queries about the state of network connectivity. It also * notifies applications when network connectivity changes. Get an instance @@ -940,34 +942,18 @@ public class ConnectivityManager { } /** - * Gets the value of the setting for enabling Mobile data. - * - * @return Whether mobile data is enabled. - * - *

          This method requires the call to hold the permission - * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * @hide + * @deprecated Talk to TelephonyManager directly */ public boolean getMobileDataEnabled() { - try { - return mService.getMobileDataEnabled(); - } catch (RemoteException e) { - return true; - } - } - - /** - * Sets the persisted value for enabling/disabling Mobile data. - * - * @param enabled Whether the user wants the mobile data connection used - * or not. - * @hide - */ - public void setMobileDataEnabled(boolean enabled) { - try { - mService.setMobileDataEnabled(enabled); - } catch (RemoteException e) { + IBinder b = ServiceManager.getService(Context.TELEPHONY_SERVICE); + if (b != null) { + try { + ITelephony it = ITelephony.Stub.asInterface(b); + return it.getDataEnabled(); + } catch (RemoteException e) { } } + return false; } /** diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index d97b1e95bd..baec36ad48 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -74,9 +74,6 @@ interface IConnectivityManager boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName); - boolean getMobileDataEnabled(); - void setMobileDataEnabled(boolean enabled); - /** Policy control over specific {@link NetworkStateTracker}. */ void setPolicyDataEnable(int networkType, boolean enabled); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7ecf248291..1e21e1cc51 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -342,12 +342,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private static final int EVENT_INET_CONDITION_HOLD_END = 5; - /** - * used internally to set enable/disable cellular data - * arg1 = ENBALED or DISABLED - */ - private static final int EVENT_SET_MOBILE_DATA = 7; - /** * used internally to clear a wakelock when transitioning * from one net to another @@ -1822,20 +1816,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { return true; } - /** - * @see ConnectivityManager#getMobileDataEnabled() - */ - public boolean getMobileDataEnabled() { - // TODO: This detail should probably be in DataConnectionTracker's - // which is where we store the value and maybe make this - // asynchronous. - enforceAccessPermission(); - boolean retVal = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.MOBILE_DATA, 1) == 1; - if (VDBG) log("getMobileDataEnabled returning " + retVal); - return retVal; - } - public void setDataDependency(int networkType, boolean met) { enforceConnectivityInternalPermission(); @@ -1908,22 +1888,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } }; - /** - * @see ConnectivityManager#setMobileDataEnabled(boolean) - */ - public void setMobileDataEnabled(boolean enabled) { - enforceChangePermission(); - if (DBG) log("setMobileDataEnabled(" + enabled + ")"); - - mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA, - (enabled ? ENABLED : DISABLED), 0)); - } - - private void handleSetMobileData(boolean enabled) { - // TODO - handle this - probably generalize passing in a transport type and send to the - // factories? - } - @Override public void setPolicyDataEnable(int networkType, boolean enabled) { // only someone like NPMS should only be calling us @@ -3315,11 +3279,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { handleInetConditionHoldEnd(netType, sequence); break; } - case EVENT_SET_MOBILE_DATA: { - boolean enabled = (msg.arg1 == ENABLED); - handleSetMobileData(enabled); - break; - } case EVENT_APPLY_GLOBAL_HTTP_PROXY: { handleDeprecatedGlobalHttpProxy(); break; From 0640cdd9fa94133e19c9cd18632338ef6908cd49 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 24 May 2014 02:25:55 +0900 Subject: [PATCH 267/296] Support disconnecting while trying to connect. Currently, once a NetworkAgent has decided to connect, there's no way to disconnect without first connecting and having ConnectivityService tear down the connection. This is suboptimal because it causes the transport to keep retrying even if it knows that it will not be able to connect. Instead, allow the transport to abort a connection request that's in progress, as long as the agent is not yet registered with ConnectivityService. Also add locking to evalScores. evalScores should already have been taking a lock, because it accesses member variables that are also accessed by the send*methods. Bug: 15295359 Change-Id: I913c341bdfc50be9c23b632399f53168e754c1c0 --- core/java/android/net/NetworkAgent.java | 46 ++++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index c2b06a297f..1c18ba5640 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -257,31 +257,43 @@ public abstract class NetworkAgent extends Handler { } /** - * called to go through our list of requests and see if we're - * good enough to try connecting. + * Called to go through our list of requests and see if we're + * good enough to try connecting, or if we have gotten worse and + * need to disconnect. * - * Only does connects - we disconnect when requested via + * Once we are registered, does nothing: we disconnect when requested via * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection * between modules (bearer or ConnectivityService dies) or more commonly * when the NetworkInfo reports to ConnectivityService it is disconnected. */ private void evalScores() { - if (mConnectionRequested) { - if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size()); - // already trying - return; - } - if (VDBG) log("evalScores!"); - for (int i=0; i < mNetworkRequests.size(); i++) { - int score = mNetworkRequests.valueAt(i).score; - if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore); - if (score < mNetworkScore) { - // have a request that has a lower scored network servicing it - // (or no network) than we could provide, so lets connect! - mConnectionRequested = true; - connect(); + synchronized(mLockObj) { + if (mRegistered) { + if (VDBG) log("evalScores - already connected - size=" + mNetworkRequests.size()); + // already trying return; } + if (VDBG) log("evalScores!"); + for (int i=0; i < mNetworkRequests.size(); i++) { + int score = mNetworkRequests.valueAt(i).score; + if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore); + if (score < mNetworkScore) { + // have a request that has a lower scored network servicing it + // (or no network) than we could provide, so let's connect! + mConnectionRequested = true; + connect(); + return; + } + } + // Our score is not high enough to satisfy any current request. + // This can happen if our score goes down after a connection is + // requested but before we actually connect. In this case, disconnect + // rather than continue trying - there's no point connecting if we know + // we'll just be torn down as soon as we do. + if (mConnectionRequested) { + mConnectionRequested = false; + disconnect(); + } } } From 892331dc0852131f29715b7ae91308c43325e2ee Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Sat, 24 May 2014 02:25:55 +0900 Subject: [PATCH 268/296] DO NOT MERGE - Support disconnecting while trying to connect. Currently, once a NetworkAgent has decided to connect, there's no way to disconnect without first connecting and having ConnectivityService tear down the connection. This is suboptimal because it causes the transport to keep retrying even if it knows that it will not be able to connect. Instead, allow the transport to abort a connection request that's in progress, as long as the agent is not yet registered with ConnectivityService. Also add locking to evalScores. evalScores should already have been taking a lock, because it accesses member variables that are also accessed by the send*methods. Bug: 15295359 Change-Id: I913c341bdfc50be9c23b632399f53168e754c1c0 (cherry picked from commit 081e99c3ac341734467b65458f94adc160f50d6c) --- core/java/android/net/NetworkAgent.java | 46 ++++++++++++++++--------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index c2b06a297f..1c18ba5640 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -257,31 +257,43 @@ public abstract class NetworkAgent extends Handler { } /** - * called to go through our list of requests and see if we're - * good enough to try connecting. + * Called to go through our list of requests and see if we're + * good enough to try connecting, or if we have gotten worse and + * need to disconnect. * - * Only does connects - we disconnect when requested via + * Once we are registered, does nothing: we disconnect when requested via * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection * between modules (bearer or ConnectivityService dies) or more commonly * when the NetworkInfo reports to ConnectivityService it is disconnected. */ private void evalScores() { - if (mConnectionRequested) { - if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size()); - // already trying - return; - } - if (VDBG) log("evalScores!"); - for (int i=0; i < mNetworkRequests.size(); i++) { - int score = mNetworkRequests.valueAt(i).score; - if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore); - if (score < mNetworkScore) { - // have a request that has a lower scored network servicing it - // (or no network) than we could provide, so lets connect! - mConnectionRequested = true; - connect(); + synchronized(mLockObj) { + if (mRegistered) { + if (VDBG) log("evalScores - already connected - size=" + mNetworkRequests.size()); + // already trying return; } + if (VDBG) log("evalScores!"); + for (int i=0; i < mNetworkRequests.size(); i++) { + int score = mNetworkRequests.valueAt(i).score; + if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore); + if (score < mNetworkScore) { + // have a request that has a lower scored network servicing it + // (or no network) than we could provide, so let's connect! + mConnectionRequested = true; + connect(); + return; + } + } + // Our score is not high enough to satisfy any current request. + // This can happen if our score goes down after a connection is + // requested but before we actually connect. In this case, disconnect + // rather than continue trying - there's no point connecting if we know + // we'll just be torn down as soon as we do. + if (mConnectionRequested) { + mConnectionRequested = false; + disconnect(); + } } } From f28fd3d850bccc06109290047171e75f6b7756e2 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 29 May 2014 14:05:41 +0900 Subject: [PATCH 269/296] Don't break things if a network goes back to CONNECTED. Currently, if a network goes from CONNECTED to some other "live" state (e.g., CONNECTING, because it's VERIFYING_POOR_LINK) and back, ConnectivityService treats it as if a new network had connected. This causes it to attempt to create the network (which fails, since a network with that netid already exists), to trigger verification, and if the verification succeeds, to tear down the network because the request it's satisfying is already satisfied by the network itself. Instead, if creating the network fails, assume it's because the network had already been created, and bail out. Also, when validation completes, ignore NetworkRequests that were being served by the same NetworkAgent as before. Bug: 15244052 Change-Id: Ifd73558e5be452d9ef88c64cca429d5f302bf354 --- .../android/server/ConnectivityService.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1e21e1cc51..5527528fd2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5606,16 +5606,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean isNewDefault = false; if (DBG) log("handleConnectionValidated for "+newNetwork.name()); // check if any NetworkRequest wants this NetworkAgent - // first check if it satisfies the NetworkCapabilities ArrayList affectedNetworks = new ArrayList(); if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities); for (NetworkRequestInfo nri : mNetworkRequests.values()) { + NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); + if (newNetwork == currentNetwork) { + if (VDBG) log("Network " + newNetwork.name() + " was already satisfying" + + " request " + nri.request.requestId + ". No change."); + keep = true; + continue; + } + + // check if it satisfies the NetworkCapabilities if (VDBG) log(" checking if request is satisfied: " + nri.request); if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities( newNetwork.networkCapabilities)) { // next check if it's better than any current network we're using for // this request - NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); if (VDBG) { log("currentScore = " + (currentNetwork != null ? currentNetwork.currentScore : 0) + @@ -5744,12 +5751,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (state == NetworkInfo.State.CONNECTED) { - // TODO - check if we want it (optimization) try { + // This is likely caused by the fact that this network already + // exists. An example is when a network goes from CONNECTED to + // CONNECTING and back (like wifi on DHCP renew). + // TODO: keep track of which networks we've created, or ask netd + // to tell us whether we've already created this network or not. mNetd.createNetwork(networkAgent.network.netId); } catch (Exception e) { - loge("Error creating Network " + networkAgent.network.netId); + loge("Error creating network " + networkAgent.network.netId + ": " + + e.getMessage()); + return; } + updateLinkProperties(networkAgent, null); notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); From 47f597dfbf0a98ee5489fa06d508503c9bb49ef9 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Thu, 29 May 2014 14:05:41 +0900 Subject: [PATCH 270/296] Don't break things if a network goes back to CONNECTED. Currently, if a network goes from CONNECTED to some other "live" state (e.g., CONNECTING, because it's VERIFYING_POOR_LINK) and back, ConnectivityService treats it as if a new network had connected. This causes it to attempt to create the network (which fails, since a network with that netid already exists), to trigger verification, and if the verification succeeds, to tear down the network because the request it's satisfying is already satisfied by the network itself. Instead, if creating the network fails, assume it's because the network had already been created, and bail out. Also, when validation completes, ignore NetworkRequests that were being served by the same NetworkAgent as before. Bug: 15244052 (cherry picked from commit cfff026ec47afc7e31f60f80e3deea7f4e2f9be5) Change-Id: I52c2220e8f1d98fca765880be3040593e92722ed --- .../android/server/ConnectivityService.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1e21e1cc51..5527528fd2 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -5606,16 +5606,23 @@ public class ConnectivityService extends IConnectivityManager.Stub { boolean isNewDefault = false; if (DBG) log("handleConnectionValidated for "+newNetwork.name()); // check if any NetworkRequest wants this NetworkAgent - // first check if it satisfies the NetworkCapabilities ArrayList affectedNetworks = new ArrayList(); if (VDBG) log(" new Network has: " + newNetwork.networkCapabilities); for (NetworkRequestInfo nri : mNetworkRequests.values()) { + NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); + if (newNetwork == currentNetwork) { + if (VDBG) log("Network " + newNetwork.name() + " was already satisfying" + + " request " + nri.request.requestId + ". No change."); + keep = true; + continue; + } + + // check if it satisfies the NetworkCapabilities if (VDBG) log(" checking if request is satisfied: " + nri.request); if (nri.request.networkCapabilities.satisfiedByNetworkCapabilities( newNetwork.networkCapabilities)) { // next check if it's better than any current network we're using for // this request - NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId); if (VDBG) { log("currentScore = " + (currentNetwork != null ? currentNetwork.currentScore : 0) + @@ -5744,12 +5751,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (state == NetworkInfo.State.CONNECTED) { - // TODO - check if we want it (optimization) try { + // This is likely caused by the fact that this network already + // exists. An example is when a network goes from CONNECTED to + // CONNECTING and back (like wifi on DHCP renew). + // TODO: keep track of which networks we've created, or ask netd + // to tell us whether we've already created this network or not. mNetd.createNetwork(networkAgent.network.netId); } catch (Exception e) { - loge("Error creating Network " + networkAgent.network.netId); + loge("Error creating network " + networkAgent.network.netId + ": " + + e.getMessage()); + return; } + updateLinkProperties(networkAgent, null); notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); From 80504dbd7469b6c67dfe9ba0eb61943d81096f89 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 20 May 2014 11:25:35 -0400 Subject: [PATCH 271/296] Implement bind-to-network functionality of android.net.Network. This is implemented by calling through to netd_client. Included are functions to bind-to-network-for-process strictly for DNS to facilitate startUsingNetworkFeature() reimplementation. bug: 13885501 Change-Id: Ib22c7d02ea81d251bdfeeb0f64a47ce32eefcb1b (cherry picked from commit dbf76f898f1f57eb74722358087c926d2f529bda) --- core/java/android/net/Network.java | 89 ++++++++++++++++++++++++- core/java/android/net/NetworkUtils.java | 44 ++++++++++++ core/jni/android_net_NetUtils.cpp | 38 +++++++++++ 3 files changed, 169 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index e0d69e372c..e489e052d9 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -16,10 +16,13 @@ package android.net; +import android.net.NetworkUtils; import android.os.Parcelable; import android.os.Parcel; +import java.io.IOException; import java.net.InetAddress; +import java.net.InetSocketAddress; import java.net.Socket; import java.net.UnknownHostException; import javax.net.SocketFactory; @@ -38,6 +41,8 @@ public class Network implements Parcelable { */ public final int netId; + private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; + /** * @hide */ @@ -78,6 +83,59 @@ public class Network implements Parcelable { return InetAddress.getByNameOnNet(host, netId); } + /** + * A {@code SocketFactory} that produces {@code Socket}'s bound to this network. + */ + private class NetworkBoundSocketFactory extends SocketFactory { + private final int mNetId; + + public NetworkBoundSocketFactory(int netId) { + super(); + mNetId = netId; + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + Socket socket = createSocket(); + socket.bind(new InetSocketAddress(localHost, localPort)); + socket.connect(new InetSocketAddress(host, port)); + return socket; + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, + int localPort) throws IOException { + Socket socket = createSocket(); + socket.bind(new InetSocketAddress(localAddress, localPort)); + socket.connect(new InetSocketAddress(address, port)); + return socket; + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + Socket socket = createSocket(); + socket.connect(new InetSocketAddress(host, port)); + return socket; + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + Socket socket = createSocket(); + socket.connect(new InetSocketAddress(host, port)); + return socket; + } + + @Override + public Socket createSocket() throws IOException { + Socket socket = new Socket(); + // Query a property of the underlying socket to ensure the underlying + // socket exists so a file descriptor is available to bind to a network. + socket.getReuseAddress(); + NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), mNetId); + return socket; + } + } + /** * Returns a {@link SocketFactory} bound to this network. Any {@link Socket} created by * this factory will have its traffic sent over this {@code Network}. Note that if this @@ -88,7 +146,10 @@ public class Network implements Parcelable { * {@code Network}. */ public SocketFactory socketFactory() { - return null; + if (mNetworkBoundSocketFactory == null) { + mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); + } + return mNetworkBoundSocketFactory; } /** @@ -99,6 +160,29 @@ public class Network implements Parcelable { * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}. */ public void bindProcess() { + NetworkUtils.bindProcessToNetwork(netId); + } + + /** + * Binds host resolutions performed by this process to this network. {@link #bindProcess} + * takes precedence over this setting. + * + * @hide + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + public void bindProcessForHostResolution() { + NetworkUtils.bindProcessToNetworkForHostResolution(netId); + } + + /** + * Clears any process specific {@link Network} binding for host resolution. This does + * not clear bindings enacted via {@link #bindProcess}. + * + * @hide + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + public void unbindProcessForHostResolution() { + NetworkUtils.unbindProcessToNetworkForHostResolution(); } /** @@ -107,7 +191,7 @@ public class Network implements Parcelable { * @return {@code Network} to which this process is bound. */ public static Network getProcessBoundNetwork() { - return null; + return new Network(NetworkUtils.getNetworkBoundToProcess()); } /** @@ -115,6 +199,7 @@ public class Network implements Parcelable { * {@link Network#bindProcess}. */ public static void unbindProcess() { + NetworkUtils.unbindProcessToNetwork(); } // implement the Parcelable interface diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index b24d3969f7..edb32866d3 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -108,6 +108,50 @@ public class NetworkUtils { */ public native static void markSocket(int socketfd, int mark); + /** + * Binds the current process to the network designated by {@code netId}. All sockets created + * in the future (and not explicitly bound via a bound {@link SocketFactory} (see + * {@link Network#socketFactory}) will be bound to this network. Note that if this + * {@code Network} ever disconnects all sockets created in this way will cease to work. This + * is by design so an application doesn't accidentally use sockets it thinks are still bound to + * a particular {@code Network}. + */ + public native static void bindProcessToNetwork(int netId); + + /** + * Clear any process specific {@code Network} binding. This reverts a call to + * {@link #bindProcessToNetwork}. + */ + public native static void unbindProcessToNetwork(); + + /** + * Return the netId last passed to {@link #bindProcessToNetwork}, or NETID_UNSET if + * {@link #unbindProcessToNetwork} has been called since {@link #bindProcessToNetwork}. + */ + public native static int getNetworkBoundToProcess(); + + /** + * Binds host resolutions performed by this process to the network designated by {@code netId}. + * {@link #bindProcessToNetwork} takes precedence over this setting. + * + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + public native static void bindProcessToNetworkForHostResolution(int netId); + + /** + * Clears any process specific {@link Network} binding for host resolution. This does + * not clear bindings enacted via {@link #bindProcessToNetwork}. + * + * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). + */ + public native static void unbindProcessToNetworkForHostResolution(); + + /** + * Explicitly binds {@code socketfd} to the network designated by {@code netId}. This + * overrides any binding via {@link #bindProcessToNetwork}. + */ + public native static void bindSocketToNetwork(int socketfd, int netId); + /** * Convert a IPv4 address from an integer to an InetAddress. * @param hostAddress an int corresponding to the IPv4 address in network byte order diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 6d23c32b33..bc5e1b3237 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -18,6 +18,8 @@ #include "jni.h" #include "JNIHelp.h" +#include "NetdClient.h" +#include "resolv_netid.h" #include #include #include @@ -250,6 +252,36 @@ static void android_net_utils_markSocket(JNIEnv *env, jobject thiz, jint socket, } } +static void android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId) +{ + setNetworkForProcess(netId); +} + +static void android_net_utils_unbindProcessToNetwork(JNIEnv *env, jobject thiz) +{ + setNetworkForProcess(NETID_UNSET); +} + +static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz) +{ + return getNetworkForProcess(); +} + +static void android_net_utils_bindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz, jint netId) +{ + setNetworkForResolv(netId); +} + +static void android_net_utils_unbindProcessToNetworkForHostResolution(JNIEnv *env, jobject thiz) +{ + setNetworkForResolv(NETID_UNSET); +} + +static void android_net_utils_bindSocketToNetwork(JNIEnv *env, jobject thiz, jint socket, jint netId) +{ + setNetworkForSocket(netId, socket); +} + // ---------------------------------------------------------------------------- /* @@ -267,6 +299,12 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError }, { "markSocket", "(II)V", (void*) android_net_utils_markSocket }, + { "bindProcessToNetwork", "(I)V", (void*) android_net_utils_bindProcessToNetwork }, + { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess }, + { "unbindProcessToNetwork", "()V", (void*) android_net_utils_unbindProcessToNetwork }, + { "bindProcessToNetworkForHostResolution", "(I)V", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, + { "unbindProcessToNetworkForHostResolution", "()V", (void*) android_net_utils_unbindProcessToNetworkForHostResolution }, + { "bindSocketToNetwork", "(II)V", (void*) android_net_utils_bindSocketToNetwork }, }; int register_android_net_NetworkUtils(JNIEnv* env) From c3c5babcb1e798abb4f7ee32173b2753b346c7e9 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Tue, 27 May 2014 10:19:39 -0400 Subject: [PATCH 272/296] Adjust Network's SocketFactory to restrict host name resolution to that Network bug: 13885501 Change-Id: Iab9a5a2e060fe261f4be9ba974c1a55fb6b9c98b (cherry picked from commit 92064edf55ee11967d9cc7529125236ee8e469b2) --- core/java/android/net/Network.java | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index e489e052d9..64516e62d1 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -94,11 +94,26 @@ public class Network implements Parcelable { mNetId = netId; } + private void connectToHost(Socket socket, String host, int port) throws IOException { + // Lookup addresses only on this Network. + InetAddress[] hostAddresses = getAllByName(host); + // Try all but last address ignoring exceptions. + for (int i = 0; i < hostAddresses.length - 1; i++) { + try { + socket.connect(new InetSocketAddress(hostAddresses[i], port)); + return; + } catch (IOException e) { + } + } + // Try last address. Do throw exceptions. + socket.connect(new InetSocketAddress(hostAddresses[hostAddresses.length - 1], port)); + } + @Override public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { Socket socket = createSocket(); socket.bind(new InetSocketAddress(localHost, localPort)); - socket.connect(new InetSocketAddress(host, port)); + connectToHost(socket, host, port); return socket; } @@ -121,7 +136,7 @@ public class Network implements Parcelable { @Override public Socket createSocket(String host, int port) throws IOException { Socket socket = createSocket(); - socket.connect(new InetSocketAddress(host, port)); + connectToHost(socket, host, port); return socket; } From 1e459f2365cf0b836bff95e454be314d473bb717 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Thu, 22 May 2014 16:30:48 -0700 Subject: [PATCH 273/296] Support legacy routes added by apps via ensureRouteToHost(). Change-Id: I0ee1ca89fdc859d75a89021ca8c1902811b1e4a9 --- .../android/server/ConnectivityService.java | 59 ++++++++++++------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5527528fd2..d7a19add8f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -514,6 +514,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // sequence number of NetworkRequests private int mNextNetworkRequestId = 1; + private static final int UID_UNUSED = -1; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -1673,10 +1675,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } return false; } + final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { LinkProperties lp = tracker.getLinkProperties(); - boolean ok = addRouteToAddress(lp, addr, exempt, tracker.getNetwork().netId); + boolean ok = modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, + tracker.getNetwork().netId, uid); if (DBG) log("requestRouteToHostAddress ok=" + ok); return ok; } finally { @@ -1686,24 +1690,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, boolean exempt, int netId) { - return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt, netId); + return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt, netId, false, UID_UNUSED); } private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, int netId) { - return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT, netId); - } - - private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt, - int netId) { - return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, netId); - } - - private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr, int netId) { - return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT, netId); + return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT, netId, false, UID_UNUSED); } private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, - boolean toDefaultTable, boolean exempt, int netId) { + boolean toDefaultTable, boolean exempt, int netId, int uid) { RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr); if (bestRoute == null) { bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName()); @@ -1718,11 +1713,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface); } } - return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt, netId); + return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt, netId, true, uid); } + /* + * TODO: Clean all this stuff up. Once we have UID-based routing, stuff will break due to + * incorrect tracking of mAddedRoutes, so a cleanup becomes necessary and urgent. But at + * the same time, there'll be no more need to track mAddedRoutes or mExemptAddresses, + * or even have the concept of an exempt address, or do things like "selectBestRoute", or + * determine "default" vs "secondary" table, etc., so the cleanup becomes possible. + */ private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd, - boolean toDefaultTable, boolean exempt, int netId) { + boolean toDefaultTable, boolean exempt, int netId, boolean legacy, int uid) { if ((lp == null) || (r == null)) { if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r); return false; @@ -1751,7 +1753,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute.getGateway(), ifaceName); } - modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId); + modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId, + legacy, uid); } } if (doAdd) { @@ -1761,7 +1764,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { synchronized (mRoutesLock) { // only track default table - only one apps can effect mAddedRoutes.add(r); - mNetd.addRoute(netId, r); + if (legacy) { + mNetd.addLegacyRouteForNetId(netId, r, uid); + } else { + mNetd.addRoute(netId, r); + } if (exempt) { LinkAddress dest = r.getDestination(); if (!mExemptAddresses.contains(dest)) { @@ -1771,7 +1778,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } else { - mNetd.addRoute(netId, r); + if (legacy) { + mNetd.addLegacyRouteForNetId(netId, r, uid); + } else { + mNetd.addRoute(netId, r); + } } } catch (Exception e) { // never crash - catch them all @@ -1787,7 +1798,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mAddedRoutes.contains(r) == false) { if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { - mNetd.removeRoute(netId, r); + if (legacy) { + mNetd.removeLegacyRouteForNetId(netId, r, uid); + } else { + mNetd.removeRoute(netId, r); + } LinkAddress dest = r.getDestination(); if (mExemptAddresses.contains(dest)) { mNetd.clearHostExemption(dest); @@ -1805,7 +1820,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { - mNetd.removeRoute(netId, r); + if (legacy) { + mNetd.removeLegacyRouteForNetId(netId, r, uid); + } else { + mNetd.removeRoute(netId, r); + } } catch (Exception e) { // never crash - catch them all if (VDBG) loge("Exception trying to remove a route: " + e); From 9052fa125ae1f0605dbb3ea20c4523a326f3cba3 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Thu, 22 May 2014 16:30:48 -0700 Subject: [PATCH 274/296] Support legacy routes added by apps via ensureRouteToHost(). Change-Id: I0ee1ca89fdc859d75a89021ca8c1902811b1e4a9 (cherry picked from commit fb17b32550de624b7f476b70b7a2fc77f31dde7d) --- .../android/server/ConnectivityService.java | 59 ++++++++++++------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 5527528fd2..d7a19add8f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -514,6 +514,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { // sequence number of NetworkRequests private int mNextNetworkRequestId = 1; + private static final int UID_UNUSED = -1; + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -1673,10 +1675,12 @@ public class ConnectivityService extends IConnectivityManager.Stub { } return false; } + final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { LinkProperties lp = tracker.getLinkProperties(); - boolean ok = addRouteToAddress(lp, addr, exempt, tracker.getNetwork().netId); + boolean ok = modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, + tracker.getNetwork().netId, uid); if (DBG) log("requestRouteToHostAddress ok=" + ok); return ok; } finally { @@ -1686,24 +1690,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, boolean exempt, int netId) { - return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt, netId); + return modifyRoute(p, r, 0, ADD, toDefaultTable, exempt, netId, false, UID_UNUSED); } private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, int netId) { - return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT, netId); - } - - private boolean addRouteToAddress(LinkProperties lp, InetAddress addr, boolean exempt, - int netId) { - return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, netId); - } - - private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr, int netId) { - return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE, UNEXEMPT, netId); + return modifyRoute(p, r, 0, REMOVE, toDefaultTable, UNEXEMPT, netId, false, UID_UNUSED); } private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, - boolean toDefaultTable, boolean exempt, int netId) { + boolean toDefaultTable, boolean exempt, int netId, int uid) { RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr); if (bestRoute == null) { bestRoute = RouteInfo.makeHostRoute(addr, lp.getInterfaceName()); @@ -1718,11 +1713,18 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface); } } - return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt, netId); + return modifyRoute(lp, bestRoute, 0, doAdd, toDefaultTable, exempt, netId, true, uid); } + /* + * TODO: Clean all this stuff up. Once we have UID-based routing, stuff will break due to + * incorrect tracking of mAddedRoutes, so a cleanup becomes necessary and urgent. But at + * the same time, there'll be no more need to track mAddedRoutes or mExemptAddresses, + * or even have the concept of an exempt address, or do things like "selectBestRoute", or + * determine "default" vs "secondary" table, etc., so the cleanup becomes possible. + */ private boolean modifyRoute(LinkProperties lp, RouteInfo r, int cycleCount, boolean doAdd, - boolean toDefaultTable, boolean exempt, int netId) { + boolean toDefaultTable, boolean exempt, int netId, boolean legacy, int uid) { if ((lp == null) || (r == null)) { if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r); return false; @@ -1751,7 +1753,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { bestRoute.getGateway(), ifaceName); } - modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId); + modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId, + legacy, uid); } } if (doAdd) { @@ -1761,7 +1764,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { synchronized (mRoutesLock) { // only track default table - only one apps can effect mAddedRoutes.add(r); - mNetd.addRoute(netId, r); + if (legacy) { + mNetd.addLegacyRouteForNetId(netId, r, uid); + } else { + mNetd.addRoute(netId, r); + } if (exempt) { LinkAddress dest = r.getDestination(); if (!mExemptAddresses.contains(dest)) { @@ -1771,7 +1778,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } } else { - mNetd.addRoute(netId, r); + if (legacy) { + mNetd.addLegacyRouteForNetId(netId, r, uid); + } else { + mNetd.addRoute(netId, r); + } } } catch (Exception e) { // never crash - catch them all @@ -1787,7 +1798,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (mAddedRoutes.contains(r) == false) { if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { - mNetd.removeRoute(netId, r); + if (legacy) { + mNetd.removeLegacyRouteForNetId(netId, r, uid); + } else { + mNetd.removeRoute(netId, r); + } LinkAddress dest = r.getDestination(); if (mExemptAddresses.contains(dest)) { mNetd.clearHostExemption(dest); @@ -1805,7 +1820,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { if (VDBG) log("Removing " + r + " for interface " + ifaceName); try { - mNetd.removeRoute(netId, r); + if (legacy) { + mNetd.removeLegacyRouteForNetId(netId, r, uid); + } else { + mNetd.removeRoute(netId, r); + } } catch (Exception e) { // never crash - catch them all if (VDBG) loge("Exception trying to remove a route: " + e); From 70cf11649eca8edbc03de01dca8480dd3f7f40de Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 27 May 2014 13:20:24 -0700 Subject: [PATCH 275/296] Refactor NetworkFactory. Make NetworkFactory a concrete class and divide responsibilites between it and NetworkAgent. Factory will track requests and by default give a single connect/disconnect api for ease of use. Then NetworkAgent is created and destroyed as needed with very simple logic. Change-Id: I401c14a6e5466f2fc63b04219b97ff85bb9af291 --- core/java/android/net/NetworkAgent.java | 337 ++++-------------- core/java/android/net/NetworkInfo.java | 5 +- .../android/server/ConnectivityService.java | 27 +- 3 files changed, 89 insertions(+), 280 deletions(-) diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 1c18ba5640..7e8b1f1aca 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -24,85 +24,39 @@ import android.os.Messenger; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; -import android.util.SparseArray; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; +import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; /** - * A Utility class for handling NetworkRequests. - * - * Created by bearer-specific code to handle tracking requests, scores, - * network data and handle communicating with ConnectivityService. Two - * abstract methods: connect and disconnect are used to act on the - * underlying bearer code. Connect is called when we have a NetworkRequest - * and our score is better than the current handling network's score, while - * disconnect is used when ConnectivityService requests a disconnect. + * A Utility class for handling for communicating between bearer-specific + * code and ConnectivityService. * * A bearer may have more than one NetworkAgent if it can simultaneously * support separate networks (IMS / Internet / MMS Apns on cellular, or - * perhaps connections with different SSID or P2P for Wi-Fi). The bearer - * code should pass its NetworkAgents the NetworkRequests each NetworkAgent - * can handle, demultiplexing for different network types. The bearer code - * can also filter out requests it can never handle. + * perhaps connections with different SSID or P2P for Wi-Fi). * - * Each NetworkAgent needs to be given a score and NetworkCapabilities for - * their potential network. While disconnected, the NetworkAgent will check - * each time its score changes or a NetworkRequest changes to see if - * the NetworkAgent can provide a higher scored network for a NetworkRequest - * that the NetworkAgent's NetworkCapabilties can satisfy. This condition will - * trigger a connect request via connect(). After connection, connection data - * should be given to the NetworkAgent by the bearer, including LinkProperties - * NetworkCapabilties and NetworkInfo. After that the NetworkAgent will register - * with ConnectivityService and forward the data on. * @hide */ public abstract class NetworkAgent extends Handler { - private final SparseArray mNetworkRequests = new SparseArray<>(); - private boolean mConnectionRequested = false; - - private AsyncChannel mAsyncChannel; + private volatile AsyncChannel mAsyncChannel; private final String LOG_TAG; private static final boolean DBG = true; private static final boolean VDBG = true; - // TODO - this class shouldn't cache data or it runs the risk of getting out of sync - // Make the API require each of these when any is updated so we have the data we need, - // without caching. - private LinkProperties mLinkProperties; - private NetworkInfo mNetworkInfo; - private NetworkCapabilities mNetworkCapabilities; - private int mNetworkScore; - private boolean mRegistered = false; private final Context mContext; - private AtomicBoolean mHasRequests = new AtomicBoolean(false); - - // TODO - add a name member for logging purposes. - - protected final Object mLockObj = new Object(); - + private final ArrayListmPreConnectedQueue = new ArrayList(); private static final int BASE = Protocol.BASE_NETWORK_AGENT; - /** - * Sent by self to queue up a new/modified request. - * obj = NetworkRequestAndScore - */ - private static final int CMD_ADD_REQUEST = BASE + 1; - - /** - * Sent by self to queue up the removal of a request. - * obj = NetworkRequest - */ - private static final int CMD_REMOVE_REQUEST = BASE + 2; - /** * Sent by ConnectivityService to the NetworkAgent to inform it of * suspected connectivity problems on its network. The NetworkAgent * should take steps to verify and correct connectivity. */ - public static final int CMD_SUSPECT_BAD = BASE + 3; + public static final int CMD_SUSPECT_BAD = BASE; /** * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to @@ -110,84 +64,63 @@ public abstract class NetworkAgent extends Handler { * Sent when the NetworkInfo changes, mainly due to change of state. * obj = NetworkInfo */ - public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 4; + public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1; /** * Sent by the NetworkAgent to ConnectivityService to pass the current * NetworkCapabilties. * obj = NetworkCapabilities */ - public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 5; + public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2; /** * Sent by the NetworkAgent to ConnectivityService to pass the current * NetworkProperties. * obj = NetworkProperties */ - public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 6; + public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3; /** * Sent by the NetworkAgent to ConnectivityService to pass the current * network score. - * arg1 = network score int + * obj = network score Integer */ - public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 7; + public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4; - public NetworkAgent(Looper looper, Context context, String logTag) { + public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, + NetworkCapabilities nc, LinkProperties lp, int score) { super(looper); LOG_TAG = logTag; mContext = context; - } - - /** - * When conditions are right, register with ConnectivityService. - * Connditions include having a well defined network and a request - * that justifies it. The NetworkAgent will remain registered until - * disconnected. - * TODO - this should have all data passed in rather than caching - */ - private void registerSelf() { - synchronized(mLockObj) { - if (!mRegistered && mConnectionRequested && - mNetworkInfo != null && mNetworkInfo.isConnected() && - mNetworkCapabilities != null && - mLinkProperties != null && - mNetworkScore != 0) { - if (DBG) log("Registering NetworkAgent"); - mRegistered = true; - ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(mNetworkInfo), - new LinkProperties(mLinkProperties), - new NetworkCapabilities(mNetworkCapabilities), mNetworkScore); - } else if (DBG && !mRegistered) { - String err = "Not registering due to "; - if (mConnectionRequested == false) err += "no Connect requested "; - if (mNetworkInfo == null) err += "null NetworkInfo "; - if (mNetworkInfo != null && mNetworkInfo.isConnected() == false) { - err += "NetworkInfo disconnected "; - } - if (mLinkProperties == null) err += "null LinkProperties "; - if (mNetworkCapabilities == null) err += "null NetworkCapabilities "; - if (mNetworkScore == 0) err += "null NetworkScore"; - log(err); - } + if (ni == null || nc == null || lp == null) { + throw new IllegalArgumentException(); } + + if (DBG) log("Registering NetworkAgent"); + ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), + new LinkProperties(lp), new NetworkCapabilities(nc), score); } @Override public void handleMessage(Message msg) { switch (msg.what) { case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { - synchronized (mLockObj) { - if (mAsyncChannel != null) { - log("Received new connection while already connected!"); - } else { - if (DBG) log("NetworkAgent fully connected"); - mAsyncChannel = new AsyncChannel(); - mAsyncChannel.connected(null, this, msg.replyTo); - mAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, - AsyncChannel.STATUS_SUCCESSFUL); + if (mAsyncChannel != null) { + log("Received new connection while already connected!"); + } else { + if (DBG) log("NetworkAgent fully connected"); + AsyncChannel ac = new AsyncChannel(); + ac.connected(null, this, msg.replyTo); + ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, + AsyncChannel.STATUS_SUCCESSFUL); + synchronized (mPreConnectedQueue) { + mAsyncChannel = ac; + for (Message m : mPreConnectedQueue) { + ac.sendMessage(m); + } + mPreConnectedQueue.clear(); } } break; @@ -199,213 +132,69 @@ public abstract class NetworkAgent extends Handler { } case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { if (DBG) log("NetworkAgent channel lost"); - disconnect(); - clear(); + // let the client know CS is done with us. + unwanted(); + synchronized (mPreConnectedQueue) { + mAsyncChannel = null; + } break; } case CMD_SUSPECT_BAD: { log("Unhandled Message " + msg); break; } - case CMD_ADD_REQUEST: { - handleAddRequest(msg); - break; - } - case CMD_REMOVE_REQUEST: { - handleRemoveRequest(msg); - break; - } } } - private void clear() { - synchronized(mLockObj) { - mNetworkRequests.clear(); - mHasRequests.set(false); - mConnectionRequested = false; - mAsyncChannel = null; - mRegistered = false; - } - } - - private static class NetworkRequestAndScore { - NetworkRequest req; - int score; - - NetworkRequestAndScore(NetworkRequest networkRequest, int score) { - req = networkRequest; - this.score = score; - } - } - - private void handleAddRequest(Message msg) { - NetworkRequestAndScore n = (NetworkRequestAndScore)msg.obj; - // replaces old request, updating score - mNetworkRequests.put(n.req.requestId, n); - mHasRequests.set(true); - evalScores(); - } - - private void handleRemoveRequest(Message msg) { - NetworkRequest networkRequest = (NetworkRequest)msg.obj; - - if (mNetworkRequests.get(networkRequest.requestId) != null) { - mNetworkRequests.remove(networkRequest.requestId); - if (mNetworkRequests.size() == 0) mHasRequests.set(false); - evalScores(); - } - } - - /** - * Called to go through our list of requests and see if we're - * good enough to try connecting, or if we have gotten worse and - * need to disconnect. - * - * Once we are registered, does nothing: we disconnect when requested via - * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection - * between modules (bearer or ConnectivityService dies) or more commonly - * when the NetworkInfo reports to ConnectivityService it is disconnected. - */ - private void evalScores() { - synchronized(mLockObj) { - if (mRegistered) { - if (VDBG) log("evalScores - already connected - size=" + mNetworkRequests.size()); - // already trying - return; - } - if (VDBG) log("evalScores!"); - for (int i=0; i < mNetworkRequests.size(); i++) { - int score = mNetworkRequests.valueAt(i).score; - if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore); - if (score < mNetworkScore) { - // have a request that has a lower scored network servicing it - // (or no network) than we could provide, so let's connect! - mConnectionRequested = true; - connect(); - return; - } - } - // Our score is not high enough to satisfy any current request. - // This can happen if our score goes down after a connection is - // requested but before we actually connect. In this case, disconnect - // rather than continue trying - there's no point connecting if we know - // we'll just be torn down as soon as we do. - if (mConnectionRequested) { - mConnectionRequested = false; - disconnect(); + private void queueOrSendMessage(int what, Object obj) { + synchronized (mPreConnectedQueue) { + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(what, obj); + } else { + Message msg = Message.obtain(); + msg.what = what; + msg.obj = obj; + mPreConnectedQueue.add(msg); } } } - public void addNetworkRequest(NetworkRequest networkRequest, int score) { - if (DBG) log("adding NetworkRequest " + networkRequest + " with score " + score); - sendMessage(obtainMessage(CMD_ADD_REQUEST, - new NetworkRequestAndScore(networkRequest, score))); - } - - public void removeNetworkRequest(NetworkRequest networkRequest) { - if (DBG) log("removing NetworkRequest " + networkRequest); - sendMessage(obtainMessage(CMD_REMOVE_REQUEST, networkRequest)); - } - /** * Called by the bearer code when it has new LinkProperties data. - * If we're a registered NetworkAgent, this new data will get forwarded on, - * otherwise we store a copy in anticipation of registering. This call - * may also prompt registration if it causes the NetworkAgent to meet - * the conditions (fully configured, connected, satisfys a request and - * has sufficient score). */ public void sendLinkProperties(LinkProperties linkProperties) { - linkProperties = new LinkProperties(linkProperties); - synchronized(mLockObj) { - mLinkProperties = linkProperties; - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, linkProperties); - } else { - registerSelf(); - } - } + queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); } /** * Called by the bearer code when it has new NetworkInfo data. - * If we're a registered NetworkAgent, this new data will get forwarded on, - * otherwise we store a copy in anticipation of registering. This call - * may also prompt registration if it causes the NetworkAgent to meet - * the conditions (fully configured, connected, satisfys a request and - * has sufficient score). */ public void sendNetworkInfo(NetworkInfo networkInfo) { - networkInfo = new NetworkInfo(networkInfo); - synchronized(mLockObj) { - mNetworkInfo = networkInfo; - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(EVENT_NETWORK_INFO_CHANGED, networkInfo); - } else { - registerSelf(); - } - } + queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); } /** * Called by the bearer code when it has new NetworkCapabilities data. - * If we're a registered NetworkAgent, this new data will get forwarded on, - * otherwise we store a copy in anticipation of registering. This call - * may also prompt registration if it causes the NetworkAgent to meet - * the conditions (fully configured, connected, satisfys a request and - * has sufficient score). - * Note that if these capabilities make the network non-useful, - * ConnectivityServce will tear this network down. */ public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) { - networkCapabilities = new NetworkCapabilities(networkCapabilities); - synchronized(mLockObj) { - mNetworkCapabilities = networkCapabilities; - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, networkCapabilities); - } else { - registerSelf(); - } - } - } - - public NetworkCapabilities getNetworkCapabilities() { - synchronized(mLockObj) { - return new NetworkCapabilities(mNetworkCapabilities); - } + queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, + new NetworkCapabilities(networkCapabilities)); } /** * Called by the bearer code when it has a new score for this network. - * If we're a registered NetworkAgent, this new data will get forwarded on, - * otherwise we store a copy. */ - public synchronized void sendNetworkScore(int score) { - synchronized(mLockObj) { - mNetworkScore = score; - evalScores(); - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(EVENT_NETWORK_SCORE_CHANGED, mNetworkScore); - } else { - registerSelf(); - } - } + public void sendNetworkScore(int score) { + queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score)); } - public boolean hasRequests() { - return mHasRequests.get(); - } - - public boolean isConnectionRequested() { - synchronized(mLockObj) { - return mConnectionRequested; - } - } - - - abstract protected void connect(); - abstract protected void disconnect(); + /** + * Called when ConnectivityService has indicated they no longer want this network. + * The parent factory should (previously) have received indication of the change + * as well, either canceling NetworkRequests or altering their score such that this + * network won't be immediately requested again. + */ + abstract protected void unwanted(); protected void log(String s) { Log.d(LOG_TAG, "NetworkAgent: " + s); diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 9e656eecbe..ccc56e23af 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -198,7 +198,10 @@ public class NetworkInfo implements Parcelable { } } - void setSubtype(int subtype, String subtypeName) { + /** + * @hide + */ + public void setSubtype(int subtype, String subtypeName) { synchronized (this) { mSubtype = subtype; mSubtypeName = subtypeName; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1c0b7b65eb..22ecd33c4e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -38,7 +38,6 @@ import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; -import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; @@ -80,6 +79,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkFactory; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkState; @@ -2995,6 +2995,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { updateNetworkInfo(nai, info); break; } + case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("EVENT_NETWORK_SCORE_CHANGED from unknown NetworkAgent"); + break; + } + Integer score = (Integer) msg.obj; + updateNetworkScore(nai, score); + break; + } case NetworkMonitor.EVENT_NETWORK_VALIDATED: { NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; handleConnectionValidated(nai); @@ -3099,7 +3109,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (NetworkRequestInfo nri : mNetworkRequests.values()) { if (nri.isRequest == false) continue; NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, + ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, (nai != null ? nai.currentScore : 0), 0, nri.request); } } else { @@ -3220,7 +3230,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) { if (DBG) log("sending new NetworkRequest to factories"); for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, + nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, nri.request); } } @@ -3243,7 +3253,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (nri.isRequest) { for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); + nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, + nri.request); } if (affectedNetwork != null) { @@ -5565,7 +5576,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); + nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, + networkRequest); } } @@ -5802,6 +5814,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + private void updateNetworkScore(NetworkAgentInfo nai, Integer scoreInteger) { + int score = scoreInteger.intValue(); + // TODO + } + // notify only this one new request of the current state protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) { int notifyType = ConnectivityManager.CALLBACK_AVAILABLE; From 3dc73e576b0c43fb4e08bbb132813cb4888407ce Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 15 May 2014 18:07:26 -0700 Subject: [PATCH 276/296] Rewrite startUsingNetworkFeature for new API bug:14993207 Change-Id: I041a80faa07bf3094af13a6c606f3b15aa03f789 (cherry picked from commit 09fe5e618b09965183cf53fba87c39025a19e8d1) --- .../java/android/net/ConnectivityManager.java | 219 ++++++++++++++++-- .../android/net/IConnectivityManager.aidl | 4 +- .../android/server/ConnectivityService.java | 30 ++- .../server/connectivity/NetworkAgentInfo.java | 17 ++ 4 files changed, 243 insertions(+), 27 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 2f2aba3286..24844ba46c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -40,6 +40,7 @@ import android.util.ArrayMap; import android.util.Log; import com.android.internal.telephony.ITelephony; +import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.Protocol; import java.net.InetAddress; @@ -807,11 +808,34 @@ public class ConnectivityManager { * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api. */ public int startUsingNetworkFeature(int networkType, String feature) { - try { - return mService.startUsingNetworkFeature(networkType, feature, - new Binder()); - } catch (RemoteException e) { - return -1; + NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); + if (netCap == null) { + Log.d(TAG, "Can't satisfy startUsingNetworkFeature for " + networkType + ", " + + feature); + return PhoneConstants.APN_REQUEST_FAILED; + } + + NetworkRequest request = null; + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l != null) { + Log.d(TAG, "renewing startUsingNetworkFeature request " + l.networkRequest); + renewRequestLocked(l); + if (l.currentNetwork != null) { + return PhoneConstants.APN_ALREADY_ACTIVE; + } else { + return PhoneConstants.APN_REQUEST_STARTED; + } + } + + request = requestNetworkForFeatureLocked(netCap); + } + if (request != null) { + Log.d(TAG, "starting startUsingNeworkFeature for request " + request); + return PhoneConstants.APN_REQUEST_STARTED; + } else { + Log.d(TAG, " request Failed"); + return PhoneConstants.APN_REQUEST_FAILED; } } @@ -831,11 +855,169 @@ public class ConnectivityManager { * @deprecated Deprecated in favor of the cleaner {@link #requestNetwork} api. */ public int stopUsingNetworkFeature(int networkType, String feature) { - try { - return mService.stopUsingNetworkFeature(networkType, feature); - } catch (RemoteException e) { + NetworkCapabilities netCap = networkCapabilitiesForFeature(networkType, feature); + if (netCap == null) { + Log.d(TAG, "Can't satisfy stopUsingNetworkFeature for " + networkType + ", " + + feature); return -1; } + + NetworkRequest request = removeRequestForFeature(netCap); + if (request != null) { + Log.d(TAG, "stopUsingNetworkFeature for " + networkType + ", " + feature); + releaseNetworkRequest(request); + } + return 1; + } + + private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { + if (networkType == TYPE_MOBILE) { + int cap = -1; + if ("enableMMS".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_MMS; + } else if ("enableSUPL".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_SUPL; + } else if ("enableDUN".equals(feature) || "enableDUNAlways".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_DUN; + } else if ("enableHIPRI".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_INTERNET; + } else if ("enableFOTA".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_FOTA; + } else if ("enableIMS".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_IMS; + } else if ("enableCBS".equals(feature)) { + cap = NetworkCapabilities.NET_CAPABILITY_CBS; + } else { + return null; + } + NetworkCapabilities netCap = new NetworkCapabilities(); + netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); + netCap.addNetworkCapability(cap); + return netCap; + } else if (networkType == TYPE_WIFI) { + if ("p2p".equals(feature)) { + NetworkCapabilities netCap = new NetworkCapabilities(); + netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); + netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); + return netCap; + } + } + return null; + } + + private int networkTypeForNetworkCapabilities(NetworkCapabilities netCap) { + if (netCap == null) return TYPE_NONE; + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { + return TYPE_MOBILE_CBS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_IMS)) { + return TYPE_MOBILE_IMS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_FOTA)) { + return TYPE_MOBILE_FOTA; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_DUN)) { + return TYPE_MOBILE_DUN; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_SUPL)) { + return TYPE_MOBILE_SUPL; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_MMS)) { + return TYPE_MOBILE_MMS; + } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { + return TYPE_MOBILE_HIPRI; + } + return TYPE_NONE; + } + + private static class LegacyRequest { + NetworkCapabilities networkCapabilities; + NetworkRequest networkRequest; + int expireSequenceNumber; + Network currentNetwork; + int delay = -1; + NetworkCallbackListener networkCallbackListener = new NetworkCallbackListener() { + @Override + public void onAvailable(NetworkRequest request, Network network) { + currentNetwork = network; + Log.d(TAG, "startUsingNetworkFeature got Network:" + network); + network.bindProcessForHostResolution(); + } + @Override + public void onLost(NetworkRequest request, Network network) { + if (network.equals(currentNetwork)) { + currentNetwork = null; + network.unbindProcessForHostResolution(); + } + Log.d(TAG, "startUsingNetworkFeature lost Network:" + network); + } + }; + } + + private HashMap sLegacyRequests = + new HashMap(); + + private NetworkRequest findRequestForFeature(NetworkCapabilities netCap) { + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l != null) return l.networkRequest; + } + return null; + } + + private void renewRequestLocked(LegacyRequest l) { + l.expireSequenceNumber++; + Log.d(TAG, "renewing request to seqNum " + l.expireSequenceNumber); + sendExpireMsgForFeature(l.networkCapabilities, l.expireSequenceNumber, l.delay); + } + + private void expireRequest(NetworkCapabilities netCap, int sequenceNum) { + int ourSeqNum = -1; + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.get(netCap); + if (l == null) return; + ourSeqNum = l.expireSequenceNumber; + if (l.expireSequenceNumber == sequenceNum) { + releaseNetworkRequest(l.networkRequest); + sLegacyRequests.remove(netCap); + } + } + Log.d(TAG, "expireRequest with " + ourSeqNum + ", " + sequenceNum); + } + + private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) { + int delay = -1; + int type = networkTypeForNetworkCapabilities(netCap); + try { + delay = mService.getRestoreDefaultNetworkDelay(type); + } catch (RemoteException e) {} + LegacyRequest l = new LegacyRequest(); + l.networkCapabilities = netCap; + l.delay = delay; + l.expireSequenceNumber = 0; + l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0, + REQUEST, true); + if (l.networkRequest == null) return null; + sLegacyRequests.put(netCap, l); + sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay); + return l.networkRequest; + } + + private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) { + if (delay >= 0) { + Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay); + Message msg = sCallbackHandler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap); + sCallbackHandler.sendMessageDelayed(msg, delay); + } + } + + private NetworkRequest removeRequestForFeature(NetworkCapabilities netCap) { + synchronized (sLegacyRequests) { + LegacyRequest l = sLegacyRequests.remove(netCap); + if (l == null) return null; + return l.networkRequest; + } } /** @@ -1782,8 +1964,10 @@ public class ConnectivityManager { public static final int CALLBACK_RELEASED = BASE + 8; /** @hide */ public static final int CALLBACK_EXIT = BASE + 9; + /** @hide obj = NetworkCapabilities, arg1 = seq number */ + private static final int EXPIRE_LEGACY_REQUEST = BASE + 10; - private static class CallbackHandler extends Handler { + private class CallbackHandler extends Handler { private final HashMapmCallbackMap; private final AtomicInteger mRefCount; private static final String TAG = "ConnectivityManager.CallbackHandler"; @@ -1903,6 +2087,10 @@ public class ConnectivityManager { getLooper().quit(); break; } + case EXPIRE_LEGACY_REQUEST: { + expireRequest((NetworkCapabilities)message.obj, message.arg1); + break; + } } } @@ -1954,8 +2142,9 @@ public class ConnectivityManager { private final static int LISTEN = 1; private final static int REQUEST = 2; - private NetworkRequest somethingForNetwork(NetworkCapabilities need, - NetworkCallbackListener networkCallbackListener, int timeoutSec, int action) { + private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, + NetworkCallbackListener networkCallbackListener, int timeoutSec, int action, + boolean legacy) { NetworkRequest networkRequest = null; if (networkCallbackListener == null) { throw new IllegalArgumentException("null NetworkCallbackListener"); @@ -1968,7 +2157,7 @@ public class ConnectivityManager { new Binder()); } else { networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler), - timeoutSec, new Binder()); + timeoutSec, new Binder(), legacy); } if (networkRequest != null) { synchronized(sNetworkCallbackListener) { @@ -1998,7 +2187,7 @@ public class ConnectivityManager { */ public NetworkRequest requestNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener) { - return somethingForNetwork(need, networkCallbackListener, 0, REQUEST); + return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, false); } /** @@ -2021,7 +2210,7 @@ public class ConnectivityManager { */ public NetworkRequest requestNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener, int timeoutSec) { - return somethingForNetwork(need, networkCallbackListener, timeoutSec, REQUEST); + return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, false); } /** @@ -2099,7 +2288,7 @@ public class ConnectivityManager { */ public NetworkRequest listenForNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener) { - return somethingForNetwork(need, networkCallbackListener, 0, LISTEN); + return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, false); } /** diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index baec36ad48..b67ae88c88 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -158,7 +158,7 @@ interface IConnectivityManager in NetworkCapabilities nc, int score); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, int timeoutSec, in IBinder binder); + in Messenger messenger, int timeoutSec, in IBinder binder, boolean legacy); NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, in PendingIntent operation); @@ -170,4 +170,6 @@ interface IConnectivityManager in PendingIntent operation); void releaseNetworkRequest(in NetworkRequest networkRequest); + + int getRestoreDefaultNetworkDelay(int networkType); } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index d7a19add8f..1c0b7b65eb 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -2843,7 +2843,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private int getRestoreDefaultNetworkDelay(int networkType) { + @Override + public int getRestoreDefaultNetworkDelay(int networkType) { String restoreDefaultNetworkDelayStr = SystemProperties.get( NETWORK_RESTORE_DELAY_PROP_NAME); if(restoreDefaultNetworkDelayStr != null && @@ -3137,6 +3138,14 @@ public class ConnectivityService extends IConnectivityManager.Stub { } catch (Exception e) { loge("Exception removing network: " + e); } + // TODO - if we move the logic to the network agent (have them disconnect + // because they lost all their requests or because their score isn't good) + // then they would disconnect organically, report their new state and then + // disconnect the channel. + if (nai.networkInfo.isConnected()) { + nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, + null, null); + } notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST); nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); mNetworkAgentInfos.remove(msg.replyTo); @@ -3203,7 +3212,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } if (bestNetwork != null) { if (VDBG) log("using " + bestNetwork.name()); - bestNetwork.networkRequests.put(nri.request.requestId, nri.request); + bestNetwork.addRequest(nri.request); notifyNetworkCallback(bestNetwork, nri); score = bestNetwork.currentScore; } @@ -3211,7 +3220,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) { if (DBG) log("sending new NetworkRequest to factories"); for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, nri.request); + nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, + 0, nri.request); } } } @@ -5279,7 +5289,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, - Messenger messenger, int timeoutSec, IBinder binder) { + Messenger messenger, int timeoutSec, IBinder binder, boolean legacy) { if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { enforceConnectivityInternalPermission(); @@ -5291,7 +5301,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities), false, nextNetworkRequestId()); + networkCapabilities), legacy, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); @@ -5392,7 +5402,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(), nextNetId(), new NetworkInfo(networkInfo), new LinkProperties(linkProperties), new NetworkCapabilities(networkCapabilities), currentScore, mContext, mTrackerHandler); - + if (VDBG) log("registerNetworkAgent " + nai); mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_AGENT, nai)); } @@ -5439,7 +5449,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mClat.stopClat(); } // If the link requires clat to be running, then start the daemon now. - if (newLp != null && na.networkInfo.isConnected()) { + if (na.networkInfo.isConnected()) { mClat.startClat(na); } else { mClat.stopClat(); @@ -5658,7 +5668,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (VDBG) log(" accepting network in place of null"); } mNetworkForRequestId.put(nri.request.requestId, newNetwork); - newNetwork.networkRequests.put(nri.request.requestId, nri.request); + newNetwork.addRequest(nri.request); keep = true; // TODO - this could get expensive if we have alot of requests for this // network. Think about if there is a way to reduce this. Push @@ -5810,15 +5820,13 @@ public class ConnectivityService extends IConnectivityManager.Stub { protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) { if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name()); - boolean needsBroadcasts = false; for (int i = 0; i < networkAgent.networkRequests.size(); i++) { NetworkRequest nr = networkAgent.networkRequests.valueAt(i); NetworkRequestInfo nri = mNetworkRequests.get(nr); if (VDBG) log(" sending notification for " + nr); - if (nr.needsBroadcasts) needsBroadcasts = true; callCallbackForRequest(nri, networkAgent, notifyType); } - if (needsBroadcasts) { + if (networkAgent.needsBroadcasts) { if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) { sendConnectedBroadcastDelayed(networkAgent.networkInfo, getConnectivityChangeDelay()); diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index 8102591ea9..e9f968377f 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -45,6 +45,17 @@ public class NetworkAgentInfo { public int currentScore; public final NetworkMonitor networkMonitor; + /** + * Indicates we need to send CONNECTIVITY_ACTION broadcasts for this network. + * For example the built-in default network request and any requsts coming from + * the deprecated startUsingNetworkFeature API will have this set. Networks + * responding to the new requestNetwork API will rely on point to point callbacks. + * + * Gets set if any legacy requests get affiliated with this network and + * stays set for life so we send disconnected bcasts to match the connected, + * even if the legacy request has moved on. + */ + public boolean needsBroadcasts = false; // The list of NetworkRequests being satisfied by this Network. public final SparseArray networkRequests = new SparseArray(); @@ -66,6 +77,12 @@ public class NetworkAgentInfo { networkMonitor = new NetworkMonitor(context, handler, this); } + public void addRequest(NetworkRequest networkRequest) { + if (networkRequest.needsBroadcasts) needsBroadcasts = true; + + networkRequests.put(networkRequest.requestId, networkRequest); + } + public String toString() { return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" + network + "} lp{" + From 06c734e52e4b5e39f9416d2f027f7ec549114d9e Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 27 May 2014 13:20:24 -0700 Subject: [PATCH 277/296] Refactor NetworkFactory. Make NetworkFactory a concrete class and divide responsibilites between it and NetworkAgent. Factory will track requests and by default give a single connect/disconnect api for ease of use. Then NetworkAgent is created and destroyed as needed with very simple logic. Change-Id: I401c14a6e5466f2fc63b04219b97ff85bb9af291 (cherry picked from commit 9a17b9c5a256cb4bb14821c5ee89b03b99c045e8) --- core/java/android/net/NetworkAgent.java | 337 ++++-------------- core/java/android/net/NetworkInfo.java | 5 +- .../android/server/ConnectivityService.java | 27 +- 3 files changed, 89 insertions(+), 280 deletions(-) diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 1c18ba5640..7e8b1f1aca 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -24,85 +24,39 @@ import android.os.Messenger; import android.os.Parcel; import android.os.Parcelable; import android.util.Log; -import android.util.SparseArray; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; +import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; /** - * A Utility class for handling NetworkRequests. - * - * Created by bearer-specific code to handle tracking requests, scores, - * network data and handle communicating with ConnectivityService. Two - * abstract methods: connect and disconnect are used to act on the - * underlying bearer code. Connect is called when we have a NetworkRequest - * and our score is better than the current handling network's score, while - * disconnect is used when ConnectivityService requests a disconnect. + * A Utility class for handling for communicating between bearer-specific + * code and ConnectivityService. * * A bearer may have more than one NetworkAgent if it can simultaneously * support separate networks (IMS / Internet / MMS Apns on cellular, or - * perhaps connections with different SSID or P2P for Wi-Fi). The bearer - * code should pass its NetworkAgents the NetworkRequests each NetworkAgent - * can handle, demultiplexing for different network types. The bearer code - * can also filter out requests it can never handle. + * perhaps connections with different SSID or P2P for Wi-Fi). * - * Each NetworkAgent needs to be given a score and NetworkCapabilities for - * their potential network. While disconnected, the NetworkAgent will check - * each time its score changes or a NetworkRequest changes to see if - * the NetworkAgent can provide a higher scored network for a NetworkRequest - * that the NetworkAgent's NetworkCapabilties can satisfy. This condition will - * trigger a connect request via connect(). After connection, connection data - * should be given to the NetworkAgent by the bearer, including LinkProperties - * NetworkCapabilties and NetworkInfo. After that the NetworkAgent will register - * with ConnectivityService and forward the data on. * @hide */ public abstract class NetworkAgent extends Handler { - private final SparseArray mNetworkRequests = new SparseArray<>(); - private boolean mConnectionRequested = false; - - private AsyncChannel mAsyncChannel; + private volatile AsyncChannel mAsyncChannel; private final String LOG_TAG; private static final boolean DBG = true; private static final boolean VDBG = true; - // TODO - this class shouldn't cache data or it runs the risk of getting out of sync - // Make the API require each of these when any is updated so we have the data we need, - // without caching. - private LinkProperties mLinkProperties; - private NetworkInfo mNetworkInfo; - private NetworkCapabilities mNetworkCapabilities; - private int mNetworkScore; - private boolean mRegistered = false; private final Context mContext; - private AtomicBoolean mHasRequests = new AtomicBoolean(false); - - // TODO - add a name member for logging purposes. - - protected final Object mLockObj = new Object(); - + private final ArrayListmPreConnectedQueue = new ArrayList(); private static final int BASE = Protocol.BASE_NETWORK_AGENT; - /** - * Sent by self to queue up a new/modified request. - * obj = NetworkRequestAndScore - */ - private static final int CMD_ADD_REQUEST = BASE + 1; - - /** - * Sent by self to queue up the removal of a request. - * obj = NetworkRequest - */ - private static final int CMD_REMOVE_REQUEST = BASE + 2; - /** * Sent by ConnectivityService to the NetworkAgent to inform it of * suspected connectivity problems on its network. The NetworkAgent * should take steps to verify and correct connectivity. */ - public static final int CMD_SUSPECT_BAD = BASE + 3; + public static final int CMD_SUSPECT_BAD = BASE; /** * Sent by the NetworkAgent (note the EVENT vs CMD prefix) to @@ -110,84 +64,63 @@ public abstract class NetworkAgent extends Handler { * Sent when the NetworkInfo changes, mainly due to change of state. * obj = NetworkInfo */ - public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 4; + public static final int EVENT_NETWORK_INFO_CHANGED = BASE + 1; /** * Sent by the NetworkAgent to ConnectivityService to pass the current * NetworkCapabilties. * obj = NetworkCapabilities */ - public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 5; + public static final int EVENT_NETWORK_CAPABILITIES_CHANGED = BASE + 2; /** * Sent by the NetworkAgent to ConnectivityService to pass the current * NetworkProperties. * obj = NetworkProperties */ - public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 6; + public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3; /** * Sent by the NetworkAgent to ConnectivityService to pass the current * network score. - * arg1 = network score int + * obj = network score Integer */ - public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 7; + public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4; - public NetworkAgent(Looper looper, Context context, String logTag) { + public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, + NetworkCapabilities nc, LinkProperties lp, int score) { super(looper); LOG_TAG = logTag; mContext = context; - } - - /** - * When conditions are right, register with ConnectivityService. - * Connditions include having a well defined network and a request - * that justifies it. The NetworkAgent will remain registered until - * disconnected. - * TODO - this should have all data passed in rather than caching - */ - private void registerSelf() { - synchronized(mLockObj) { - if (!mRegistered && mConnectionRequested && - mNetworkInfo != null && mNetworkInfo.isConnected() && - mNetworkCapabilities != null && - mLinkProperties != null && - mNetworkScore != 0) { - if (DBG) log("Registering NetworkAgent"); - mRegistered = true; - ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( - Context.CONNECTIVITY_SERVICE); - cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(mNetworkInfo), - new LinkProperties(mLinkProperties), - new NetworkCapabilities(mNetworkCapabilities), mNetworkScore); - } else if (DBG && !mRegistered) { - String err = "Not registering due to "; - if (mConnectionRequested == false) err += "no Connect requested "; - if (mNetworkInfo == null) err += "null NetworkInfo "; - if (mNetworkInfo != null && mNetworkInfo.isConnected() == false) { - err += "NetworkInfo disconnected "; - } - if (mLinkProperties == null) err += "null LinkProperties "; - if (mNetworkCapabilities == null) err += "null NetworkCapabilities "; - if (mNetworkScore == 0) err += "null NetworkScore"; - log(err); - } + if (ni == null || nc == null || lp == null) { + throw new IllegalArgumentException(); } + + if (DBG) log("Registering NetworkAgent"); + ConnectivityManager cm = (ConnectivityManager)mContext.getSystemService( + Context.CONNECTIVITY_SERVICE); + cm.registerNetworkAgent(new Messenger(this), new NetworkInfo(ni), + new LinkProperties(lp), new NetworkCapabilities(nc), score); } @Override public void handleMessage(Message msg) { switch (msg.what) { case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: { - synchronized (mLockObj) { - if (mAsyncChannel != null) { - log("Received new connection while already connected!"); - } else { - if (DBG) log("NetworkAgent fully connected"); - mAsyncChannel = new AsyncChannel(); - mAsyncChannel.connected(null, this, msg.replyTo); - mAsyncChannel.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, - AsyncChannel.STATUS_SUCCESSFUL); + if (mAsyncChannel != null) { + log("Received new connection while already connected!"); + } else { + if (DBG) log("NetworkAgent fully connected"); + AsyncChannel ac = new AsyncChannel(); + ac.connected(null, this, msg.replyTo); + ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED, + AsyncChannel.STATUS_SUCCESSFUL); + synchronized (mPreConnectedQueue) { + mAsyncChannel = ac; + for (Message m : mPreConnectedQueue) { + ac.sendMessage(m); + } + mPreConnectedQueue.clear(); } } break; @@ -199,213 +132,69 @@ public abstract class NetworkAgent extends Handler { } case AsyncChannel.CMD_CHANNEL_DISCONNECTED: { if (DBG) log("NetworkAgent channel lost"); - disconnect(); - clear(); + // let the client know CS is done with us. + unwanted(); + synchronized (mPreConnectedQueue) { + mAsyncChannel = null; + } break; } case CMD_SUSPECT_BAD: { log("Unhandled Message " + msg); break; } - case CMD_ADD_REQUEST: { - handleAddRequest(msg); - break; - } - case CMD_REMOVE_REQUEST: { - handleRemoveRequest(msg); - break; - } } } - private void clear() { - synchronized(mLockObj) { - mNetworkRequests.clear(); - mHasRequests.set(false); - mConnectionRequested = false; - mAsyncChannel = null; - mRegistered = false; - } - } - - private static class NetworkRequestAndScore { - NetworkRequest req; - int score; - - NetworkRequestAndScore(NetworkRequest networkRequest, int score) { - req = networkRequest; - this.score = score; - } - } - - private void handleAddRequest(Message msg) { - NetworkRequestAndScore n = (NetworkRequestAndScore)msg.obj; - // replaces old request, updating score - mNetworkRequests.put(n.req.requestId, n); - mHasRequests.set(true); - evalScores(); - } - - private void handleRemoveRequest(Message msg) { - NetworkRequest networkRequest = (NetworkRequest)msg.obj; - - if (mNetworkRequests.get(networkRequest.requestId) != null) { - mNetworkRequests.remove(networkRequest.requestId); - if (mNetworkRequests.size() == 0) mHasRequests.set(false); - evalScores(); - } - } - - /** - * Called to go through our list of requests and see if we're - * good enough to try connecting, or if we have gotten worse and - * need to disconnect. - * - * Once we are registered, does nothing: we disconnect when requested via - * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection - * between modules (bearer or ConnectivityService dies) or more commonly - * when the NetworkInfo reports to ConnectivityService it is disconnected. - */ - private void evalScores() { - synchronized(mLockObj) { - if (mRegistered) { - if (VDBG) log("evalScores - already connected - size=" + mNetworkRequests.size()); - // already trying - return; - } - if (VDBG) log("evalScores!"); - for (int i=0; i < mNetworkRequests.size(); i++) { - int score = mNetworkRequests.valueAt(i).score; - if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore); - if (score < mNetworkScore) { - // have a request that has a lower scored network servicing it - // (or no network) than we could provide, so let's connect! - mConnectionRequested = true; - connect(); - return; - } - } - // Our score is not high enough to satisfy any current request. - // This can happen if our score goes down after a connection is - // requested but before we actually connect. In this case, disconnect - // rather than continue trying - there's no point connecting if we know - // we'll just be torn down as soon as we do. - if (mConnectionRequested) { - mConnectionRequested = false; - disconnect(); + private void queueOrSendMessage(int what, Object obj) { + synchronized (mPreConnectedQueue) { + if (mAsyncChannel != null) { + mAsyncChannel.sendMessage(what, obj); + } else { + Message msg = Message.obtain(); + msg.what = what; + msg.obj = obj; + mPreConnectedQueue.add(msg); } } } - public void addNetworkRequest(NetworkRequest networkRequest, int score) { - if (DBG) log("adding NetworkRequest " + networkRequest + " with score " + score); - sendMessage(obtainMessage(CMD_ADD_REQUEST, - new NetworkRequestAndScore(networkRequest, score))); - } - - public void removeNetworkRequest(NetworkRequest networkRequest) { - if (DBG) log("removing NetworkRequest " + networkRequest); - sendMessage(obtainMessage(CMD_REMOVE_REQUEST, networkRequest)); - } - /** * Called by the bearer code when it has new LinkProperties data. - * If we're a registered NetworkAgent, this new data will get forwarded on, - * otherwise we store a copy in anticipation of registering. This call - * may also prompt registration if it causes the NetworkAgent to meet - * the conditions (fully configured, connected, satisfys a request and - * has sufficient score). */ public void sendLinkProperties(LinkProperties linkProperties) { - linkProperties = new LinkProperties(linkProperties); - synchronized(mLockObj) { - mLinkProperties = linkProperties; - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, linkProperties); - } else { - registerSelf(); - } - } + queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); } /** * Called by the bearer code when it has new NetworkInfo data. - * If we're a registered NetworkAgent, this new data will get forwarded on, - * otherwise we store a copy in anticipation of registering. This call - * may also prompt registration if it causes the NetworkAgent to meet - * the conditions (fully configured, connected, satisfys a request and - * has sufficient score). */ public void sendNetworkInfo(NetworkInfo networkInfo) { - networkInfo = new NetworkInfo(networkInfo); - synchronized(mLockObj) { - mNetworkInfo = networkInfo; - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(EVENT_NETWORK_INFO_CHANGED, networkInfo); - } else { - registerSelf(); - } - } + queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); } /** * Called by the bearer code when it has new NetworkCapabilities data. - * If we're a registered NetworkAgent, this new data will get forwarded on, - * otherwise we store a copy in anticipation of registering. This call - * may also prompt registration if it causes the NetworkAgent to meet - * the conditions (fully configured, connected, satisfys a request and - * has sufficient score). - * Note that if these capabilities make the network non-useful, - * ConnectivityServce will tear this network down. */ public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) { - networkCapabilities = new NetworkCapabilities(networkCapabilities); - synchronized(mLockObj) { - mNetworkCapabilities = networkCapabilities; - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, networkCapabilities); - } else { - registerSelf(); - } - } - } - - public NetworkCapabilities getNetworkCapabilities() { - synchronized(mLockObj) { - return new NetworkCapabilities(mNetworkCapabilities); - } + queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, + new NetworkCapabilities(networkCapabilities)); } /** * Called by the bearer code when it has a new score for this network. - * If we're a registered NetworkAgent, this new data will get forwarded on, - * otherwise we store a copy. */ - public synchronized void sendNetworkScore(int score) { - synchronized(mLockObj) { - mNetworkScore = score; - evalScores(); - if (mAsyncChannel != null) { - mAsyncChannel.sendMessage(EVENT_NETWORK_SCORE_CHANGED, mNetworkScore); - } else { - registerSelf(); - } - } + public void sendNetworkScore(int score) { + queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score)); } - public boolean hasRequests() { - return mHasRequests.get(); - } - - public boolean isConnectionRequested() { - synchronized(mLockObj) { - return mConnectionRequested; - } - } - - - abstract protected void connect(); - abstract protected void disconnect(); + /** + * Called when ConnectivityService has indicated they no longer want this network. + * The parent factory should (previously) have received indication of the change + * as well, either canceling NetworkRequests or altering their score such that this + * network won't be immediately requested again. + */ + abstract protected void unwanted(); protected void log(String s) { Log.d(LOG_TAG, "NetworkAgent: " + s); diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index 9e656eecbe..ccc56e23af 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -198,7 +198,10 @@ public class NetworkInfo implements Parcelable { } } - void setSubtype(int subtype, String subtypeName) { + /** + * @hide + */ + public void setSubtype(int subtype, String subtypeName) { synchronized (this) { mSubtype = subtype; mSubtypeName = subtypeName; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1c0b7b65eb..22ecd33c4e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -38,7 +38,6 @@ import static android.net.ConnectivityManager.TYPE_WIMAX; import static android.net.ConnectivityManager.TYPE_PROXY; import static android.net.ConnectivityManager.getNetworkTypeName; import static android.net.ConnectivityManager.isNetworkTypeValid; -import static android.net.ConnectivityServiceProtocol.NetworkFactoryProtocol; import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL; import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; @@ -80,6 +79,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkConfig; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; +import android.net.NetworkFactory; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkState; @@ -2995,6 +2995,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { updateNetworkInfo(nai, info); break; } + case NetworkAgent.EVENT_NETWORK_SCORE_CHANGED: { + NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); + if (nai == null) { + loge("EVENT_NETWORK_SCORE_CHANGED from unknown NetworkAgent"); + break; + } + Integer score = (Integer) msg.obj; + updateNetworkScore(nai, score); + break; + } case NetworkMonitor.EVENT_NETWORK_VALIDATED: { NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; handleConnectionValidated(nai); @@ -3099,7 +3109,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { for (NetworkRequestInfo nri : mNetworkRequests.values()) { if (nri.isRequest == false) continue; NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId); - ac.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, + ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, (nai != null ? nai.currentScore : 0), 0, nri.request); } } else { @@ -3220,7 +3230,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (msg.what == EVENT_REGISTER_NETWORK_REQUEST) { if (DBG) log("sending new NetworkRequest to factories"); for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, + nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, nri.request); } } @@ -3243,7 +3253,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (nri.isRequest) { for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_CANCEL_REQUEST, nri.request); + nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_CANCEL_REQUEST, + nri.request); } if (affectedNetwork != null) { @@ -5565,7 +5576,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, int score) { if (VDBG) log("sending new Min Network Score(" + score + "): " + networkRequest.toString()); for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(NetworkFactoryProtocol.CMD_REQUEST_NETWORK, score, 0, networkRequest); + nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, + networkRequest); } } @@ -5802,6 +5814,11 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } + private void updateNetworkScore(NetworkAgentInfo nai, Integer scoreInteger) { + int score = scoreInteger.intValue(); + // TODO + } + // notify only this one new request of the current state protected void notifyNetworkCallback(NetworkAgentInfo nai, NetworkRequestInfo nri) { int notifyType = ConnectivityManager.CALLBACK_AVAILABLE; From 03f23bfe91cc142568568b90ee562e0b5b84922f Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 2 Jun 2014 15:32:02 -0700 Subject: [PATCH 278/296] Fix Legacy NetworkInfo API Make the connectivity changed broadcasts send correct NetworkInfos. Also update the results of getNetwork. bug:15290306 bug:15191336 bug:14993207 Change-Id: Ie99ad25f3ebb90d18348e7013761b139e7481866 --- .../java/android/net/ConnectivityManager.java | 20 +- .../android/net/IConnectivityManager.aidl | 2 +- core/java/android/net/NetworkInfo.java | 9 + core/java/android/net/NetworkRequest.java | 22 +- .../android/server/ConnectivityService.java | 288 ++++++++++++------ .../server/connectivity/NetworkAgentInfo.java | 14 - 6 files changed, 224 insertions(+), 131 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 24844ba46c..a48a388820 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -905,7 +905,7 @@ public class ConnectivityManager { return null; } - private int networkTypeForNetworkCapabilities(NetworkCapabilities netCap) { + private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) { if (netCap == null) return TYPE_NONE; if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { return TYPE_MOBILE_CBS; @@ -928,6 +928,9 @@ public class ConnectivityManager { if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { return TYPE_MOBILE_HIPRI; } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)) { + return TYPE_WIFI_P2P; + } return TYPE_NONE; } @@ -988,7 +991,7 @@ public class ConnectivityManager { private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) { int delay = -1; - int type = networkTypeForNetworkCapabilities(netCap); + int type = legacyTypeForNetworkCapabilities(netCap); try { delay = mService.getRestoreDefaultNetworkDelay(type); } catch (RemoteException e) {} @@ -997,7 +1000,7 @@ public class ConnectivityManager { l.delay = delay; l.expireSequenceNumber = 0; l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0, - REQUEST, true); + REQUEST, type); if (l.networkRequest == null) return null; sLegacyRequests.put(netCap, l); sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay); @@ -2144,7 +2147,7 @@ public class ConnectivityManager { private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener, int timeoutSec, int action, - boolean legacy) { + int legacyType) { NetworkRequest networkRequest = null; if (networkCallbackListener == null) { throw new IllegalArgumentException("null NetworkCallbackListener"); @@ -2157,7 +2160,7 @@ public class ConnectivityManager { new Binder()); } else { networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler), - timeoutSec, new Binder(), legacy); + timeoutSec, new Binder(), legacyType); } if (networkRequest != null) { synchronized(sNetworkCallbackListener) { @@ -2187,7 +2190,7 @@ public class ConnectivityManager { */ public NetworkRequest requestNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener) { - return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, false); + return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, TYPE_NONE); } /** @@ -2210,7 +2213,8 @@ public class ConnectivityManager { */ public NetworkRequest requestNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener, int timeoutSec) { - return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, false); + return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, + TYPE_NONE); } /** @@ -2288,7 +2292,7 @@ public class ConnectivityManager { */ public NetworkRequest listenForNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener) { - return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, false); + return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, TYPE_NONE); } /** diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b67ae88c88..5f1ff3e1d9 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -158,7 +158,7 @@ interface IConnectivityManager in NetworkCapabilities nc, int score); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, int timeoutSec, in IBinder binder, boolean legacy); + in Messenger messenger, int timeoutSec, in IBinder binder, int legacy); NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, in PendingIntent operation); diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index ccc56e23af..d2794127f5 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -187,6 +187,15 @@ public class NetworkInfo implements Parcelable { } } + /** + * @hide + */ + public void setType(int type) { + synchronized (this) { + mNetworkType = type; + } + } + /** * Return a network-type-specific integer describing the subtype * of the network. diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 480cb057b0..47377e97be 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -47,19 +47,19 @@ public class NetworkRequest implements Parcelable { public final int requestId; /** - * Set for legacy requests and the default. + * Set for legacy requests and the default. Set to TYPE_NONE for none. * Causes CONNECTIVITY_ACTION broadcasts to be sent. * @hide */ - public final boolean needsBroadcasts; + public final int legacyType; /** * @hide */ - public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) { + public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId) { requestId = rId; networkCapabilities = nc; - this.needsBroadcasts = needsBroadcasts; + this.legacyType = legacyType; } /** @@ -68,7 +68,7 @@ public class NetworkRequest implements Parcelable { public NetworkRequest(NetworkRequest that) { networkCapabilities = new NetworkCapabilities(that.networkCapabilities); requestId = that.requestId; - needsBroadcasts = that.needsBroadcasts; + this.legacyType = that.legacyType; } // implement the Parcelable interface @@ -77,16 +77,16 @@ public class NetworkRequest implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(networkCapabilities, flags); - dest.writeInt(needsBroadcasts ? 1 : 0); + dest.writeInt(legacyType); dest.writeInt(requestId); } public static final Creator CREATOR = new Creator() { public NetworkRequest createFromParcel(Parcel in) { NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null); - boolean needsBroadcasts = (in.readInt() == 1); + int legacyType = in.readInt(); int requestId = in.readInt(); - NetworkRequest result = new NetworkRequest(nc, needsBroadcasts, requestId); + NetworkRequest result = new NetworkRequest(nc, legacyType, requestId); return result; } public NetworkRequest[] newArray(int size) { @@ -95,14 +95,14 @@ public class NetworkRequest implements Parcelable { }; public String toString() { - return "NetworkRequest [ id=" + requestId + ", needsBroadcasts=" + needsBroadcasts + + return "NetworkRequest [ id=" + requestId + ", legacyType=" + legacyType + ", " + networkCapabilities.toString() + " ]"; } public boolean equals(Object obj) { if (obj instanceof NetworkRequest == false) return false; NetworkRequest that = (NetworkRequest)obj; - return (that.needsBroadcasts == this.needsBroadcasts && + return (that.legacyType == this.legacyType && that.requestId == this.requestId && ((that.networkCapabilities == null && this.networkCapabilities == null) || (that.networkCapabilities != null && @@ -110,7 +110,7 @@ public class NetworkRequest implements Parcelable { } public int hashCode() { - return requestId + (needsBroadcasts ? 1013 : 2026) + + return requestId + (legacyType * 1013) + (networkCapabilities.hashCode() * 1051); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 22ecd33c4e..b2b4217140 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -258,17 +258,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private NetworkStateTracker mNetTrackers[]; - /** - * Holds references to all NetworkAgentInfos claiming to support the legacy - * NetworkType. We used to have a static set of of NetworkStateTrackers - * for each network type. This is the new model. - * Supports synchronous inspection of state. - * These are built out at startup such that an unsupported network - * doesn't get an ArrayList instance, making this a tristate: - * unsupported, supported but not active and active. - */ - private ArrayList mNetworkAgentInfoForType[]; - /* Handles captive portal check on a network */ private CaptivePortalTracker mCaptivePortalTracker; @@ -516,6 +505,118 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int UID_UNUSED = -1; + /** + * Implements support for the legacy "one network per network type" model. + * + * We used to have a static array of NetworkStateTrackers, one for each + * network type, but that doesn't work any more now that we can have, + * for example, more that one wifi network. This class stores all the + * NetworkAgentInfo objects that support a given type, but the legacy + * API will only see the first one. + * + * It serves two main purposes: + * + * 1. Provide information about "the network for a given type" (since this + * API only supports one). + * 2. Send legacy connectivity change broadcasts. Broadcasts are sent if + * the first network for a given type changes, or if the default network + * changes. + */ + private class LegacyTypeTracker { + /** + * Array of lists, one per legacy network type (e.g., TYPE_MOBILE_MMS). + * Each list holds references to all NetworkAgentInfos that are used to + * satisfy requests for that network type. + * + * This array is built out at startup such that an unsupported network + * doesn't get an ArrayList instance, making this a tristate: + * unsupported, supported but not active and active. + * + * The actual lists are populated when we scan the network types that + * are supported on this device. + */ + private ArrayList mTypeLists[]; + + public LegacyTypeTracker() { + mTypeLists = (ArrayList[]) + new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1]; + } + + public void addSupportedType(int type) { + if (mTypeLists[type] != null) { + throw new IllegalStateException( + "legacy list for type " + type + "already initialized"); + } + mTypeLists[type] = new ArrayList(); + } + + private boolean isDefaultNetwork(NetworkAgentInfo nai) { + return mNetworkForRequestId.get(mDefaultRequest.requestId) == nai; + } + + public boolean isTypeSupported(int type) { + return isNetworkTypeValid(type) && mTypeLists[type] != null; + } + + public NetworkAgentInfo getNetworkForType(int type) { + if (isTypeSupported(type) && !mTypeLists[type].isEmpty()) { + return mTypeLists[type].get(0); + } else { + return null; + } + } + + public void add(int type, NetworkAgentInfo nai) { + if (!isTypeSupported(type)) { + return; // Invalid network type. + } + if (VDBG) log("Adding agent " + nai + " for legacy network type " + type); + + ArrayList list = mTypeLists[type]; + if (list.contains(nai)) { + loge("Attempting to register duplicate agent for type " + type + ": " + nai); + return; + } + + if (list.isEmpty() || isDefaultNetwork(nai)) { + if (VDBG) log("Sending connected broadcast for type " + type + + "isDefaultNetwork=" + isDefaultNetwork(nai)); + sendLegacyNetworkBroadcast(nai, true, type); + } + list.add(nai); + } + + public void remove(NetworkAgentInfo nai) { + if (VDBG) log("Removing agent " + nai); + for (int type = 0; type < mTypeLists.length; type++) { + ArrayList list = mTypeLists[type]; + if (list == null || list.isEmpty()) { + continue; + } + + boolean wasFirstNetwork = false; + if (list.get(0).equals(nai)) { + // This network was the first in the list. Send broadcast. + wasFirstNetwork = true; + } + list.remove(nai); + + if (wasFirstNetwork || isDefaultNetwork(nai)) { + if (VDBG) log("Sending disconnected broadcast for type " + type + + "isDefaultNetwork=" + isDefaultNetwork(nai)); + sendLegacyNetworkBroadcast(nai, false, type); + } + + if (!list.isEmpty() && wasFirstNetwork) { + if (VDBG) log("Other network available for type " + type + + ", sending connected broadcast"); + sendLegacyNetworkBroadcast(list.get(0), false, type); + } + } + } + } + private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(); + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -531,7 +632,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - mDefaultRequest = new NetworkRequest(netCap, true, nextNetworkRequestId()); + mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId()); NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(), NetworkRequestInfo.REQUEST); mNetworkRequests.put(mDefaultRequest, nri); @@ -587,9 +688,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( com.android.internal.R.integer.config_networkTransitionTimeout); - mNetworkAgentInfoForType = (ArrayList[]) - new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1]; - mNetTrackers = new NetworkStateTracker[ ConnectivityManager.MAX_NETWORK_TYPE+1]; mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1]; @@ -644,7 +742,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { "radio " + n.radio + " in network type " + n.type); continue; } - mNetworkAgentInfoForType[n.type] = new ArrayList(); + mLegacyTypeTracker.addSupportedType(n.type); mNetConfigs[n.type] = n; mNetworksDefined++; @@ -3125,11 +3223,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { loge("Error connecting NetworkAgent"); NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo); - try { - mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai); - } catch (NullPointerException e) {} if (nai != null) { mNetworkForNetId.remove(nai.network.netId); + mLegacyTypeTracker.remove(nai); } } } @@ -3160,10 +3256,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); mNetworkAgentInfos.remove(msg.replyTo); updateClat(null, nai.linkProperties, nai); - try { - mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai); - } catch (NullPointerException e) {} - + mLegacyTypeTracker.remove(nai); mNetworkForNetId.remove(nai.network.netId); // Since we've lost the network, go through all the requests that // it was satisfying and see if any other factory can satisfy them. @@ -3173,7 +3266,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId); if (VDBG) { log(" checking request " + request + ", currentNetwork = " + - currentNetwork != null ? currentNetwork.name() : "null"); + (currentNetwork != null ? currentNetwork.name() : "null")); } if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { mNetworkForRequestId.remove(request.requestId); @@ -3223,6 +3316,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (bestNetwork != null) { if (VDBG) log("using " + bestNetwork.name()); bestNetwork.addRequest(nri.request); + int legacyType = nri.request.legacyType; + if (legacyType != TYPE_NONE) { + mLegacyTypeTracker.add(legacyType, bestNetwork); + } notifyNetworkCallback(bestNetwork, nri); score = bestNetwork.currentScore; } @@ -5300,7 +5397,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, - Messenger messenger, int timeoutSec, IBinder binder, boolean legacy) { + Messenger messenger, int timeoutSec, IBinder binder, int legacyType) { if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { enforceConnectivityInternalPermission(); @@ -5312,7 +5409,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities), legacy, nextNetworkRequestId()); + networkCapabilities), legacyType, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); @@ -5338,7 +5435,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { enforceAccessPermission(); NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities), false, nextNetworkRequestId()); + networkCapabilities), TYPE_NONE, nextNetworkRequestId()); if (DBG) log("listenForNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.LISTEN); @@ -5420,11 +5517,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleRegisterNetworkAgent(NetworkAgentInfo na) { if (VDBG) log("Got NetworkAgent Messenger"); mNetworkAgentInfos.put(na.messenger, na); - try { - mNetworkAgentInfoForType[na.networkInfo.getType()].add(na); - } catch (NullPointerException e) { - loge("registered NetworkAgent for unsupported type: " + na); - } mNetworkForNetId.put(na.network.netId, na); na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger); NetworkInfo networkInfo = na.networkInfo; @@ -5681,6 +5773,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mNetworkForRequestId.put(nri.request.requestId, newNetwork); newNetwork.addRequest(nri.request); + int legacyType = nri.request.legacyType; + if (legacyType != TYPE_NONE) { + mLegacyTypeTracker.add(legacyType, newNetwork); + } keep = true; // TODO - this could get expensive if we have alot of requests for this // network. Think about if there is a way to reduce this. Push @@ -5694,6 +5790,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { setDefaultDnsSystemProperties(new ArrayList()); } + mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork); } } } @@ -5828,13 +5925,53 @@ public class ConnectivityService extends IConnectivityManager.Stub { // } else if (nai.networkMonitor.isEvaluating()) { // notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType); // } - if (nri.request.needsBroadcasts) { - // TODO -// sendNetworkBroadcast(nai, notifyType); - } callCallbackForRequest(nri, nai, notifyType); } + private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, boolean connected, int type) { + if (connected) { + NetworkInfo info = new NetworkInfo(nai.networkInfo); + info.setType(type); + sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); + } else { + NetworkInfo info = new NetworkInfo(nai.networkInfo); + info.setType(type); + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); + if (info.isFailover()) { + intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); + nai.networkInfo.setFailover(false); + } + if (info.getReason() != null) { + intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); + } + if (info.getExtraInfo() != null) { + intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); + } + NetworkAgentInfo newDefaultAgent = null; + if (nai.networkRequests.get(mDefaultRequest.requestId) != null) { + newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId); + if (newDefaultAgent != null) { + intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, + newDefaultAgent.networkInfo); + } else { + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); + } + } + intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, + mDefaultInetConditionPublished); + final Intent immediateIntent = new Intent(intent); + immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); + sendStickyBroadcast(immediateIntent); + sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); + if (newDefaultAgent != null) { + sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo, + getConnectivityChangeDelay()); + } + } + } + protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) { if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name()); for (int i = 0; i < networkAgent.networkRequests.size(); i++) { @@ -5843,76 +5980,33 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (VDBG) log(" sending notification for " + nr); callCallbackForRequest(nri, networkAgent, notifyType); } - if (networkAgent.needsBroadcasts) { - if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) { - sendConnectedBroadcastDelayed(networkAgent.networkInfo, - getConnectivityChangeDelay()); - } else if (notifyType == ConnectivityManager.CALLBACK_LOST) { - NetworkInfo info = new NetworkInfo(networkAgent.networkInfo); - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - networkAgent.networkInfo.setFailover(false); - } - if (info.getReason() != null) { - intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); - } - if (info.getExtraInfo() != null) { - intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); - } - NetworkAgentInfo newDefaultAgent = null; - if (networkAgent.networkRequests.get(mDefaultRequest.requestId) != null) { - newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId); - if (newDefaultAgent != null) { - intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, - newDefaultAgent.networkInfo); - } else { - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } - } - intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, - mDefaultInetConditionPublished); - final Intent immediateIntent = new Intent(intent); - immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); - sendStickyBroadcast(immediateIntent); - sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); - if (newDefaultAgent != null) { - sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo, - getConnectivityChangeDelay()); - } - } - } } private LinkProperties getLinkPropertiesForTypeInternal(int networkType) { - ArrayList list = mNetworkAgentInfoForType[networkType]; - if (list == null) return null; - try { - return new LinkProperties(list.get(0).linkProperties); - } catch (IndexOutOfBoundsException e) { - return new LinkProperties(); - } + NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); + return (nai != null) ? + new LinkProperties(nai.linkProperties) : + new LinkProperties(); } private NetworkInfo getNetworkInfoForType(int networkType) { - ArrayList list = mNetworkAgentInfoForType[networkType]; - if (list == null) return null; - try { - return new NetworkInfo(list.get(0).networkInfo); - } catch (IndexOutOfBoundsException e) { - return new NetworkInfo(networkType, 0, "Unknown", ""); + if (!mLegacyTypeTracker.isTypeSupported(networkType)) + return null; + + NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); + if (nai != null) { + NetworkInfo result = new NetworkInfo(nai.networkInfo); + result.setType(networkType); + return result; + } else { + return new NetworkInfo(networkType, 0, "Unknown", ""); } } private NetworkCapabilities getNetworkCapabilitiesForType(int networkType) { - ArrayList list = mNetworkAgentInfoForType[networkType]; - if (list == null) return null; - try { - return new NetworkCapabilities(list.get(0).networkCapabilities); - } catch (IndexOutOfBoundsException e) { - return new NetworkCapabilities(); - } + NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); + return (nai != null) ? + new NetworkCapabilities(nai.networkCapabilities) : + new NetworkCapabilities(); } } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index e9f968377f..b03c247e80 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -45,18 +45,6 @@ public class NetworkAgentInfo { public int currentScore; public final NetworkMonitor networkMonitor; - /** - * Indicates we need to send CONNECTIVITY_ACTION broadcasts for this network. - * For example the built-in default network request and any requsts coming from - * the deprecated startUsingNetworkFeature API will have this set. Networks - * responding to the new requestNetwork API will rely on point to point callbacks. - * - * Gets set if any legacy requests get affiliated with this network and - * stays set for life so we send disconnected bcasts to match the connected, - * even if the legacy request has moved on. - */ - public boolean needsBroadcasts = false; - // The list of NetworkRequests being satisfied by this Network. public final SparseArray networkRequests = new SparseArray(); public final ArrayList networkLingered = new ArrayList(); @@ -78,8 +66,6 @@ public class NetworkAgentInfo { } public void addRequest(NetworkRequest networkRequest) { - if (networkRequest.needsBroadcasts) needsBroadcasts = true; - networkRequests.put(networkRequest.requestId, networkRequest); } From 802c11080e4978b8e09bd2e0cb4c59b7117ef8c8 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 2 Jun 2014 15:32:02 -0700 Subject: [PATCH 279/296] Fix Legacy NetworkInfo API Make the connectivity changed broadcasts send correct NetworkInfos. Also update the results of getNetwork. bug:15290306 bug:15191336 bug:14993207 Change-Id: Ie99ad25f3ebb90d18348e7013761b139e7481866 (cherry picked from commit 16fe1c18289de200d2249e51db8c0986619f487b) --- .../java/android/net/ConnectivityManager.java | 20 +- .../android/net/IConnectivityManager.aidl | 2 +- core/java/android/net/NetworkInfo.java | 9 + core/java/android/net/NetworkRequest.java | 22 +- .../android/server/ConnectivityService.java | 288 ++++++++++++------ .../server/connectivity/NetworkAgentInfo.java | 14 - 6 files changed, 224 insertions(+), 131 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 24844ba46c..a48a388820 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -905,7 +905,7 @@ public class ConnectivityManager { return null; } - private int networkTypeForNetworkCapabilities(NetworkCapabilities netCap) { + private int legacyTypeForNetworkCapabilities(NetworkCapabilities netCap) { if (netCap == null) return TYPE_NONE; if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { return TYPE_MOBILE_CBS; @@ -928,6 +928,9 @@ public class ConnectivityManager { if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { return TYPE_MOBILE_HIPRI; } + if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)) { + return TYPE_WIFI_P2P; + } return TYPE_NONE; } @@ -988,7 +991,7 @@ public class ConnectivityManager { private NetworkRequest requestNetworkForFeatureLocked(NetworkCapabilities netCap) { int delay = -1; - int type = networkTypeForNetworkCapabilities(netCap); + int type = legacyTypeForNetworkCapabilities(netCap); try { delay = mService.getRestoreDefaultNetworkDelay(type); } catch (RemoteException e) {} @@ -997,7 +1000,7 @@ public class ConnectivityManager { l.delay = delay; l.expireSequenceNumber = 0; l.networkRequest = sendRequestForNetwork(netCap, l.networkCallbackListener, 0, - REQUEST, true); + REQUEST, type); if (l.networkRequest == null) return null; sLegacyRequests.put(netCap, l); sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay); @@ -2144,7 +2147,7 @@ public class ConnectivityManager { private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener, int timeoutSec, int action, - boolean legacy) { + int legacyType) { NetworkRequest networkRequest = null; if (networkCallbackListener == null) { throw new IllegalArgumentException("null NetworkCallbackListener"); @@ -2157,7 +2160,7 @@ public class ConnectivityManager { new Binder()); } else { networkRequest = mService.requestNetwork(need, new Messenger(sCallbackHandler), - timeoutSec, new Binder(), legacy); + timeoutSec, new Binder(), legacyType); } if (networkRequest != null) { synchronized(sNetworkCallbackListener) { @@ -2187,7 +2190,7 @@ public class ConnectivityManager { */ public NetworkRequest requestNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener) { - return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, false); + return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, TYPE_NONE); } /** @@ -2210,7 +2213,8 @@ public class ConnectivityManager { */ public NetworkRequest requestNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener, int timeoutSec) { - return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, false); + return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, + TYPE_NONE); } /** @@ -2288,7 +2292,7 @@ public class ConnectivityManager { */ public NetworkRequest listenForNetwork(NetworkCapabilities need, NetworkCallbackListener networkCallbackListener) { - return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, false); + return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, TYPE_NONE); } /** diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index b67ae88c88..5f1ff3e1d9 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -158,7 +158,7 @@ interface IConnectivityManager in NetworkCapabilities nc, int score); NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, int timeoutSec, in IBinder binder, boolean legacy); + in Messenger messenger, int timeoutSec, in IBinder binder, int legacy); NetworkRequest pendingRequestForNetwork(in NetworkCapabilities networkCapabilities, in PendingIntent operation); diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java index ccc56e23af..d2794127f5 100644 --- a/core/java/android/net/NetworkInfo.java +++ b/core/java/android/net/NetworkInfo.java @@ -187,6 +187,15 @@ public class NetworkInfo implements Parcelable { } } + /** + * @hide + */ + public void setType(int type) { + synchronized (this) { + mNetworkType = type; + } + } + /** * Return a network-type-specific integer describing the subtype * of the network. diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 480cb057b0..47377e97be 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -47,19 +47,19 @@ public class NetworkRequest implements Parcelable { public final int requestId; /** - * Set for legacy requests and the default. + * Set for legacy requests and the default. Set to TYPE_NONE for none. * Causes CONNECTIVITY_ACTION broadcasts to be sent. * @hide */ - public final boolean needsBroadcasts; + public final int legacyType; /** * @hide */ - public NetworkRequest(NetworkCapabilities nc, boolean needsBroadcasts, int rId) { + public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId) { requestId = rId; networkCapabilities = nc; - this.needsBroadcasts = needsBroadcasts; + this.legacyType = legacyType; } /** @@ -68,7 +68,7 @@ public class NetworkRequest implements Parcelable { public NetworkRequest(NetworkRequest that) { networkCapabilities = new NetworkCapabilities(that.networkCapabilities); requestId = that.requestId; - needsBroadcasts = that.needsBroadcasts; + this.legacyType = that.legacyType; } // implement the Parcelable interface @@ -77,16 +77,16 @@ public class NetworkRequest implements Parcelable { } public void writeToParcel(Parcel dest, int flags) { dest.writeParcelable(networkCapabilities, flags); - dest.writeInt(needsBroadcasts ? 1 : 0); + dest.writeInt(legacyType); dest.writeInt(requestId); } public static final Creator CREATOR = new Creator() { public NetworkRequest createFromParcel(Parcel in) { NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null); - boolean needsBroadcasts = (in.readInt() == 1); + int legacyType = in.readInt(); int requestId = in.readInt(); - NetworkRequest result = new NetworkRequest(nc, needsBroadcasts, requestId); + NetworkRequest result = new NetworkRequest(nc, legacyType, requestId); return result; } public NetworkRequest[] newArray(int size) { @@ -95,14 +95,14 @@ public class NetworkRequest implements Parcelable { }; public String toString() { - return "NetworkRequest [ id=" + requestId + ", needsBroadcasts=" + needsBroadcasts + + return "NetworkRequest [ id=" + requestId + ", legacyType=" + legacyType + ", " + networkCapabilities.toString() + " ]"; } public boolean equals(Object obj) { if (obj instanceof NetworkRequest == false) return false; NetworkRequest that = (NetworkRequest)obj; - return (that.needsBroadcasts == this.needsBroadcasts && + return (that.legacyType == this.legacyType && that.requestId == this.requestId && ((that.networkCapabilities == null && this.networkCapabilities == null) || (that.networkCapabilities != null && @@ -110,7 +110,7 @@ public class NetworkRequest implements Parcelable { } public int hashCode() { - return requestId + (needsBroadcasts ? 1013 : 2026) + + return requestId + (legacyType * 1013) + (networkCapabilities.hashCode() * 1051); } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 22ecd33c4e..b2b4217140 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -258,17 +258,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private NetworkStateTracker mNetTrackers[]; - /** - * Holds references to all NetworkAgentInfos claiming to support the legacy - * NetworkType. We used to have a static set of of NetworkStateTrackers - * for each network type. This is the new model. - * Supports synchronous inspection of state. - * These are built out at startup such that an unsupported network - * doesn't get an ArrayList instance, making this a tristate: - * unsupported, supported but not active and active. - */ - private ArrayList mNetworkAgentInfoForType[]; - /* Handles captive portal check on a network */ private CaptivePortalTracker mCaptivePortalTracker; @@ -516,6 +505,118 @@ public class ConnectivityService extends IConnectivityManager.Stub { private static final int UID_UNUSED = -1; + /** + * Implements support for the legacy "one network per network type" model. + * + * We used to have a static array of NetworkStateTrackers, one for each + * network type, but that doesn't work any more now that we can have, + * for example, more that one wifi network. This class stores all the + * NetworkAgentInfo objects that support a given type, but the legacy + * API will only see the first one. + * + * It serves two main purposes: + * + * 1. Provide information about "the network for a given type" (since this + * API only supports one). + * 2. Send legacy connectivity change broadcasts. Broadcasts are sent if + * the first network for a given type changes, or if the default network + * changes. + */ + private class LegacyTypeTracker { + /** + * Array of lists, one per legacy network type (e.g., TYPE_MOBILE_MMS). + * Each list holds references to all NetworkAgentInfos that are used to + * satisfy requests for that network type. + * + * This array is built out at startup such that an unsupported network + * doesn't get an ArrayList instance, making this a tristate: + * unsupported, supported but not active and active. + * + * The actual lists are populated when we scan the network types that + * are supported on this device. + */ + private ArrayList mTypeLists[]; + + public LegacyTypeTracker() { + mTypeLists = (ArrayList[]) + new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1]; + } + + public void addSupportedType(int type) { + if (mTypeLists[type] != null) { + throw new IllegalStateException( + "legacy list for type " + type + "already initialized"); + } + mTypeLists[type] = new ArrayList(); + } + + private boolean isDefaultNetwork(NetworkAgentInfo nai) { + return mNetworkForRequestId.get(mDefaultRequest.requestId) == nai; + } + + public boolean isTypeSupported(int type) { + return isNetworkTypeValid(type) && mTypeLists[type] != null; + } + + public NetworkAgentInfo getNetworkForType(int type) { + if (isTypeSupported(type) && !mTypeLists[type].isEmpty()) { + return mTypeLists[type].get(0); + } else { + return null; + } + } + + public void add(int type, NetworkAgentInfo nai) { + if (!isTypeSupported(type)) { + return; // Invalid network type. + } + if (VDBG) log("Adding agent " + nai + " for legacy network type " + type); + + ArrayList list = mTypeLists[type]; + if (list.contains(nai)) { + loge("Attempting to register duplicate agent for type " + type + ": " + nai); + return; + } + + if (list.isEmpty() || isDefaultNetwork(nai)) { + if (VDBG) log("Sending connected broadcast for type " + type + + "isDefaultNetwork=" + isDefaultNetwork(nai)); + sendLegacyNetworkBroadcast(nai, true, type); + } + list.add(nai); + } + + public void remove(NetworkAgentInfo nai) { + if (VDBG) log("Removing agent " + nai); + for (int type = 0; type < mTypeLists.length; type++) { + ArrayList list = mTypeLists[type]; + if (list == null || list.isEmpty()) { + continue; + } + + boolean wasFirstNetwork = false; + if (list.get(0).equals(nai)) { + // This network was the first in the list. Send broadcast. + wasFirstNetwork = true; + } + list.remove(nai); + + if (wasFirstNetwork || isDefaultNetwork(nai)) { + if (VDBG) log("Sending disconnected broadcast for type " + type + + "isDefaultNetwork=" + isDefaultNetwork(nai)); + sendLegacyNetworkBroadcast(nai, false, type); + } + + if (!list.isEmpty() && wasFirstNetwork) { + if (VDBG) log("Other network available for type " + type + + ", sending connected broadcast"); + sendLegacyNetworkBroadcast(list.get(0), false, type); + } + } + } + } + private LegacyTypeTracker mLegacyTypeTracker = new LegacyTypeTracker(); + public ConnectivityService(Context context, INetworkManagementService netd, INetworkStatsService statsService, INetworkPolicyManager policyManager) { // Currently, omitting a NetworkFactory will create one internally @@ -531,7 +632,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - mDefaultRequest = new NetworkRequest(netCap, true, nextNetworkRequestId()); + mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId()); NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(), NetworkRequestInfo.REQUEST); mNetworkRequests.put(mDefaultRequest, nri); @@ -587,9 +688,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( com.android.internal.R.integer.config_networkTransitionTimeout); - mNetworkAgentInfoForType = (ArrayList[]) - new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE + 1]; - mNetTrackers = new NetworkStateTracker[ ConnectivityManager.MAX_NETWORK_TYPE+1]; mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1]; @@ -644,7 +742,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { "radio " + n.radio + " in network type " + n.type); continue; } - mNetworkAgentInfoForType[n.type] = new ArrayList(); + mLegacyTypeTracker.addSupportedType(n.type); mNetConfigs[n.type] = n; mNetworksDefined++; @@ -3125,11 +3223,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { loge("Error connecting NetworkAgent"); NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo); - try { - mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai); - } catch (NullPointerException e) {} if (nai != null) { mNetworkForNetId.remove(nai.network.netId); + mLegacyTypeTracker.remove(nai); } } } @@ -3160,10 +3256,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED); mNetworkAgentInfos.remove(msg.replyTo); updateClat(null, nai.linkProperties, nai); - try { - mNetworkAgentInfoForType[nai.networkInfo.getType()].remove(nai); - } catch (NullPointerException e) {} - + mLegacyTypeTracker.remove(nai); mNetworkForNetId.remove(nai.network.netId); // Since we've lost the network, go through all the requests that // it was satisfying and see if any other factory can satisfy them. @@ -3173,7 +3266,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId); if (VDBG) { log(" checking request " + request + ", currentNetwork = " + - currentNetwork != null ? currentNetwork.name() : "null"); + (currentNetwork != null ? currentNetwork.name() : "null")); } if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) { mNetworkForRequestId.remove(request.requestId); @@ -3223,6 +3316,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (bestNetwork != null) { if (VDBG) log("using " + bestNetwork.name()); bestNetwork.addRequest(nri.request); + int legacyType = nri.request.legacyType; + if (legacyType != TYPE_NONE) { + mLegacyTypeTracker.add(legacyType, bestNetwork); + } notifyNetworkCallback(bestNetwork, nri); score = bestNetwork.currentScore; } @@ -5300,7 +5397,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { @Override public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, - Messenger messenger, int timeoutSec, IBinder binder, boolean legacy) { + Messenger messenger, int timeoutSec, IBinder binder, int legacyType) { if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) == false) { enforceConnectivityInternalPermission(); @@ -5312,7 +5409,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { throw new IllegalArgumentException("Bad timeout specified"); } NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities), legacy, nextNetworkRequestId()); + networkCapabilities), legacyType, nextNetworkRequestId()); if (DBG) log("requestNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.REQUEST); @@ -5338,7 +5435,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { enforceAccessPermission(); NetworkRequest networkRequest = new NetworkRequest(new NetworkCapabilities( - networkCapabilities), false, nextNetworkRequestId()); + networkCapabilities), TYPE_NONE, nextNetworkRequestId()); if (DBG) log("listenForNetwork for " + networkRequest); NetworkRequestInfo nri = new NetworkRequestInfo(messenger, networkRequest, binder, NetworkRequestInfo.LISTEN); @@ -5420,11 +5517,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleRegisterNetworkAgent(NetworkAgentInfo na) { if (VDBG) log("Got NetworkAgent Messenger"); mNetworkAgentInfos.put(na.messenger, na); - try { - mNetworkAgentInfoForType[na.networkInfo.getType()].add(na); - } catch (NullPointerException e) { - loge("registered NetworkAgent for unsupported type: " + na); - } mNetworkForNetId.put(na.network.netId, na); na.asyncChannel.connect(mContext, mTrackerHandler, na.messenger); NetworkInfo networkInfo = na.networkInfo; @@ -5681,6 +5773,10 @@ public class ConnectivityService extends IConnectivityManager.Stub { } mNetworkForRequestId.put(nri.request.requestId, newNetwork); newNetwork.addRequest(nri.request); + int legacyType = nri.request.legacyType; + if (legacyType != TYPE_NONE) { + mLegacyTypeTracker.add(legacyType, newNetwork); + } keep = true; // TODO - this could get expensive if we have alot of requests for this // network. Think about if there is a way to reduce this. Push @@ -5694,6 +5790,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { setDefaultDnsSystemProperties(new ArrayList()); } + mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), newNetwork); } } } @@ -5828,13 +5925,53 @@ public class ConnectivityService extends IConnectivityManager.Stub { // } else if (nai.networkMonitor.isEvaluating()) { // notifyType = NetworkCallbacks.callCallbackForRequest(request, nai, notifyType); // } - if (nri.request.needsBroadcasts) { - // TODO -// sendNetworkBroadcast(nai, notifyType); - } callCallbackForRequest(nri, nai, notifyType); } + private void sendLegacyNetworkBroadcast(NetworkAgentInfo nai, boolean connected, int type) { + if (connected) { + NetworkInfo info = new NetworkInfo(nai.networkInfo); + info.setType(type); + sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); + } else { + NetworkInfo info = new NetworkInfo(nai.networkInfo); + info.setType(type); + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); + if (info.isFailover()) { + intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); + nai.networkInfo.setFailover(false); + } + if (info.getReason() != null) { + intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); + } + if (info.getExtraInfo() != null) { + intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); + } + NetworkAgentInfo newDefaultAgent = null; + if (nai.networkRequests.get(mDefaultRequest.requestId) != null) { + newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId); + if (newDefaultAgent != null) { + intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, + newDefaultAgent.networkInfo); + } else { + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); + } + } + intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, + mDefaultInetConditionPublished); + final Intent immediateIntent = new Intent(intent); + immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); + sendStickyBroadcast(immediateIntent); + sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); + if (newDefaultAgent != null) { + sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo, + getConnectivityChangeDelay()); + } + } + } + protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType) { if (VDBG) log("notifyType " + notifyType + " for " + networkAgent.name()); for (int i = 0; i < networkAgent.networkRequests.size(); i++) { @@ -5843,76 +5980,33 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (VDBG) log(" sending notification for " + nr); callCallbackForRequest(nri, networkAgent, notifyType); } - if (networkAgent.needsBroadcasts) { - if (notifyType == ConnectivityManager.CALLBACK_AVAILABLE) { - sendConnectedBroadcastDelayed(networkAgent.networkInfo, - getConnectivityChangeDelay()); - } else if (notifyType == ConnectivityManager.CALLBACK_LOST) { - NetworkInfo info = new NetworkInfo(networkAgent.networkInfo); - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - networkAgent.networkInfo.setFailover(false); - } - if (info.getReason() != null) { - intent.putExtra(ConnectivityManager.EXTRA_REASON, info.getReason()); - } - if (info.getExtraInfo() != null) { - intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); - } - NetworkAgentInfo newDefaultAgent = null; - if (networkAgent.networkRequests.get(mDefaultRequest.requestId) != null) { - newDefaultAgent = mNetworkForRequestId.get(mDefaultRequest.requestId); - if (newDefaultAgent != null) { - intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, - newDefaultAgent.networkInfo); - } else { - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } - } - intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, - mDefaultInetConditionPublished); - final Intent immediateIntent = new Intent(intent); - immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); - sendStickyBroadcast(immediateIntent); - sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); - if (newDefaultAgent != null) { - sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo, - getConnectivityChangeDelay()); - } - } - } } private LinkProperties getLinkPropertiesForTypeInternal(int networkType) { - ArrayList list = mNetworkAgentInfoForType[networkType]; - if (list == null) return null; - try { - return new LinkProperties(list.get(0).linkProperties); - } catch (IndexOutOfBoundsException e) { - return new LinkProperties(); - } + NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); + return (nai != null) ? + new LinkProperties(nai.linkProperties) : + new LinkProperties(); } private NetworkInfo getNetworkInfoForType(int networkType) { - ArrayList list = mNetworkAgentInfoForType[networkType]; - if (list == null) return null; - try { - return new NetworkInfo(list.get(0).networkInfo); - } catch (IndexOutOfBoundsException e) { - return new NetworkInfo(networkType, 0, "Unknown", ""); + if (!mLegacyTypeTracker.isTypeSupported(networkType)) + return null; + + NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); + if (nai != null) { + NetworkInfo result = new NetworkInfo(nai.networkInfo); + result.setType(networkType); + return result; + } else { + return new NetworkInfo(networkType, 0, "Unknown", ""); } } private NetworkCapabilities getNetworkCapabilitiesForType(int networkType) { - ArrayList list = mNetworkAgentInfoForType[networkType]; - if (list == null) return null; - try { - return new NetworkCapabilities(list.get(0).networkCapabilities); - } catch (IndexOutOfBoundsException e) { - return new NetworkCapabilities(); - } + NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); + return (nai != null) ? + new NetworkCapabilities(nai.networkCapabilities) : + new NetworkCapabilities(); } } diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java index e9f968377f..b03c247e80 100644 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java @@ -45,18 +45,6 @@ public class NetworkAgentInfo { public int currentScore; public final NetworkMonitor networkMonitor; - /** - * Indicates we need to send CONNECTIVITY_ACTION broadcasts for this network. - * For example the built-in default network request and any requsts coming from - * the deprecated startUsingNetworkFeature API will have this set. Networks - * responding to the new requestNetwork API will rely on point to point callbacks. - * - * Gets set if any legacy requests get affiliated with this network and - * stays set for life so we send disconnected bcasts to match the connected, - * even if the legacy request has moved on. - */ - public boolean needsBroadcasts = false; - // The list of NetworkRequests being satisfied by this Network. public final SparseArray networkRequests = new SparseArray(); public final ArrayList networkLingered = new ArrayList(); @@ -78,8 +66,6 @@ public class NetworkAgentInfo { } public void addRequest(NetworkRequest networkRequest) { - if (networkRequest.needsBroadcasts) needsBroadcasts = true; - networkRequests.put(networkRequest.requestId, networkRequest); } From ae5370cab5e3b377b448593765234569660e2467 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 3 Jun 2014 17:22:11 -0700 Subject: [PATCH 280/296] Fix legacy APIs. Two fixes. First make sure we mark the request as handled by the network handling it. Second, convert ensureRouteToHostForAddress to use the new legacyNetworkForType. bug:14993207 Change-Id: I230968938ca0ed91f834b36a2af60caff2eab682 --- .../android/server/ConnectivityService.java | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b2b4217140..abb8cc5e25 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1754,31 +1754,34 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) log("requestRouteToHostAddress on invalid network: " + networkType); return false; } - NetworkStateTracker tracker = mNetTrackers[networkType]; - DetailedState netState = DetailedState.DISCONNECTED; - if (tracker != null) { - netState = tracker.getNetworkInfo().getDetailedState(); + + NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); + if (nai == null) { + if (mLegacyTypeTracker.isTypeSupported(networkType) == false) { + if (DBG) log("requestRouteToHostAddress on unsupported network: " + networkType); + } else { + if (DBG) log("requestRouteToHostAddress on down network: " + networkType); + } + return false; } + DetailedState netState = nai.networkInfo.getDetailedState(); + if ((netState != DetailedState.CONNECTED && - netState != DetailedState.CAPTIVE_PORTAL_CHECK) || - tracker.isTeardownRequested()) { + netState != DetailedState.CAPTIVE_PORTAL_CHECK)) { if (VDBG) { log("requestRouteToHostAddress on down network " + "(" + networkType + ") - dropped" - + " tracker=" + tracker - + " netState=" + netState - + " isTeardownRequested=" - + ((tracker != null) ? tracker.isTeardownRequested() : "tracker:null")); + + " netState=" + netState); } return false; } final int uid = Binder.getCallingUid(); final long token = Binder.clearCallingIdentity(); try { - LinkProperties lp = tracker.getLinkProperties(); + LinkProperties lp = nai.linkProperties; boolean ok = modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, - tracker.getNetwork().netId, uid); + nai.network.netId, uid); if (DBG) log("requestRouteToHostAddress ok=" + ok); return ok; } finally { @@ -3316,6 +3319,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (bestNetwork != null) { if (VDBG) log("using " + bestNetwork.name()); bestNetwork.addRequest(nri.request); + mNetworkForRequestId.put(nri.request.requestId, bestNetwork); int legacyType = nri.request.legacyType; if (legacyType != TYPE_NONE) { mLegacyTypeTracker.add(legacyType, bestNetwork); From 21c178d0a6c5249dffaeebae52df423c9069c818 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 4 Jun 2014 12:20:06 +0900 Subject: [PATCH 281/296] Make requests for restricted networks not require unrestricted access. Currently, calling startUsingNetworkFeature for a restricted APN type (e.g., IMS or FOTA) will create a request that requires NET_CAPABILITY_NOT_RESTRICTED. Because these APNs are restricted, when we bring them up we conclude that it does not match the unrestricted requirement, and we tear them down. 1. Clear the NET_CAPABILITY_NOT_RESTRICTED capability when creating requests in startUsingNetworkFeature. 2. Refactor the code to a common function so this cannot happen again. Bug: 15191336 Change-Id: Id1ec79c58ff79b1a83457ffaecc57d50b61ed4e4 --- .../java/android/net/ConnectivityManager.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index a48a388820..c4cbdd54d2 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -870,6 +870,26 @@ public class ConnectivityManager { return 1; } + /** + * Removes the NET_CAPABILITY_NOT_RESTRICTED capability from the given + * NetworkCapabilities object if it lists any capabilities that are + * typically provided by retricted networks. + * @hide + */ + public static void maybeMarkCapabilitiesRestricted(NetworkCapabilities nc) { + for (Integer capability: nc.getNetworkCapabilities()) { + switch (capability.intValue()) { + case NetworkCapabilities.NET_CAPABILITY_CBS: + case NetworkCapabilities.NET_CAPABILITY_DUN: + case NetworkCapabilities.NET_CAPABILITY_FOTA: + case NetworkCapabilities.NET_CAPABILITY_IA: + case NetworkCapabilities.NET_CAPABILITY_IMS: + nc.removeNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + break; + } + } + } + private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { if (networkType == TYPE_MOBILE) { int cap = -1; @@ -893,12 +913,14 @@ public class ConnectivityManager { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); netCap.addNetworkCapability(cap); + maybeMarkCapabilitiesRestricted(netCap); return netCap; } else if (networkType == TYPE_WIFI) { if ("p2p".equals(feature)) { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); + maybeMarkCapabilitiesRestricted(netCap); return netCap; } } From 2606df87905f55d3cfc3397c0caeaf92541cfbdd Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 4 Jun 2014 19:59:21 +0900 Subject: [PATCH 282/296] Call a network restricted only if all capabilities are restricted When guessing whether a network is restricted or not (e.g., when constructing a NetworkCapabilities object from an APN type, or when constructing a request using startUsingNetworkFeature), only assume the network is restricted if all the capabilities it provides are typically provided by restricted networks (e.g., IMS, FOTA, etc.). Previous code would conclude a network was restricted even if it supported one "restricted" capability, so for example an APN that provides both Internet connectivity and FOTA was marked as restricted. This caused it to become ineligible to provide the default Internet connection, because that must be unrestricted. Also expand the list of restricted APN types a bit. Bug: 15417453 Change-Id: I8c385f2cc83c695449dc8cf943d918321716fe58 --- .../java/android/net/ConnectivityManager.java | 24 +++++++++++++++---- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index c4cbdd54d2..b96f16646c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -872,22 +872,36 @@ public class ConnectivityManager { /** * Removes the NET_CAPABILITY_NOT_RESTRICTED capability from the given - * NetworkCapabilities object if it lists any capabilities that are - * typically provided by retricted networks. + * NetworkCapabilities object if all the capabilities it provides are + * typically provided by restricted networks. + * + * TODO: consider: + * - Moving to NetworkCapabilities + * - Renaming it to guessRestrictedCapability and make it set the + * restricted capability bit in addition to clearing it. * @hide */ public static void maybeMarkCapabilitiesRestricted(NetworkCapabilities nc) { - for (Integer capability: nc.getNetworkCapabilities()) { + for (Integer capability : nc.getNetworkCapabilities()) { switch (capability.intValue()) { case NetworkCapabilities.NET_CAPABILITY_CBS: case NetworkCapabilities.NET_CAPABILITY_DUN: + case NetworkCapabilities.NET_CAPABILITY_EIMS: case NetworkCapabilities.NET_CAPABILITY_FOTA: case NetworkCapabilities.NET_CAPABILITY_IA: case NetworkCapabilities.NET_CAPABILITY_IMS: - nc.removeNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - break; + case NetworkCapabilities.NET_CAPABILITY_RCS: + case NetworkCapabilities.NET_CAPABILITY_XCAP: + continue; + default: + // At least one capability usually provided by unrestricted + // networks. Conclude that this network is unrestricted. + return; } } + // All the capabilities are typically provided by restricted networks. + // Conclude that this network is restricted. + nc.removeNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { From 85230629dfd3e29aa3f4d19517457ea1fc3dc207 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 3 Jun 2014 16:43:57 -0700 Subject: [PATCH 283/296] Report new network scores back to factories. This is a first order approx of what we want - should probably be good enough in most cases. bug:15277751 Change-Id: I10e3b25f6ad5c7e022ba966ed514d4e6a999180d --- .../android/server/ConnectivityService.java | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b2b4217140..8451e732cc 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3100,7 +3100,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } Integer score = (Integer) msg.obj; - updateNetworkScore(nai, score); + if (score != null) updateNetworkScore(nai, score.intValue()); break; } case NetworkMonitor.EVENT_NETWORK_VALIDATED: { @@ -5911,9 +5911,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void updateNetworkScore(NetworkAgentInfo nai, Integer scoreInteger) { - int score = scoreInteger.intValue(); - // TODO + private void updateNetworkScore(NetworkAgentInfo nai, int score) { + if (DBG) log("updateNetworkScore for " + nai.name() + " to " + score); + + nai.currentScore = score; + + // TODO - This will not do the right thing if this network is lowering + // its score and has requests that can be served by other + // currently-active networks, or if the network is increasing its + // score and other networks have requests that can be better served + // by this network. + // + // Really we want to see if any of our requests migrate to other + // active/lingered networks and if any other requests migrate to us (depending + // on increasing/decreasing currentScore. That's a bit of work and probably our + // score checking/network allocation code needs to be modularized so we can understand + // (see handleConnectionValided for an example). + // + // As a first order approx, lets just advertise the new score to factories. If + // somebody can beat it they will nominate a network and our normal net replacement + // code will fire. + for (int i = 0; i < nai.networkRequests.size(); i++) { + NetworkRequest nr = nai.networkRequests.valueAt(i); + sendUpdatedScoreToFactories(nr, score); + } } // notify only this one new request of the current state From 63d11e519f9dee282caab157ee0d8b06cced85f4 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Tue, 3 Jun 2014 16:43:57 -0700 Subject: [PATCH 284/296] DO NOT MERGE Report new network scores back to factories. This is a first order approx of what we want - should probably be good enough in most cases. bug:15277751 Change-Id: I10e3b25f6ad5c7e022ba966ed514d4e6a999180d (cherry picked from commit 94a5c61cb82401dd777d0a7ac43183d92d955323) --- .../android/server/ConnectivityService.java | 29 ++++++++++++++++--- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index abb8cc5e25..bd4576115b 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3103,7 +3103,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { break; } Integer score = (Integer) msg.obj; - updateNetworkScore(nai, score); + if (score != null) updateNetworkScore(nai, score.intValue()); break; } case NetworkMonitor.EVENT_NETWORK_VALIDATED: { @@ -5915,9 +5915,30 @@ public class ConnectivityService extends IConnectivityManager.Stub { } } - private void updateNetworkScore(NetworkAgentInfo nai, Integer scoreInteger) { - int score = scoreInteger.intValue(); - // TODO + private void updateNetworkScore(NetworkAgentInfo nai, int score) { + if (DBG) log("updateNetworkScore for " + nai.name() + " to " + score); + + nai.currentScore = score; + + // TODO - This will not do the right thing if this network is lowering + // its score and has requests that can be served by other + // currently-active networks, or if the network is increasing its + // score and other networks have requests that can be better served + // by this network. + // + // Really we want to see if any of our requests migrate to other + // active/lingered networks and if any other requests migrate to us (depending + // on increasing/decreasing currentScore. That's a bit of work and probably our + // score checking/network allocation code needs to be modularized so we can understand + // (see handleConnectionValided for an example). + // + // As a first order approx, lets just advertise the new score to factories. If + // somebody can beat it they will nominate a network and our normal net replacement + // code will fire. + for (int i = 0; i < nai.networkRequests.size(); i++) { + NetworkRequest nr = nai.networkRequests.valueAt(i); + sendUpdatedScoreToFactories(nr, score); + } } // notify only this one new request of the current state From 4a52c697d24a88dea1d609313fd820bbea471383 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Thu, 5 Jun 2014 16:39:28 -0700 Subject: [PATCH 285/296] Fix the marking of restricted network requests Need to realized that the NOT_RESTRICTED bit is set by default, so if looking at what bits are set to decide if we want NOT_RESTRICTED cleared, we need to ignore the bit itself. bug:15456019 Change-Id: Iecae598f47ec7306d475e2262bb1c452ddf0fc75 --- core/java/android/net/ConnectivityManager.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index b96f16646c..59732eee6c 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -892,6 +892,7 @@ public class ConnectivityManager { case NetworkCapabilities.NET_CAPABILITY_IMS: case NetworkCapabilities.NET_CAPABILITY_RCS: case NetworkCapabilities.NET_CAPABILITY_XCAP: + case NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED: //there by default continue; default: // At least one capability usually provided by unrestricted From 8cdda64b9c1b73ed841003d8d3ae9c7a9b2c7daa Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Thu, 29 May 2014 10:12:39 -0400 Subject: [PATCH 286/296] Apply API review to android.net.Network: - socketFactory() renamed to getSocketFactory() - Make sure bindProcess() documentation points developers to getSocketFactory() as the preferred approach - Move bindProcess() and unbindProcess() to ConnectivityManager.setProcessBoundNetwork() -- passing null clears it. - Move getProcessBoundNetwork() to ConnectivityManager.getProcessBoundNetwork(). Bug:15142362 Bug:13885501 Change-Id: Ia55c59d52e1ec8bf10dd0d9d037bd04c0998bc71 --- .../java/android/net/ConnectivityManager.java | 69 +++++++++++++++++-- core/java/android/net/Network.java | 55 +-------------- core/java/android/net/NetworkUtils.java | 2 +- 3 files changed, 69 insertions(+), 57 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 59732eee6c..2740266897 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -22,6 +22,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.net.NetworkUtils; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Handler; @@ -982,13 +983,13 @@ public class ConnectivityManager { public void onAvailable(NetworkRequest request, Network network) { currentNetwork = network; Log.d(TAG, "startUsingNetworkFeature got Network:" + network); - network.bindProcessForHostResolution(); + setProcessDefaultNetworkForHostResolution(network); } @Override public void onLost(NetworkRequest request, Network network) { if (network.equals(currentNetwork)) { currentNetwork = null; - network.unbindProcessForHostResolution(); + setProcessDefaultNetworkForHostResolution(null); } Log.d(TAG, "startUsingNetworkFeature lost Network:" + network); } @@ -1072,7 +1073,7 @@ public class ConnectivityManager { * @return {@code true} on success, {@code false} on failure * * @deprecated Deprecated in favor of the {@link #requestNetwork}, - * {@link Network#bindProcess} and {@link Network#socketFactory} api. + * {@link #setProcessDefaultNetwork} and {@link Network#getSocketFactory} api. */ public boolean requestRouteToHost(int networkType, int hostAddress) { InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); @@ -1096,7 +1097,7 @@ public class ConnectivityManager { * @return {@code true} on success, {@code false} on failure * @hide * @deprecated Deprecated in favor of the {@link #requestNetwork} and - * {@link Network#bindProcess} api. + * {@link #setProcessDefaultNetwork} api. */ public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { byte[] address = hostAddress.getAddress(); @@ -2348,4 +2349,64 @@ public class ConnectivityManager { mService.releaseNetworkRequest(networkRequest); } catch (RemoteException e) {} } + + /** + * Binds the current process to {@code network}. All Sockets created in the future + * (and not explicitly bound via a bound SocketFactory from + * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to + * {@code network}. All host name resolutions will be limited to {@code network} as well. + * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to + * work and all host name resolutions will fail. This is by design so an application doesn't + * accidentally use Sockets it thinks are still bound to a particular {@link Network}. + * To clear binding pass {@code null} for {@code network}. Using individually bound + * Sockets created by Network.getSocketFactory().createSocket() and + * performing network-specific host name resolutions via + * {@link Network#getAllByName Network.getAllByName} is preferred to calling + * {@code setProcessDefaultNetwork}. + * + * @param network The {@link Network} to bind the current process to, or {@code null} to clear + * the current binding. + * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. + */ + public static boolean setProcessDefaultNetwork(Network network) { + if (network == null) { + NetworkUtils.unbindProcessToNetwork(); + } else { + NetworkUtils.bindProcessToNetwork(network.netId); + } + // TODO fix return value + return true; + } + + /** + * Returns the {@link Network} currently bound to this process via + * {@link #setProcessDefaultNetwork}, or {@code null} if no {@link Network} is explicitly bound. + * + * @return {@code Network} to which this process is bound, or {@code null}. + */ + public static Network getProcessDefaultNetwork() { + int netId = NetworkUtils.getNetworkBoundToProcess(); + if (netId == 0) return null; + return new Network(netId); + } + + /** + * Binds host resolutions performed by this process to {@code network}. + * {@link #setProcessDefaultNetwork} takes precedence over this setting. + * + * @param network The {@link Network} to bind host resolutions from the current process to, or + * {@code null} to clear the current binding. + * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. + * @hide + * @deprecated This is strictly for legacy usage to support {@link #startUsingNetworkFeature}. + */ + public static boolean setProcessDefaultNetworkForHostResolution(Network network) { + if (network == null) { + NetworkUtils.unbindProcessToNetworkForHostResolution(); + } else { + NetworkUtils.bindProcessToNetworkForHostResolution(network.netId); + } + // TODO hook up the return value. + return true; + } } diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 64516e62d1..d933f26c78 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -32,7 +32,8 @@ import javax.net.SocketFactory; * {@link ConnectivityManager.NetworkCallbackListener} in response to * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}. * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis - * through a targeted {@link SocketFactory} or process-wide via {@link #bindProcess}. + * through a targeted {@link SocketFactory} or process-wide via + * {@link ConnectivityManager#setProcessDefaultNetwork}. */ public class Network implements Parcelable { @@ -160,63 +161,13 @@ public class Network implements Parcelable { * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this * {@code Network}. */ - public SocketFactory socketFactory() { + public SocketFactory getSocketFactory() { if (mNetworkBoundSocketFactory == null) { mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); } return mNetworkBoundSocketFactory; } - /** - * Binds the current process to this network. All sockets created in the future (and not - * explicitly bound via a bound {@link SocketFactory} (see {@link Network#socketFactory}) - * will be bound to this network. Note that if this {@code Network} ever disconnects - * all sockets created in this way will cease to work. This is by design so an application - * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}. - */ - public void bindProcess() { - NetworkUtils.bindProcessToNetwork(netId); - } - - /** - * Binds host resolutions performed by this process to this network. {@link #bindProcess} - * takes precedence over this setting. - * - * @hide - * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). - */ - public void bindProcessForHostResolution() { - NetworkUtils.bindProcessToNetworkForHostResolution(netId); - } - - /** - * Clears any process specific {@link Network} binding for host resolution. This does - * not clear bindings enacted via {@link #bindProcess}. - * - * @hide - * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). - */ - public void unbindProcessForHostResolution() { - NetworkUtils.unbindProcessToNetworkForHostResolution(); - } - - /** - * A static utility method to return any {@code Network} currently bound by this process. - * - * @return {@code Network} to which this process is bound. - */ - public static Network getProcessBoundNetwork() { - return new Network(NetworkUtils.getNetworkBoundToProcess()); - } - - /** - * Clear any process specific {@code Network} binding. This reverts a call to - * {@link Network#bindProcess}. - */ - public static void unbindProcess() { - NetworkUtils.unbindProcessToNetwork(); - } - // implement the Parcelable interface public int describeContents() { return 0; diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index edb32866d3..b02f88ec81 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -111,7 +111,7 @@ public class NetworkUtils { /** * Binds the current process to the network designated by {@code netId}. All sockets created * in the future (and not explicitly bound via a bound {@link SocketFactory} (see - * {@link Network#socketFactory}) will be bound to this network. Note that if this + * {@link Network#getSocketFactory}) will be bound to this network. Note that if this * {@code Network} ever disconnects all sockets created in this way will cease to work. This * is by design so an application doesn't accidentally use sockets it thinks are still bound to * a particular {@code Network}. From 69aceaf7f2cfdd25f47bbf8804106d5e4086f6f3 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 6 Jun 2014 10:30:11 -0700 Subject: [PATCH 287/296] Fix public API of LinkProperties. bug:15142362 Change-Id: I1457111da7d3bd09998f7e010febb8bb4c45c8bc --- core/java/android/net/LinkProperties.java | 86 +++++++++++-------- .../src/android/net/LinkPropertiesTest.java | 36 ++++---- .../android/server/ConnectivityService.java | 9 +- 3 files changed, 74 insertions(+), 57 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 3c366799f6..cff9025d74 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Hashtable; +import java.util.List; /** * Describes the properties of a network link. @@ -58,10 +59,12 @@ public class LinkProperties implements Parcelable { private Hashtable mStackedLinks = new Hashtable(); - // @hide + /** + * @hide + */ public static class CompareResult { - public Collection removed = new ArrayList(); - public Collection added = new ArrayList(); + public List removed = new ArrayList(); + public List added = new ArrayList(); @Override public String toString() { @@ -81,7 +84,7 @@ public class LinkProperties implements Parcelable { if (source != null) { mIfaceName = source.getInterfaceName(); for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l); - for (InetAddress i : source.getDnses()) mDnses.add(i); + for (InetAddress i : source.getDnsServers()) mDnses.add(i); mDomains = source.getDomains(); for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? @@ -98,6 +101,7 @@ public class LinkProperties implements Parcelable { * will have their interface changed to match this new value. * * @param iface The name of the network interface used for this link. + * @hide */ public void setInterfaceName(String iface) { mIfaceName = iface; @@ -117,9 +121,11 @@ public class LinkProperties implements Parcelable { return mIfaceName; } - // @hide - public Collection getAllInterfaceNames() { - Collection interfaceNames = new ArrayList(mStackedLinks.size() + 1); + /** + * @hide + */ + public List getAllInterfaceNames() { + List interfaceNames = new ArrayList(mStackedLinks.size() + 1); if (mIfaceName != null) interfaceNames.add(new String(mIfaceName)); for (LinkProperties stacked: mStackedLinks.values()) { interfaceNames.addAll(stacked.getAllInterfaceNames()); @@ -134,23 +140,23 @@ public class LinkProperties implements Parcelable { * prefix lengths for each address. This is a simplified utility alternative to * {@link LinkProperties#getLinkAddresses}. * - * @return An umodifiable {@link Collection} of {@link InetAddress} for this link. + * @return An umodifiable {@link List} of {@link InetAddress} for this link. * @hide */ - public Collection getAddresses() { - Collection addresses = new ArrayList(); + public List getAddresses() { + List addresses = new ArrayList(); for (LinkAddress linkAddress : mLinkAddresses) { addresses.add(linkAddress.getAddress()); } - return Collections.unmodifiableCollection(addresses); + return Collections.unmodifiableList(addresses); } /** * Returns all the addresses on this link and all the links stacked above it. * @hide */ - public Collection getAllAddresses() { - Collection addresses = new ArrayList(); + public List getAllAddresses() { + List addresses = new ArrayList(); for (LinkAddress linkAddress : mLinkAddresses) { addresses.add(linkAddress.getAddress()); } @@ -174,6 +180,7 @@ public class LinkProperties implements Parcelable { * same address/prefix does not already exist. If it does exist it is replaced. * @param address The {@code LinkAddress} to add. * @return true if {@code address} was added or updated, false otherwise. + * @hide */ public boolean addLinkAddress(LinkAddress address) { if (address == null) { @@ -200,6 +207,7 @@ public class LinkProperties implements Parcelable { * * @param toRemove A {@link LinkAddress} specifying the address to remove. * @return true if the address was removed, false if it did not exist. + * @hide */ public boolean removeLinkAddress(LinkAddress toRemove) { int i = findLinkAddressIndex(toRemove); @@ -214,18 +222,18 @@ public class LinkProperties implements Parcelable { * Returns all the {@link LinkAddress} on this link. Typically a link will have * one IPv4 address and one or more IPv6 addresses. * - * @return An unmodifiable {@link Collection} of {@link LinkAddress} for this link. + * @return An unmodifiable {@link List} of {@link LinkAddress} for this link. */ - public Collection getLinkAddresses() { - return Collections.unmodifiableCollection(mLinkAddresses); + public List getLinkAddresses() { + return Collections.unmodifiableList(mLinkAddresses); } /** * Returns all the addresses on this link and all the links stacked above it. * @hide */ - public Collection getAllLinkAddresses() { - Collection addresses = new ArrayList(); + public List getAllLinkAddresses() { + List addresses = new ArrayList(); addresses.addAll(mLinkAddresses); for (LinkProperties stacked: mStackedLinks.values()) { addresses.addAll(stacked.getAllLinkAddresses()); @@ -239,6 +247,7 @@ public class LinkProperties implements Parcelable { * * @param addresses The {@link Collection} of {@link LinkAddress} to set in this * object. + * @hide */ public void setLinkAddresses(Collection addresses) { mLinkAddresses.clear(); @@ -250,20 +259,21 @@ public class LinkProperties implements Parcelable { /** * Adds the given {@link InetAddress} to the list of DNS servers. * - * @param dns The {@link InetAddress} to add to the list of DNS servers. + * @param dnsServer The {@link InetAddress} to add to the list of DNS servers. + * @hide */ - public void addDns(InetAddress dns) { - if (dns != null) mDnses.add(dns); + public void addDnsServer(InetAddress dnsServer) { + if (dnsServer != null) mDnses.add(dnsServer); } /** * Returns all the {@link LinkAddress} for DNS servers on this link. * - * @return An umodifiable {@link Collection} of {@link InetAddress} for DNS servers on + * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on * this link. */ - public Collection getDnses() { - return Collections.unmodifiableCollection(mDnses); + public List getDnsServers() { + return Collections.unmodifiableList(mDnses); } /** @@ -271,6 +281,7 @@ public class LinkProperties implements Parcelable { * * @param domains A {@link String} listing in priority order the comma separated * domains to search when resolving host names on this link. + * @hide */ public void setDomains(String domains) { mDomains = domains; @@ -323,6 +334,7 @@ public class LinkProperties implements Parcelable { * proper course is to add either un-named or properly named {@link RouteInfo}. * * @param route A {@link RouteInfo} to add to this object. + * @hide */ public void addRoute(RouteInfo route) { if (route != null) { @@ -339,18 +351,18 @@ public class LinkProperties implements Parcelable { /** * Returns all the {@link RouteInfo} set on this link. * - * @return An unmodifiable {@link Collection} of {@link RouteInfo} for this link. + * @return An unmodifiable {@link List} of {@link RouteInfo} for this link. */ - public Collection getRoutes() { - return Collections.unmodifiableCollection(mRoutes); + public List getRoutes() { + return Collections.unmodifiableList(mRoutes); } /** * Returns all the routes on this link and all the links stacked above it. * @hide */ - public Collection getAllRoutes() { - Collection routes = new ArrayList(); + public List getAllRoutes() { + List routes = new ArrayList(); routes.addAll(mRoutes); for (LinkProperties stacked: mStackedLinks.values()) { routes.addAll(stacked.getAllRoutes()); @@ -364,6 +376,7 @@ public class LinkProperties implements Parcelable { * not enforce it and applications may ignore them. * * @param proxy A {@link ProxyInfo} defining the Http Proxy to use on this link. + * @hide */ public void setHttpProxy(ProxyInfo proxy) { mHttpProxy = proxy; @@ -419,16 +432,17 @@ public class LinkProperties implements Parcelable { * Returns all the links stacked on top of this link. * @hide */ - public Collection getStackedLinks() { - Collection stacked = new ArrayList(); + public List getStackedLinks() { + List stacked = new ArrayList(); for (LinkProperties link : mStackedLinks.values()) { stacked.add(new LinkProperties(link)); } - return Collections.unmodifiableCollection(stacked); + return Collections.unmodifiableList(stacked); } /** * Clears this object to its initial state. + * @hide */ public void clear() { mIfaceName = null; @@ -486,6 +500,7 @@ public class LinkProperties implements Parcelable { * Returns true if this link has an IPv4 address. * * @return {@code true} if there is an IPv4 address, {@code false} otherwise. + * @hide */ public boolean hasIPv4Address() { for (LinkAddress address : mLinkAddresses) { @@ -500,6 +515,7 @@ public class LinkProperties implements Parcelable { * Returns true if this link has an IPv6 address. * * @return {@code true} if there is an IPv6 address, {@code false} otherwise. + * @hide */ public boolean hasIPv6Address() { for (LinkAddress address : mLinkAddresses) { @@ -543,7 +559,7 @@ public class LinkProperties implements Parcelable { * @hide */ public boolean isIdenticalDnses(LinkProperties target) { - Collection targetDnses = target.getDnses(); + Collection targetDnses = target.getDnsServers(); String targetDomains = target.getDomains(); if (mDomains == null) { if (targetDomains != null) return false; @@ -696,7 +712,7 @@ public class LinkProperties implements Parcelable { result.removed = new ArrayList(mDnses); result.added.clear(); if (target != null) { - for (InetAddress newAddress : target.getDnses()) { + for (InetAddress newAddress : target.getDnsServers()) { if (! result.removed.remove(newAddress)) { result.added.add(newAddress); } @@ -831,7 +847,7 @@ public class LinkProperties implements Parcelable { addressCount = in.readInt(); for (int i=0; i dnses = p.getDnses(); + Collection dnses = p.getDnsServers(); int netId = nt.getNetwork().netId; if (mNetConfigs[netType].isDefault()) { String network = nt.getNetworkInfo().getTypeName(); @@ -5625,7 +5625,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) { if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) { - Collection dnses = newLp.getDnses(); + Collection dnses = newLp.getDnsServers(); if (dnses.size() == 0 && mDefaultDns != null) { dnses = new ArrayList(); dnses.add(mDefaultDns); @@ -5790,7 +5790,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { isNewDefault = true; updateActiveDefaultNetwork(newNetwork); if (newNetwork.linkProperties != null) { - setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnses()); + setDefaultDnsSystemProperties( + newNetwork.linkProperties.getDnsServers()); } else { setDefaultDnsSystemProperties(new ArrayList()); } From c4418f95e425f64f468429d64965b2ca78b91b6e Mon Sep 17 00:00:00 2001 From: Amit Mahajan Date: Fri, 6 Jun 2014 16:53:34 -0700 Subject: [PATCH 288/296] Handle provisioning APN by turning off/on radio. The change is specific to AT&T as they want no signaling from device during provisioning. I've tested following cases: - expired AT&T SIM to make sure provisioning flow works as expected. - airplane mode on/off with both active and expired AT&T SIM. - wifi <-> mobile transitions work okay. - LTE with Verizon SIM (basic sanity). bug: 13190133 Change-Id: I215963174ae6000ae71d1dda693f95413f3d6e81 --- .../com/android/server/ConnectivityService.java | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 41a0e6b9a6..3872674a50 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -4145,7 +4145,9 @@ public class ConnectivityService extends IConnectivityManager.Stub { mIsProvisioningNetwork.set(true); MobileDataStateTracker mdst = (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; - mdst.setInternalDataEnable(false); + + // Disable radio until user starts provisioning + mdst.setRadio(false); } else { if (DBG) log("CheckMp.onComplete: warm (no dns/tcp), no url"); } @@ -4651,17 +4653,24 @@ public class ConnectivityService extends IConnectivityManager.Stub { // Mark notification as not visible setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); - // If provisioning network handle as a special case, + // Check airplane mode + boolean isAirplaneModeOn = Settings.System.getInt(mContext.getContentResolver(), + Settings.Global.AIRPLANE_MODE_ON, 0) == 1; + // If provisioning network and not in airplane mode handle as a special case, // otherwise launch browser with the intent directly. - if (mIsProvisioningNetwork.get()) { + if (mIsProvisioningNetwork.get() && !isAirplaneModeOn) { if (DBG) log("handleMobileProvisioningAction: on prov network enable then launch"); + mIsProvisioningNetwork.set(false); mIsStartingProvisioning.set(true); MobileDataStateTracker mdst = (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; + // Radio was disabled on CMP_RESULT_CODE_PROVISIONING_NETWORK, enable it here + mdst.setRadio(true); mdst.setEnableFailFastMobileData(DctConstants.ENABLED); mdst.enableMobileProvisioning(url); } else { if (DBG) log("handleMobileProvisioningAction: not prov network, launch browser directly"); + mIsProvisioningNetwork.set(false); Intent newIntent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, Intent.CATEGORY_APP_BROWSER); newIntent.setData(Uri.parse(url)); From fc2e61014a2bdf24cef0116cc432ab6f8c285462 Mon Sep 17 00:00:00 2001 From: vandwalle Date: Mon, 2 Jun 2014 15:30:39 -0700 Subject: [PATCH 289/296] remember and report network score Change-Id: Iccb2ec603bc9c0d3cf1976d0cc3f343cb1096494 --- core/java/android/net/NetworkAgent.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index 7e8b1f1aca..3d0874beda 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -80,6 +80,11 @@ public abstract class NetworkAgent extends Handler { */ public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3; + /* centralize place where base network score, and network score scaling, will be + * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE + */ + public static final int WIFI_BASE_SCORE = 60; + /** * Sent by the NetworkAgent to ConnectivityService to pass the current * network score. From 887d7b1d5a077d9f89e4441207f3a8eaeb889043 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Tue, 3 Jun 2014 18:41:43 -0700 Subject: [PATCH 290/296] Add a new IpPrefix class and use it in RouteInfo. This change uses IpPrefix only in the public API and continues to use LinkAddress for everything else. It does not change the callers to use the new APIs, with the exception of changing all current uses of getDestination to getDestinationLinkAddress to make room for the new getDestination method that returns an IpPrefix. Based on Sreeram's earlier change: https://googleplex-android-review.git.corp.google.com/#/c/477874/ but a bit simplified and with a bit more documentation. Bug: 15142362 Bug: 13885501 Change-Id: Ib4cd96b22cbff4ea31bb26a7853989f50da8de4e --- core/java/android/net/IpPrefix.java | 173 ++++++++++++++++++ core/java/android/net/LinkProperties.java | 12 +- core/java/android/net/RouteInfo.java | 77 ++++++-- .../src/android/net/RouteInfoTest.java | 6 +- .../android/server/ConnectivityService.java | 4 +- 5 files changed, 253 insertions(+), 19 deletions(-) create mode 100644 core/java/android/net/IpPrefix.java diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java new file mode 100644 index 0000000000..dfe03849ae --- /dev/null +++ b/core/java/android/net/IpPrefix.java @@ -0,0 +1,173 @@ +/* + * 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; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; + +/** + * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a + * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of + * information: + * + *

            + *
          • A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix. + *
          • A prefix length. This specifies the length of the prefix by specifing the number of bits + * in the IP address, starting from the most significant bit in network byte order, that + * are constant for all addresses in the prefix. + *
          + * + * For example, the prefix 192.0.2.0/24 covers the 256 IPv4 addresses from + * 192.0.2.0 to 192.0.2.255, inclusive, and the prefix + * 2001:db8:1:2 covers the 2^64 IPv6 addresses from 2001:db8:1:2:: to + * 2001:db8:1:2:ffff:ffff:ffff:ffff, inclusive. + * + * Objects of this class are immutable. + */ +public class IpPrefix implements Parcelable { + private final byte[] address; // network byte order + private final int prefixLength; + + /** + * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in + * network byte order and a prefix length. + * + * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. + * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). + * + * @hide + */ + public IpPrefix(byte[] address, int prefixLength) { + if (address.length != 4 && address.length != 16) { + throw new IllegalArgumentException( + "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); + } + if (prefixLength < 0 || prefixLength > (address.length * 8)) { + throw new IllegalArgumentException("IpPrefix with " + address.length + + " bytes has invalid prefix length " + prefixLength); + } + this.address = address.clone(); + this.prefixLength = prefixLength; + // TODO: Validate that the non-prefix bits are zero + } + + /** + * @hide + */ + public IpPrefix(InetAddress address, int prefixLength) { + this(address.getAddress(), prefixLength); + } + + /** + * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two + * objects are equal if they have the same startAddress and prefixLength. + * + * @param obj the object to be tested for equality. + * @return {@code true} if both objects are equal, {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IpPrefix)) { + return false; + } + IpPrefix that = (IpPrefix) obj; + return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength; + } + + /** + * Gets the hashcode of the represented IP prefix. + * + * @return the appropriate hashcode value. + */ + @Override + public int hashCode() { + return Arrays.hashCode(address) + 11 * prefixLength; + } + + /** + * Returns a copy of the first IP address in the prefix. Modifying the returned object does not + * change this object's contents. + * + * @return the address in the form of a byte array. + */ + public InetAddress getAddress() { + try { + return InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte + // array is the wrong length, but we check that in the constructor. + return null; + } + } + + /** + * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth + * element). Modifying the returned array does not change this object's contents. + * + * @return the address in the form of a byte array. + */ + public byte[] getRawAddress() { + return address.clone(); + } + + /** + * Returns the prefix length of this {@code IpAddress}. + * + * @return the prefix length. + */ + public int getPrefixLength() { + return prefixLength; + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(address); + dest.writeInt(prefixLength); + } + + /** + * Implement the Parcelable interface. + * @hide + */ + public static final Creator CREATOR = + new Creator() { + public IpPrefix createFromParcel(Parcel in) { + byte[] address = in.createByteArray(); + int prefixLength = in.readInt(); + return new IpPrefix(address, prefixLength); + } + + public IpPrefix[] newArray(int size) { + return new IpPrefix[size]; + } + }; +} diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index cff9025d74..bb05936a16 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -77,9 +77,15 @@ public class LinkProperties implements Parcelable { } } + /** + * @hide + */ public LinkProperties() { } + /** + * @hide + */ public LinkProperties(LinkProperties source) { if (source != null) { mIfaceName = source.getInterfaceName(); @@ -267,7 +273,7 @@ public class LinkProperties implements Parcelable { } /** - * Returns all the {@link LinkAddress} for DNS servers on this link. + * Returns all the {@link InetAddress} for DNS servers on this link. * * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on * this link. @@ -477,12 +483,12 @@ public class LinkProperties implements Parcelable { String domainName = "Domains: " + mDomains; - String mtu = "MTU: " + mMtu; + String mtu = " MTU: " + mMtu; String routes = " Routes: ["; for (RouteInfo route : mRoutes) routes += route.toString() + ","; routes += "] "; - String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); + String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " "); String stacked = ""; if (mStackedLinks.values().size() > 0) { diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index ad8e4f7eec..a65523b236 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -35,10 +35,10 @@ import java.util.Objects; * * A route contains three pieces of information: *
            - *
          • a destination {@link LinkAddress} for directly-connected subnets. If this is - * {@code null} it indicates a default route of the address family (IPv4 or IPv6) + *
          • a destination {@link IpPrefix} specifying the network destinations covered by this route. + * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6) * implied by the gateway IP address. - *
          • a gateway {@link InetAddress} for default routes. If this is {@code null} it + *
          • a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it * indicates a directly-connected route. *
          • an interface (which may be unspecified). *
          @@ -49,6 +49,7 @@ import java.util.Objects; public class RouteInfo implements Parcelable { /** * The IP destination address for this route. + * TODO: Make this an IpPrefix. */ private final LinkAddress mDestination; @@ -80,6 +81,19 @@ public class RouteInfo implements Parcelable { * @param destination the destination prefix * @param gateway the IP address to route packets through * @param iface the interface name to send packets on + * + * TODO: Convert to use IpPrefix. + * + * @hide + */ + public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) { + this(destination == null ? null : + new LinkAddress(destination.getAddress(), destination.getPrefixLength()), + gateway, iface); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { if (destination == null) { @@ -128,8 +142,17 @@ public class RouteInfo implements Parcelable { *

          * Destination and gateway may not both be null. * - * @param destination the destination address and prefix in a {@link LinkAddress} + * @param destination the destination address and prefix in an {@link IpPrefix} * @param gateway the {@link InetAddress} to route packets through + * + * @hide + */ + public RouteInfo(IpPrefix destination, InetAddress gateway) { + this(destination, gateway, null); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination, InetAddress gateway) { this(destination, gateway, null); @@ -139,16 +162,27 @@ public class RouteInfo implements Parcelable { * Constructs a default {@code RouteInfo} object. * * @param gateway the {@link InetAddress} to route packets through + * + * @hide */ public RouteInfo(InetAddress gateway) { - this(null, gateway, null); + this((LinkAddress) null, gateway, null); } /** * Constructs a {@code RouteInfo} object representing a direct connected subnet. * - * @param destination the {@link LinkAddress} describing the address and prefix + * @param destination the {@link IpPrefix} describing the address and prefix * length of the subnet. + * + * @hide + */ + public RouteInfo(IpPrefix destination) { + this(destination, null, null); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination) { this(destination, null, null); @@ -194,11 +228,19 @@ public class RouteInfo implements Parcelable { } /** - * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}. + * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}. * - * @return {@link LinkAddress} specifying the destination. This is never {@code null}. + * @return {@link IpPrefix} specifying the destination. This is never {@code null}. */ - public LinkAddress getDestination() { + public IpPrefix getDestination() { + return new IpPrefix(mDestination.getAddress(), mDestination.getPrefixLength()); + } + + /** + * TODO: Convert callers to use IpPrefix and then remove. + * @hide + */ + public LinkAddress getDestinationLinkAddress() { return mDestination; } @@ -233,7 +275,8 @@ public class RouteInfo implements Parcelable { /** * Indicates if this route is a host route (ie, matches only a single host address). * - * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6. + * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6, + * respectively. * @hide */ public boolean isHostRoute() { @@ -295,13 +338,22 @@ public class RouteInfo implements Parcelable { return bestRoute; } + /** + * Returns a human-readable description of this object. + */ public String toString() { String val = ""; if (mDestination != null) val = mDestination.toString(); - if (mGateway != null) val += " -> " + mGateway.getHostAddress(); + val += " ->"; + if (mGateway != null) val += " " + mGateway.getHostAddress(); + if (mInterface != null) val += " " + mInterface; return val; } + /** + * Compares this RouteInfo object against the specified object and indicates if they are equal. + * @return {@code true} if the objects are equal, {@code false} otherwise. + */ public boolean equals(Object obj) { if (this == obj) return true; @@ -314,6 +366,9 @@ public class RouteInfo implements Parcelable { Objects.equals(mInterface, target.getInterface()); } + /** + * Returns a hashcode for this RouteInfo object. + */ public int hashCode() { return (mDestination == null ? 0 : mDestination.hashCode() * 41) + (mGateway == null ? 0 :mGateway.hashCode() * 47) diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java index 55d6592d9a..01283a65ba 100644 --- a/core/tests/coretests/src/android/net/RouteInfoTest.java +++ b/core/tests/coretests/src/android/net/RouteInfoTest.java @@ -43,17 +43,17 @@ public class RouteInfoTest extends TestCase { // Invalid input. try { - r = new RouteInfo(null, null, "rmnet0"); + r = new RouteInfo((LinkAddress) null, null, "rmnet0"); fail("Expected RuntimeException: destination and gateway null"); } catch(RuntimeException e) {} // Null destination is default route. - r = new RouteInfo(null, Address("2001:db8::1"), null); + r = new RouteInfo((LinkAddress) null, Address("2001:db8::1"), null); assertEquals(Prefix("::/0"), r.getDestination()); assertEquals(Address("2001:db8::1"), r.getGateway()); assertNull(r.getInterface()); - r = new RouteInfo(null, Address("192.0.2.1"), "wlan0"); + r = new RouteInfo((LinkAddress) null, Address("192.0.2.1"), "wlan0"); assertEquals(Prefix("0.0.0.0/0"), r.getDestination()); assertEquals(Address("192.0.2.1"), r.getGateway()); assertEquals("wlan0", r.getInterface()); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 4c594e1a3e..25e78225a1 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1871,7 +1871,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetd.addRoute(netId, r); } if (exempt) { - LinkAddress dest = r.getDestination(); + LinkAddress dest = r.getDestinationLinkAddress(); if (!mExemptAddresses.contains(dest)) { mNetd.setHostExemption(dest); mExemptAddresses.add(dest); @@ -1904,7 +1904,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { mNetd.removeRoute(netId, r); } - LinkAddress dest = r.getDestination(); + LinkAddress dest = r.getDestinationLinkAddress(); if (mExemptAddresses.contains(dest)) { mNetd.clearHostExemption(dest); mExemptAddresses.remove(dest); From b0116bf5bfb2b64902a685462a72c4869100937a Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Mon, 9 Jun 2014 22:58:46 +0900 Subject: [PATCH 291/296] Minor changes to the LinkAddress API docs. 1. Rename getNetworkPrefixLength to getPrefixLength. Update all callers in frameworks/base and add a shim method and a TODO for the rest. 2. @hide isSameAddressAs. It doesn't add much, and it's just one-liner that callers can implement if they want. 3. Fix the alignment of the initial paragraph (

            should have been
          ). 4. Remove the documentation that talks about creating LinkAddresses, since there's no public API for creating them. With these changes I think LinkAddress is fine as a public API. Bug: 15142362 Change-Id: Iaf3b1db577745bb68a9e1dd7f96d666dd3f3ec7c --- core/java/android/net/LinkAddress.java | 35 +++++++++++-------- core/java/android/net/RouteInfo.java | 18 +++++----- .../src/android/net/LinkAddressTest.java | 12 +++---- .../android/server/ConnectivityService.java | 2 +- 4 files changed, 37 insertions(+), 30 deletions(-) diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java index d07c0b61a1..524607822d 100644 --- a/core/java/android/net/LinkAddress.java +++ b/core/java/android/net/LinkAddress.java @@ -39,18 +39,13 @@ import static android.system.OsConstants.RT_SCOPE_UNIVERSE; *
            *
          • An IP address and prefix length (e.g., {@code 2001:db8::1/64} or {@code 192.0.2.1/24}). * The address must be unicast, as multicast addresses cannot be assigned to interfaces. - *
          • Address flags: A bitmask of {@code IFA_F_*} values representing properties - * of the address. - *
          • Address scope: An integer defining the scope in which the address is unique (e.g., - * {@code RT_SCOPE_LINK} or {@code RT_SCOPE_SITE}). - *
              - *

              - * When constructing a {@code LinkAddress}, the IP address and prefix are required. The flags and - * scope are optional. If they are not specified, the flags are set to zero, and the scope will be - * determined based on the IP address (e.g., link-local addresses will be created with a scope of - * {@code RT_SCOPE_LINK}, global addresses with {@code RT_SCOPE_UNIVERSE}, - * etc.) If they are specified, they are not checked for validity. - * + *

            • Address flags: A bitmask of {@code OsConstants.IFA_F_*} values representing properties + * of the address (e.g., {@code android.system.OsConstants.IFA_F_OPTIMISTIC}). + *
            • Address scope: One of the {@code OsConstants.IFA_F_*} values; defines the scope in which + * the address is unique (e.g., + * {@code android.system.OsConstants.RT_SCOPE_LINK} or + * {@code android.system.OsConstants.RT_SCOPE_UNIVERSE}). + *
            */ public class LinkAddress implements Parcelable { /** @@ -202,7 +197,9 @@ public class LinkAddress implements Parcelable { /** * Compares this {@code LinkAddress} instance against {@code obj}. Two addresses are equal if - * their address, prefix length, flags and scope are equal. + * their address, prefix length, flags and scope are equal. Thus, for example, two addresses + * that have the same address and prefix length are not equal if one of them is deprecated and + * the other is not. * * @param obj the object to be tested for equality. * @return {@code true} if both objects are equal, {@code false} otherwise. @@ -236,6 +233,7 @@ public class LinkAddress implements Parcelable { * @param other the {@code LinkAddress} to compare to. * @return {@code true} if both objects have the same address and prefix length, {@code false} * otherwise. + * @hide */ public boolean isSameAddressAs(LinkAddress other) { return address.equals(other.address) && prefixLength == other.prefixLength; @@ -251,10 +249,19 @@ public class LinkAddress implements Parcelable { /** * Returns the prefix length of this {@code LinkAddress}. */ - public int getNetworkPrefixLength() { + public int getPrefixLength() { return prefixLength; } + /** + * Returns the prefix length of this {@code LinkAddress}. + * TODO: Delete all callers and remove in favour of getPrefixLength(). + * @hide + */ + public int getNetworkPrefixLength() { + return getPrefixLength(); + } + /** * Returns the flags of this {@code LinkAddress}. */ diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index a65523b236..af27e1ddd1 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -119,7 +119,7 @@ public class RouteInfo implements Parcelable { mHasGateway = (!gateway.isAnyLocalAddress()); mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), - destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength()); + destination.getPrefixLength()), destination.getPrefixLength()); if ((destination.getAddress() instanceof Inet4Address && (gateway instanceof Inet4Address == false)) || (destination.getAddress() instanceof Inet6Address && @@ -210,18 +210,18 @@ public class RouteInfo implements Parcelable { private boolean isHost() { return (mDestination.getAddress() instanceof Inet4Address && - mDestination.getNetworkPrefixLength() == 32) || + mDestination.getPrefixLength() == 32) || (mDestination.getAddress() instanceof Inet6Address && - mDestination.getNetworkPrefixLength() == 128); + mDestination.getPrefixLength() == 128); } private boolean isDefault() { boolean val = false; if (mGateway != null) { if (mGateway instanceof Inet4Address) { - val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); + val = (mDestination == null || mDestination.getPrefixLength() == 0); } else { - val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0); + val = (mDestination == null || mDestination.getPrefixLength() == 0); } } return val; @@ -306,7 +306,7 @@ public class RouteInfo implements Parcelable { // match the route destination and destination with prefix length InetAddress dstNet = NetworkUtils.getNetworkPart(destination, - mDestination.getNetworkPrefixLength()); + mDestination.getPrefixLength()); return mDestination.getAddress().equals(dstNet); } @@ -328,8 +328,8 @@ public class RouteInfo implements Parcelable { for (RouteInfo route : routes) { if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) { if ((bestRoute != null) && - (bestRoute.mDestination.getNetworkPrefixLength() >= - route.mDestination.getNetworkPrefixLength())) { + (bestRoute.mDestination.getPrefixLength() >= + route.mDestination.getPrefixLength())) { continue; } if (route.matches(dest)) bestRoute = route; @@ -394,7 +394,7 @@ public class RouteInfo implements Parcelable { } else { dest.writeByte((byte) 1); dest.writeByteArray(mDestination.getAddress().getAddress()); - dest.writeInt(mDestination.getNetworkPrefixLength()); + dest.writeInt(mDestination.getPrefixLength()); } if (mGateway == null) { diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java index bccf556486..814ecdd95b 100644 --- a/core/tests/coretests/src/android/net/LinkAddressTest.java +++ b/core/tests/coretests/src/android/net/LinkAddressTest.java @@ -56,26 +56,26 @@ public class LinkAddressTest extends AndroidTestCase { // Valid addresses work as expected. address = new LinkAddress(V4_ADDRESS, 25); assertEquals(V4_ADDRESS, address.getAddress()); - assertEquals(25, address.getNetworkPrefixLength()); + assertEquals(25, address.getPrefixLength()); assertEquals(0, address.getFlags()); assertEquals(RT_SCOPE_UNIVERSE, address.getScope()); address = new LinkAddress(V6_ADDRESS, 127); assertEquals(V6_ADDRESS, address.getAddress()); - assertEquals(127, address.getNetworkPrefixLength()); + assertEquals(127, address.getPrefixLength()); assertEquals(0, address.getFlags()); assertEquals(RT_SCOPE_UNIVERSE, address.getScope()); // Nonsensical flags/scopes or combinations thereof are acceptable. address = new LinkAddress(V6 + "/64", IFA_F_DEPRECATED | IFA_F_PERMANENT, RT_SCOPE_LINK); assertEquals(V6_ADDRESS, address.getAddress()); - assertEquals(64, address.getNetworkPrefixLength()); + assertEquals(64, address.getPrefixLength()); assertEquals(IFA_F_DEPRECATED | IFA_F_PERMANENT, address.getFlags()); assertEquals(RT_SCOPE_LINK, address.getScope()); address = new LinkAddress(V4 + "/23", 123, 456); assertEquals(V4_ADDRESS, address.getAddress()); - assertEquals(23, address.getNetworkPrefixLength()); + assertEquals(23, address.getPrefixLength()); assertEquals(123, address.getFlags()); assertEquals(456, address.getScope()); @@ -94,10 +94,10 @@ public class LinkAddressTest extends AndroidTestCase { } assertEquals(NetworkUtils.numericToInetAddress("127.0.0.1"), ipv4Loopback.getAddress()); - assertEquals(8, ipv4Loopback.getNetworkPrefixLength()); + assertEquals(8, ipv4Loopback.getPrefixLength()); assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress()); - assertEquals(128, ipv6Loopback.getNetworkPrefixLength()); + assertEquals(128, ipv6Loopback.getPrefixLength()); // Null addresses are rejected. try { diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 25e78225a1..9087726a3e 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1669,7 +1669,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { continue; } - int prefix = destination.getNetworkPrefixLength(); + int prefix = destination.getPrefixLength(); InetAddress addrMasked = NetworkUtils.getNetworkPart(address, prefix); InetAddress destMasked = NetworkUtils.getNetworkPart(destination.getAddress(), prefix); From 87afb9411ce50421987e313fc855726268877ceb Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Fri, 6 Jun 2014 10:30:11 -0700 Subject: [PATCH 292/296] Fix public API of LinkProperties. bug:15142362 (cherry picked from commit 51d898fd0223a4b7c728980ab987dd985c02df5f) Change-Id: I1457111da7d3bd09998f7e010febb8bb4c45c8bc --- core/java/android/net/LinkProperties.java | 86 +++++++++++-------- .../src/android/net/LinkPropertiesTest.java | 36 ++++---- .../android/server/ConnectivityService.java | 9 +- 3 files changed, 74 insertions(+), 57 deletions(-) diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 3c366799f6..cff9025d74 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -30,6 +30,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Hashtable; +import java.util.List; /** * Describes the properties of a network link. @@ -58,10 +59,12 @@ public class LinkProperties implements Parcelable { private Hashtable mStackedLinks = new Hashtable(); - // @hide + /** + * @hide + */ public static class CompareResult { - public Collection removed = new ArrayList(); - public Collection added = new ArrayList(); + public List removed = new ArrayList(); + public List added = new ArrayList(); @Override public String toString() { @@ -81,7 +84,7 @@ public class LinkProperties implements Parcelable { if (source != null) { mIfaceName = source.getInterfaceName(); for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l); - for (InetAddress i : source.getDnses()) mDnses.add(i); + for (InetAddress i : source.getDnsServers()) mDnses.add(i); mDomains = source.getDomains(); for (RouteInfo r : source.getRoutes()) mRoutes.add(r); mHttpProxy = (source.getHttpProxy() == null) ? @@ -98,6 +101,7 @@ public class LinkProperties implements Parcelable { * will have their interface changed to match this new value. * * @param iface The name of the network interface used for this link. + * @hide */ public void setInterfaceName(String iface) { mIfaceName = iface; @@ -117,9 +121,11 @@ public class LinkProperties implements Parcelable { return mIfaceName; } - // @hide - public Collection getAllInterfaceNames() { - Collection interfaceNames = new ArrayList(mStackedLinks.size() + 1); + /** + * @hide + */ + public List getAllInterfaceNames() { + List interfaceNames = new ArrayList(mStackedLinks.size() + 1); if (mIfaceName != null) interfaceNames.add(new String(mIfaceName)); for (LinkProperties stacked: mStackedLinks.values()) { interfaceNames.addAll(stacked.getAllInterfaceNames()); @@ -134,23 +140,23 @@ public class LinkProperties implements Parcelable { * prefix lengths for each address. This is a simplified utility alternative to * {@link LinkProperties#getLinkAddresses}. * - * @return An umodifiable {@link Collection} of {@link InetAddress} for this link. + * @return An umodifiable {@link List} of {@link InetAddress} for this link. * @hide */ - public Collection getAddresses() { - Collection addresses = new ArrayList(); + public List getAddresses() { + List addresses = new ArrayList(); for (LinkAddress linkAddress : mLinkAddresses) { addresses.add(linkAddress.getAddress()); } - return Collections.unmodifiableCollection(addresses); + return Collections.unmodifiableList(addresses); } /** * Returns all the addresses on this link and all the links stacked above it. * @hide */ - public Collection getAllAddresses() { - Collection addresses = new ArrayList(); + public List getAllAddresses() { + List addresses = new ArrayList(); for (LinkAddress linkAddress : mLinkAddresses) { addresses.add(linkAddress.getAddress()); } @@ -174,6 +180,7 @@ public class LinkProperties implements Parcelable { * same address/prefix does not already exist. If it does exist it is replaced. * @param address The {@code LinkAddress} to add. * @return true if {@code address} was added or updated, false otherwise. + * @hide */ public boolean addLinkAddress(LinkAddress address) { if (address == null) { @@ -200,6 +207,7 @@ public class LinkProperties implements Parcelable { * * @param toRemove A {@link LinkAddress} specifying the address to remove. * @return true if the address was removed, false if it did not exist. + * @hide */ public boolean removeLinkAddress(LinkAddress toRemove) { int i = findLinkAddressIndex(toRemove); @@ -214,18 +222,18 @@ public class LinkProperties implements Parcelable { * Returns all the {@link LinkAddress} on this link. Typically a link will have * one IPv4 address and one or more IPv6 addresses. * - * @return An unmodifiable {@link Collection} of {@link LinkAddress} for this link. + * @return An unmodifiable {@link List} of {@link LinkAddress} for this link. */ - public Collection getLinkAddresses() { - return Collections.unmodifiableCollection(mLinkAddresses); + public List getLinkAddresses() { + return Collections.unmodifiableList(mLinkAddresses); } /** * Returns all the addresses on this link and all the links stacked above it. * @hide */ - public Collection getAllLinkAddresses() { - Collection addresses = new ArrayList(); + public List getAllLinkAddresses() { + List addresses = new ArrayList(); addresses.addAll(mLinkAddresses); for (LinkProperties stacked: mStackedLinks.values()) { addresses.addAll(stacked.getAllLinkAddresses()); @@ -239,6 +247,7 @@ public class LinkProperties implements Parcelable { * * @param addresses The {@link Collection} of {@link LinkAddress} to set in this * object. + * @hide */ public void setLinkAddresses(Collection addresses) { mLinkAddresses.clear(); @@ -250,20 +259,21 @@ public class LinkProperties implements Parcelable { /** * Adds the given {@link InetAddress} to the list of DNS servers. * - * @param dns The {@link InetAddress} to add to the list of DNS servers. + * @param dnsServer The {@link InetAddress} to add to the list of DNS servers. + * @hide */ - public void addDns(InetAddress dns) { - if (dns != null) mDnses.add(dns); + public void addDnsServer(InetAddress dnsServer) { + if (dnsServer != null) mDnses.add(dnsServer); } /** * Returns all the {@link LinkAddress} for DNS servers on this link. * - * @return An umodifiable {@link Collection} of {@link InetAddress} for DNS servers on + * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on * this link. */ - public Collection getDnses() { - return Collections.unmodifiableCollection(mDnses); + public List getDnsServers() { + return Collections.unmodifiableList(mDnses); } /** @@ -271,6 +281,7 @@ public class LinkProperties implements Parcelable { * * @param domains A {@link String} listing in priority order the comma separated * domains to search when resolving host names on this link. + * @hide */ public void setDomains(String domains) { mDomains = domains; @@ -323,6 +334,7 @@ public class LinkProperties implements Parcelable { * proper course is to add either un-named or properly named {@link RouteInfo}. * * @param route A {@link RouteInfo} to add to this object. + * @hide */ public void addRoute(RouteInfo route) { if (route != null) { @@ -339,18 +351,18 @@ public class LinkProperties implements Parcelable { /** * Returns all the {@link RouteInfo} set on this link. * - * @return An unmodifiable {@link Collection} of {@link RouteInfo} for this link. + * @return An unmodifiable {@link List} of {@link RouteInfo} for this link. */ - public Collection getRoutes() { - return Collections.unmodifiableCollection(mRoutes); + public List getRoutes() { + return Collections.unmodifiableList(mRoutes); } /** * Returns all the routes on this link and all the links stacked above it. * @hide */ - public Collection getAllRoutes() { - Collection routes = new ArrayList(); + public List getAllRoutes() { + List routes = new ArrayList(); routes.addAll(mRoutes); for (LinkProperties stacked: mStackedLinks.values()) { routes.addAll(stacked.getAllRoutes()); @@ -364,6 +376,7 @@ public class LinkProperties implements Parcelable { * not enforce it and applications may ignore them. * * @param proxy A {@link ProxyInfo} defining the Http Proxy to use on this link. + * @hide */ public void setHttpProxy(ProxyInfo proxy) { mHttpProxy = proxy; @@ -419,16 +432,17 @@ public class LinkProperties implements Parcelable { * Returns all the links stacked on top of this link. * @hide */ - public Collection getStackedLinks() { - Collection stacked = new ArrayList(); + public List getStackedLinks() { + List stacked = new ArrayList(); for (LinkProperties link : mStackedLinks.values()) { stacked.add(new LinkProperties(link)); } - return Collections.unmodifiableCollection(stacked); + return Collections.unmodifiableList(stacked); } /** * Clears this object to its initial state. + * @hide */ public void clear() { mIfaceName = null; @@ -486,6 +500,7 @@ public class LinkProperties implements Parcelable { * Returns true if this link has an IPv4 address. * * @return {@code true} if there is an IPv4 address, {@code false} otherwise. + * @hide */ public boolean hasIPv4Address() { for (LinkAddress address : mLinkAddresses) { @@ -500,6 +515,7 @@ public class LinkProperties implements Parcelable { * Returns true if this link has an IPv6 address. * * @return {@code true} if there is an IPv6 address, {@code false} otherwise. + * @hide */ public boolean hasIPv6Address() { for (LinkAddress address : mLinkAddresses) { @@ -543,7 +559,7 @@ public class LinkProperties implements Parcelable { * @hide */ public boolean isIdenticalDnses(LinkProperties target) { - Collection targetDnses = target.getDnses(); + Collection targetDnses = target.getDnsServers(); String targetDomains = target.getDomains(); if (mDomains == null) { if (targetDomains != null) return false; @@ -696,7 +712,7 @@ public class LinkProperties implements Parcelable { result.removed = new ArrayList(mDnses); result.added.clear(); if (target != null) { - for (InetAddress newAddress : target.getDnses()) { + for (InetAddress newAddress : target.getDnsServers()) { if (! result.removed.remove(newAddress)) { result.added.add(newAddress); } @@ -831,7 +847,7 @@ public class LinkProperties implements Parcelable { addressCount = in.readInt(); for (int i=0; i dnses = p.getDnses(); + Collection dnses = p.getDnsServers(); int netId = nt.getNetwork().netId; if (mNetConfigs[netType].isDefault()) { String network = nt.getNetworkInfo().getTypeName(); @@ -5625,7 +5625,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId) { if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) { - Collection dnses = newLp.getDnses(); + Collection dnses = newLp.getDnsServers(); if (dnses.size() == 0 && mDefaultDns != null) { dnses = new ArrayList(); dnses.add(mDefaultDns); @@ -5790,7 +5790,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { isNewDefault = true; updateActiveDefaultNetwork(newNetwork); if (newNetwork.linkProperties != null) { - setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnses()); + setDefaultDnsSystemProperties( + newNetwork.linkProperties.getDnsServers()); } else { setDefaultDnsSystemProperties(new ArrayList()); } From c4c6498fcc5f1a204b30082a9cada931fe61d702 Mon Sep 17 00:00:00 2001 From: Paul Jensen Date: Thu, 29 May 2014 10:12:39 -0400 Subject: [PATCH 293/296] Apply API review to android.net.Network: - socketFactory() renamed to getSocketFactory() - Make sure bindProcess() documentation points developers to getSocketFactory() as the preferred approach - Move bindProcess() and unbindProcess() to ConnectivityManager.setProcessBoundNetwork() -- passing null clears it. - Move getProcessBoundNetwork() to ConnectivityManager.getProcessBoundNetwork(). Bug:15142362 Bug:13885501 Change-Id: Ia55c59d52e1ec8bf10dd0d9d037bd04c0998bc71 (cherry picked from commit 5ca1e6675bf4182b6e9ca76a7696bf2e38e96c4f) --- .../java/android/net/ConnectivityManager.java | 69 +++++++++++++++++-- core/java/android/net/Network.java | 55 +-------------- core/java/android/net/NetworkUtils.java | 2 +- 3 files changed, 69 insertions(+), 57 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index b96f16646c..60e76e0ee2 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -22,6 +22,7 @@ import android.annotation.SdkConstant.SdkConstantType; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.net.NetworkUtils; import android.os.Binder; import android.os.Build.VERSION_CODES; import android.os.Handler; @@ -981,13 +982,13 @@ public class ConnectivityManager { public void onAvailable(NetworkRequest request, Network network) { currentNetwork = network; Log.d(TAG, "startUsingNetworkFeature got Network:" + network); - network.bindProcessForHostResolution(); + setProcessDefaultNetworkForHostResolution(network); } @Override public void onLost(NetworkRequest request, Network network) { if (network.equals(currentNetwork)) { currentNetwork = null; - network.unbindProcessForHostResolution(); + setProcessDefaultNetworkForHostResolution(null); } Log.d(TAG, "startUsingNetworkFeature lost Network:" + network); } @@ -1071,7 +1072,7 @@ public class ConnectivityManager { * @return {@code true} on success, {@code false} on failure * * @deprecated Deprecated in favor of the {@link #requestNetwork}, - * {@link Network#bindProcess} and {@link Network#socketFactory} api. + * {@link #setProcessDefaultNetwork} and {@link Network#getSocketFactory} api. */ public boolean requestRouteToHost(int networkType, int hostAddress) { InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); @@ -1095,7 +1096,7 @@ public class ConnectivityManager { * @return {@code true} on success, {@code false} on failure * @hide * @deprecated Deprecated in favor of the {@link #requestNetwork} and - * {@link Network#bindProcess} api. + * {@link #setProcessDefaultNetwork} api. */ public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { byte[] address = hostAddress.getAddress(); @@ -2347,4 +2348,64 @@ public class ConnectivityManager { mService.releaseNetworkRequest(networkRequest); } catch (RemoteException e) {} } + + /** + * Binds the current process to {@code network}. All Sockets created in the future + * (and not explicitly bound via a bound SocketFactory from + * {@link Network#getSocketFactory() Network.getSocketFactory()}) will be bound to + * {@code network}. All host name resolutions will be limited to {@code network} as well. + * Note that if {@code network} ever disconnects, all Sockets created in this way will cease to + * work and all host name resolutions will fail. This is by design so an application doesn't + * accidentally use Sockets it thinks are still bound to a particular {@link Network}. + * To clear binding pass {@code null} for {@code network}. Using individually bound + * Sockets created by Network.getSocketFactory().createSocket() and + * performing network-specific host name resolutions via + * {@link Network#getAllByName Network.getAllByName} is preferred to calling + * {@code setProcessDefaultNetwork}. + * + * @param network The {@link Network} to bind the current process to, or {@code null} to clear + * the current binding. + * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. + */ + public static boolean setProcessDefaultNetwork(Network network) { + if (network == null) { + NetworkUtils.unbindProcessToNetwork(); + } else { + NetworkUtils.bindProcessToNetwork(network.netId); + } + // TODO fix return value + return true; + } + + /** + * Returns the {@link Network} currently bound to this process via + * {@link #setProcessDefaultNetwork}, or {@code null} if no {@link Network} is explicitly bound. + * + * @return {@code Network} to which this process is bound, or {@code null}. + */ + public static Network getProcessDefaultNetwork() { + int netId = NetworkUtils.getNetworkBoundToProcess(); + if (netId == 0) return null; + return new Network(netId); + } + + /** + * Binds host resolutions performed by this process to {@code network}. + * {@link #setProcessDefaultNetwork} takes precedence over this setting. + * + * @param network The {@link Network} to bind host resolutions from the current process to, or + * {@code null} to clear the current binding. + * @return {@code true} on success, {@code false} if the {@link Network} is no longer valid. + * @hide + * @deprecated This is strictly for legacy usage to support {@link #startUsingNetworkFeature}. + */ + public static boolean setProcessDefaultNetworkForHostResolution(Network network) { + if (network == null) { + NetworkUtils.unbindProcessToNetworkForHostResolution(); + } else { + NetworkUtils.bindProcessToNetworkForHostResolution(network.netId); + } + // TODO hook up the return value. + return true; + } } diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 64516e62d1..d933f26c78 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -32,7 +32,8 @@ import javax.net.SocketFactory; * {@link ConnectivityManager.NetworkCallbackListener} in response to * {@link ConnectivityManager#requestNetwork} or {@link ConnectivityManager#listenForNetwork}. * It is used to direct traffic to the given {@code Network}, either on a {@link Socket} basis - * through a targeted {@link SocketFactory} or process-wide via {@link #bindProcess}. + * through a targeted {@link SocketFactory} or process-wide via + * {@link ConnectivityManager#setProcessDefaultNetwork}. */ public class Network implements Parcelable { @@ -160,63 +161,13 @@ public class Network implements Parcelable { * @return a {@link SocketFactory} which produces {@link Socket} instances bound to this * {@code Network}. */ - public SocketFactory socketFactory() { + public SocketFactory getSocketFactory() { if (mNetworkBoundSocketFactory == null) { mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); } return mNetworkBoundSocketFactory; } - /** - * Binds the current process to this network. All sockets created in the future (and not - * explicitly bound via a bound {@link SocketFactory} (see {@link Network#socketFactory}) - * will be bound to this network. Note that if this {@code Network} ever disconnects - * all sockets created in this way will cease to work. This is by design so an application - * doesn't accidentally use sockets it thinks are still bound to a particular {@code Network}. - */ - public void bindProcess() { - NetworkUtils.bindProcessToNetwork(netId); - } - - /** - * Binds host resolutions performed by this process to this network. {@link #bindProcess} - * takes precedence over this setting. - * - * @hide - * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). - */ - public void bindProcessForHostResolution() { - NetworkUtils.bindProcessToNetworkForHostResolution(netId); - } - - /** - * Clears any process specific {@link Network} binding for host resolution. This does - * not clear bindings enacted via {@link #bindProcess}. - * - * @hide - * @deprecated This is strictly for legacy usage to support startUsingNetworkFeature(). - */ - public void unbindProcessForHostResolution() { - NetworkUtils.unbindProcessToNetworkForHostResolution(); - } - - /** - * A static utility method to return any {@code Network} currently bound by this process. - * - * @return {@code Network} to which this process is bound. - */ - public static Network getProcessBoundNetwork() { - return new Network(NetworkUtils.getNetworkBoundToProcess()); - } - - /** - * Clear any process specific {@code Network} binding. This reverts a call to - * {@link Network#bindProcess}. - */ - public static void unbindProcess() { - NetworkUtils.unbindProcessToNetwork(); - } - // implement the Parcelable interface public int describeContents() { return 0; diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index edb32866d3..b02f88ec81 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -111,7 +111,7 @@ public class NetworkUtils { /** * Binds the current process to the network designated by {@code netId}. All sockets created * in the future (and not explicitly bound via a bound {@link SocketFactory} (see - * {@link Network#socketFactory}) will be bound to this network. Note that if this + * {@link Network#getSocketFactory}) will be bound to this network. Note that if this * {@code Network} ever disconnects all sockets created in this way will cease to work. This * is by design so an application doesn't accidentally use sockets it thinks are still bound to * a particular {@code Network}. From 96151d642eaa17dadde4921317f3f9a6781cfaa3 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Wed, 11 Jun 2014 15:56:51 -0700 Subject: [PATCH 294/296] Fix wifi connectivity issues. http://ag/480881 changed RouteInfo.getDestination() to return an IpPrefix instead of a LinkAddress. This makes the equals() comparison always fail. So, when ConnectivityService.updateRoutes() is given identical routes, instead of realizing that there's no diff, it would consider them different, and thus add and remove the same route. The add would fail, since the route already existed in netd, but the remove would succeed, leaving the system with no routes and thus no connectivity. Bug: 15564210 Change-Id: I2003b0fcb809cc20837dc489c58af37891ca4556 --- core/java/android/net/RouteInfo.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index af27e1ddd1..8b42bcd5cb 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -361,7 +361,7 @@ public class RouteInfo implements Parcelable { RouteInfo target = (RouteInfo) obj; - return Objects.equals(mDestination, target.getDestination()) && + return Objects.equals(mDestination, target.getDestinationLinkAddress()) && Objects.equals(mGateway, target.getGateway()) && Objects.equals(mInterface, target.getInterface()); } From aaaf7bab7fb5c69f99a7d2e0c025e574831d4865 Mon Sep 17 00:00:00 2001 From: Sreeram Ramachandran Date: Tue, 3 Jun 2014 18:41:43 -0700 Subject: [PATCH 295/296] Add a new IpPrefix class and use it in RouteInfo. This change uses IpPrefix only in the public API and continues to use LinkAddress for everything else. It does not change the callers to use the new APIs, with the exception of changing all current uses of getDestination to getDestinationLinkAddress to make room for the new getDestination method that returns an IpPrefix. Based on Sreeram's earlier change: https://googleplex-android-review.git.corp.google.com/#/c/477874/ but a bit simplified and with a bit more documentation. Bug: 15142362 Bug: 13885501 Change-Id: Ib4cd96b22cbff4ea31bb26a7853989f50da8de4e (cherry picked from commit 7d3b4b9a3d4de9673119632da0ebd583e50126f7) --- core/java/android/net/IpPrefix.java | 170 ++++++++++++++++++ core/java/android/net/LinkProperties.java | 15 +- core/java/android/net/RouteInfo.java | 82 +++++++-- .../src/android/net/RouteInfoTest.java | 6 +- .../android/server/ConnectivityService.java | 4 +- 5 files changed, 252 insertions(+), 25 deletions(-) create mode 100644 core/java/android/net/IpPrefix.java diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java new file mode 100644 index 0000000000..a14d13f176 --- /dev/null +++ b/core/java/android/net/IpPrefix.java @@ -0,0 +1,170 @@ +/* + * 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; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; + +/** + * This class represents an IP prefix, i.e., a contiguous block of IP addresses aligned on a + * power of two boundary (also known as an "IP subnet"). A prefix is specified by two pieces of + * information: + * + *
              + *
            • A starting IP address (IPv4 or IPv6). This is the first IP address of the prefix. + *
            • A prefix length. This specifies the length of the prefix by specifing the number of bits + * in the IP address, starting from the most significant bit in network byte order, that + * are constant for all addresses in the prefix. + *
            + * + * For example, the prefix 192.0.2.0/24 covers the 256 IPv4 addresses from + * 192.0.2.0 to 192.0.2.255, inclusive, and the prefix + * 2001:db8:1:2 covers the 2^64 IPv6 addresses from 2001:db8:1:2:: to + * 2001:db8:1:2:ffff:ffff:ffff:ffff, inclusive. + * + * Objects of this class are immutable. + */ +public final class IpPrefix implements Parcelable { + private final byte[] address; // network byte order + private final int prefixLength; + + /** + * Constructs a new {@code IpPrefix} from a byte array containing an IPv4 or IPv6 address in + * network byte order and a prefix length. + * + * @param address the IP address. Must be non-null and exactly 4 or 16 bytes long. + * @param prefixLength the prefix length. Must be >= 0 and <= (32 or 128) (IPv4 or IPv6). + * + * @hide + */ + public IpPrefix(byte[] address, int prefixLength) { + if (address.length != 4 && address.length != 16) { + throw new IllegalArgumentException( + "IpPrefix has " + address.length + " bytes which is neither 4 nor 16"); + } + if (prefixLength < 0 || prefixLength > (address.length * 8)) { + throw new IllegalArgumentException("IpPrefix with " + address.length + + " bytes has invalid prefix length " + prefixLength); + } + this.address = address.clone(); + this.prefixLength = prefixLength; + // TODO: Validate that the non-prefix bits are zero + } + + /** + * @hide + */ + public IpPrefix(InetAddress address, int prefixLength) { + this(address.getAddress(), prefixLength); + } + + /** + * Compares this {@code IpPrefix} object against the specified object in {@code obj}. Two + * objects are equal if they have the same startAddress and prefixLength. + * + * @param obj the object to be tested for equality. + * @return {@code true} if both objects are equal, {@code false} otherwise. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IpPrefix)) { + return false; + } + IpPrefix that = (IpPrefix) obj; + return Arrays.equals(this.address, that.address) && this.prefixLength == that.prefixLength; + } + + /** + * Gets the hashcode of the represented IP prefix. + * + * @return the appropriate hashcode value. + */ + @Override + public int hashCode() { + return Arrays.hashCode(address) + 11 * prefixLength; + } + + /** + * Returns a copy of the first IP address in the prefix. Modifying the returned object does not + * change this object's contents. + * + * @return the address in the form of a byte array. + */ + public InetAddress getAddress() { + try { + return InetAddress.getByAddress(address); + } catch (UnknownHostException e) { + // Cannot happen. InetAddress.getByAddress can only throw an exception if the byte + // array is the wrong length, but we check that in the constructor. + return null; + } + } + + /** + * Returns a copy of the IP address bytes in network order (the highest order byte is the zeroth + * element). Modifying the returned array does not change this object's contents. + * + * @return the address in the form of a byte array. + */ + public byte[] getRawAddress() { + return address.clone(); + } + + /** + * Returns the prefix length of this {@code IpAddress}. + * + * @return the prefix length. + */ + public int getPrefixLength() { + return prefixLength; + } + + /** + * Implement the Parcelable interface. + */ + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface. + */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeByteArray(address); + dest.writeInt(prefixLength); + } + + /** + * Implement the Parcelable interface. + */ + public static final Creator CREATOR = + new Creator() { + public IpPrefix createFromParcel(Parcel in) { + byte[] address = in.createByteArray(); + int prefixLength = in.readInt(); + return new IpPrefix(address, prefixLength); + } + + public IpPrefix[] newArray(int size) { + return new IpPrefix[size]; + } + }; +} diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index cff9025d74..8eefa0f55f 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -44,7 +44,7 @@ import java.util.List; * does not affect live networks. * */ -public class LinkProperties implements Parcelable { +public final class LinkProperties implements Parcelable { // The interface described by the network link. private String mIfaceName; private ArrayList mLinkAddresses = new ArrayList(); @@ -77,9 +77,15 @@ public class LinkProperties implements Parcelable { } } + /** + * @hide + */ public LinkProperties() { } + /** + * @hide + */ public LinkProperties(LinkProperties source) { if (source != null) { mIfaceName = source.getInterfaceName(); @@ -267,7 +273,7 @@ public class LinkProperties implements Parcelable { } /** - * Returns all the {@link LinkAddress} for DNS servers on this link. + * Returns all the {@link InetAddress} for DNS servers on this link. * * @return An umodifiable {@link List} of {@link InetAddress} for DNS servers on * this link. @@ -457,7 +463,6 @@ public class LinkProperties implements Parcelable { /** * Implement the Parcelable interface - * @hide */ public int describeContents() { return 0; @@ -477,12 +482,12 @@ public class LinkProperties implements Parcelable { String domainName = "Domains: " + mDomains; - String mtu = "MTU: " + mMtu; + String mtu = " MTU: " + mMtu; String routes = " Routes: ["; for (RouteInfo route : mRoutes) routes += route.toString() + ","; routes += "] "; - String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " "); + String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " "); String stacked = ""; if (mStackedLinks.values().size() > 0) { diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index ad8e4f7eec..6d65d8f069 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -35,10 +35,10 @@ import java.util.Objects; * * A route contains three pieces of information: *
              - *
            • a destination {@link LinkAddress} for directly-connected subnets. If this is - * {@code null} it indicates a default route of the address family (IPv4 or IPv6) + *
            • a destination {@link IpPrefix} specifying the network destinations covered by this route. + * If this is {@code null} it indicates a default route of the address family (IPv4 or IPv6) * implied by the gateway IP address. - *
            • a gateway {@link InetAddress} for default routes. If this is {@code null} it + *
            • a gateway {@link InetAddress} indicating the next hop to use. If this is {@code null} it * indicates a directly-connected route. *
            • an interface (which may be unspecified). *
            @@ -46,9 +46,10 @@ import java.util.Objects; * destination and gateway are both specified, they must be of the same address family * (IPv4 or IPv6). */ -public class RouteInfo implements Parcelable { +public final class RouteInfo implements Parcelable { /** * The IP destination address for this route. + * TODO: Make this an IpPrefix. */ private final LinkAddress mDestination; @@ -80,6 +81,19 @@ public class RouteInfo implements Parcelable { * @param destination the destination prefix * @param gateway the IP address to route packets through * @param iface the interface name to send packets on + * + * TODO: Convert to use IpPrefix. + * + * @hide + */ + public RouteInfo(IpPrefix destination, InetAddress gateway, String iface) { + this(destination == null ? null : + new LinkAddress(destination.getAddress(), destination.getPrefixLength()), + gateway, iface); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination, InetAddress gateway, String iface) { if (destination == null) { @@ -128,8 +142,17 @@ public class RouteInfo implements Parcelable { *

            * Destination and gateway may not both be null. * - * @param destination the destination address and prefix in a {@link LinkAddress} + * @param destination the destination address and prefix in an {@link IpPrefix} * @param gateway the {@link InetAddress} to route packets through + * + * @hide + */ + public RouteInfo(IpPrefix destination, InetAddress gateway) { + this(destination, gateway, null); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination, InetAddress gateway) { this(destination, gateway, null); @@ -139,16 +162,27 @@ public class RouteInfo implements Parcelable { * Constructs a default {@code RouteInfo} object. * * @param gateway the {@link InetAddress} to route packets through + * + * @hide */ public RouteInfo(InetAddress gateway) { - this(null, gateway, null); + this((LinkAddress) null, gateway, null); } /** * Constructs a {@code RouteInfo} object representing a direct connected subnet. * - * @param destination the {@link LinkAddress} describing the address and prefix + * @param destination the {@link IpPrefix} describing the address and prefix * length of the subnet. + * + * @hide + */ + public RouteInfo(IpPrefix destination) { + this(destination, null, null); + } + + /** + * @hide */ public RouteInfo(LinkAddress destination) { this(destination, null, null); @@ -194,11 +228,19 @@ public class RouteInfo implements Parcelable { } /** - * Retrieves the destination address and prefix length in the form of a {@link LinkAddress}. + * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}. * - * @return {@link LinkAddress} specifying the destination. This is never {@code null}. + * @return {@link IpPrefix} specifying the destination. This is never {@code null}. */ - public LinkAddress getDestination() { + public IpPrefix getDestination() { + return new IpPrefix(mDestination.getAddress(), mDestination.getPrefixLength()); + } + + /** + * TODO: Convert callers to use IpPrefix and then remove. + * @hide + */ + public LinkAddress getDestinationLinkAddress() { return mDestination; } @@ -233,7 +275,8 @@ public class RouteInfo implements Parcelable { /** * Indicates if this route is a host route (ie, matches only a single host address). * - * @return {@code true} if the destination has a prefix length of 32/128 for v4/v6. + * @return {@code true} if the destination has a prefix length of 32 or 128 for IPv4 or IPv6, + * respectively. * @hide */ public boolean isHostRoute() { @@ -295,13 +338,22 @@ public class RouteInfo implements Parcelable { return bestRoute; } + /** + * Returns a human-readable description of this object. + */ public String toString() { String val = ""; if (mDestination != null) val = mDestination.toString(); - if (mGateway != null) val += " -> " + mGateway.getHostAddress(); + val += " ->"; + if (mGateway != null) val += " " + mGateway.getHostAddress(); + if (mInterface != null) val += " " + mInterface; return val; } + /** + * Compares this RouteInfo object against the specified object and indicates if they are equal. + * @return {@code true} if the objects are equal, {@code false} otherwise. + */ public boolean equals(Object obj) { if (this == obj) return true; @@ -314,6 +366,9 @@ public class RouteInfo implements Parcelable { Objects.equals(mInterface, target.getInterface()); } + /** + * Returns a hashcode for this RouteInfo object. + */ public int hashCode() { return (mDestination == null ? 0 : mDestination.hashCode() * 41) + (mGateway == null ? 0 :mGateway.hashCode() * 47) @@ -323,7 +378,6 @@ public class RouteInfo implements Parcelable { /** * Implement the Parcelable interface - * @hide */ public int describeContents() { return 0; @@ -331,7 +385,6 @@ public class RouteInfo implements Parcelable { /** * Implement the Parcelable interface - * @hide */ public void writeToParcel(Parcel dest, int flags) { if (mDestination == null) { @@ -354,7 +407,6 @@ public class RouteInfo implements Parcelable { /** * Implement the Parcelable interface. - * @hide */ public static final Creator CREATOR = new Creator() { diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java index 55d6592d9a..01283a65ba 100644 --- a/core/tests/coretests/src/android/net/RouteInfoTest.java +++ b/core/tests/coretests/src/android/net/RouteInfoTest.java @@ -43,17 +43,17 @@ public class RouteInfoTest extends TestCase { // Invalid input. try { - r = new RouteInfo(null, null, "rmnet0"); + r = new RouteInfo((LinkAddress) null, null, "rmnet0"); fail("Expected RuntimeException: destination and gateway null"); } catch(RuntimeException e) {} // Null destination is default route. - r = new RouteInfo(null, Address("2001:db8::1"), null); + r = new RouteInfo((LinkAddress) null, Address("2001:db8::1"), null); assertEquals(Prefix("::/0"), r.getDestination()); assertEquals(Address("2001:db8::1"), r.getGateway()); assertNull(r.getInterface()); - r = new RouteInfo(null, Address("192.0.2.1"), "wlan0"); + r = new RouteInfo((LinkAddress) null, Address("192.0.2.1"), "wlan0"); assertEquals(Prefix("0.0.0.0/0"), r.getDestination()); assertEquals(Address("192.0.2.1"), r.getGateway()); assertEquals("wlan0", r.getInterface()); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 70b9d4410c..5b36ec6139 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -1871,7 +1871,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { mNetd.addRoute(netId, r); } if (exempt) { - LinkAddress dest = r.getDestination(); + LinkAddress dest = r.getDestinationLinkAddress(); if (!mExemptAddresses.contains(dest)) { mNetd.setHostExemption(dest); mExemptAddresses.add(dest); @@ -1904,7 +1904,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else { mNetd.removeRoute(netId, r); } - LinkAddress dest = r.getDestination(); + LinkAddress dest = r.getDestinationLinkAddress(); if (mExemptAddresses.contains(dest)) { mNetd.clearHostExemption(dest); mExemptAddresses.remove(dest); From bfd1f4c206f56836332a27af68c775b7170e2063 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Sun, 8 Jun 2014 16:42:59 -0700 Subject: [PATCH 296/296] Make NetworkCapabilities publicly immutable. Applying API council comments. bug: 15142362 (cherry picked from commit Ie0bde68b72656a676d90c0343b9756fe9268d8d6) Change-Id: Ie0bde68b72656a676d90c0343b9756fe9268d8d6 --- .../java/android/net/ConnectivityManager.java | 16 ++- .../java/android/net/NetworkCapabilities.java | 88 +++++++++------ core/java/android/net/NetworkRequest.java | 104 ++++++++++++++++-- .../android/server/ConnectivityService.java | 4 +- 4 files changed, 158 insertions(+), 54 deletions(-) diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 60e76e0ee2..65d47261e6 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -429,6 +429,11 @@ public class ConnectivityManager { */ public final static int INVALID_NET_ID = 0; + /** + * @hide + */ + public final static int REQUEST_ID_UNSET = 0; + private final IConnectivityManager mService; private final String mPackageName; @@ -883,8 +888,8 @@ public class ConnectivityManager { * @hide */ public static void maybeMarkCapabilitiesRestricted(NetworkCapabilities nc) { - for (Integer capability : nc.getNetworkCapabilities()) { - switch (capability.intValue()) { + for (int capability : nc.getCapabilities()) { + switch (capability) { case NetworkCapabilities.NET_CAPABILITY_CBS: case NetworkCapabilities.NET_CAPABILITY_DUN: case NetworkCapabilities.NET_CAPABILITY_EIMS: @@ -902,7 +907,7 @@ public class ConnectivityManager { } // All the capabilities are typically provided by restricted networks. // Conclude that this network is restricted. - nc.removeNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); } private NetworkCapabilities networkCapabilitiesForFeature(int networkType, String feature) { @@ -926,15 +931,14 @@ public class ConnectivityManager { return null; } NetworkCapabilities netCap = new NetworkCapabilities(); - netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR); - netCap.addNetworkCapability(cap); + netCap.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR).addCapability(cap); maybeMarkCapabilitiesRestricted(netCap); return netCap; } else if (networkType == TYPE_WIFI) { if ("p2p".equals(feature)) { NetworkCapabilities netCap = new NetworkCapabilities(); netCap.addTransportType(NetworkCapabilities.TRANSPORT_WIFI); - netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); + netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); maybeMarkCapabilitiesRestricted(netCap); return netCap; } diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 35274f1e7e..fe96287c83 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -44,6 +44,9 @@ public final class NetworkCapabilities implements Parcelable { private static final String TAG = "NetworkCapabilities"; private static final boolean DBG = false; + /** + * @hide + */ public NetworkCapabilities() { } @@ -154,58 +157,64 @@ public final class NetworkCapabilities implements Parcelable { * Multiple capabilities may be applied sequentially. Note that when searching * for a network to satisfy a request, all capabilities requested must be satisfied. * - * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added. + * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added. + * @return This NetworkCapability to facilitate chaining. + * @hide */ - public void addNetworkCapability(int networkCapability) { - if (networkCapability < MIN_NET_CAPABILITY || - networkCapability > MAX_NET_CAPABILITY) { + public NetworkCapabilities addCapability(int capability) { + if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { throw new IllegalArgumentException("NetworkCapability out of range"); } - mNetworkCapabilities |= 1 << networkCapability; + mNetworkCapabilities |= 1 << capability; + return this; } /** * Removes (if found) the given capability from this {@code NetworkCapability} instance. * - * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed. + * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed. + * @return This NetworkCapability to facilitate chaining. + * @hide */ - public void removeNetworkCapability(int networkCapability) { - if (networkCapability < MIN_NET_CAPABILITY || - networkCapability > MAX_NET_CAPABILITY) { + public NetworkCapabilities removeCapability(int capability) { + if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { throw new IllegalArgumentException("NetworkCapability out of range"); } - mNetworkCapabilities &= ~(1 << networkCapability); + mNetworkCapabilities &= ~(1 << capability); + return this; } /** * Gets all the capabilities set on this {@code NetworkCapability} instance. * - * @return a {@link Collection} of {@code NetworkCapabilities.NET_CAPABILITY_*} values + * @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values * for this instance. + * @hide */ - public Collection getNetworkCapabilities() { + public int[] getCapabilities() { return enumerateBits(mNetworkCapabilities); } /** * Tests for the presence of a capabilitity on this instance. * - * @param networkCapability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for. + * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for. * @return {@code true} if set on this instance. */ - public boolean hasCapability(int networkCapability) { - if (networkCapability < MIN_NET_CAPABILITY || - networkCapability > MAX_NET_CAPABILITY) { + public boolean hasCapability(int capability) { + if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { return false; } - return ((mNetworkCapabilities & (1 << networkCapability)) != 0); + return ((mNetworkCapabilities & (1 << capability)) != 0); } - private Collection enumerateBits(long val) { - ArrayList result = new ArrayList(); + private int[] enumerateBits(long val) { + int size = Long.bitCount(val); + int[] result = new int[size]; + int index = 0; int resource = 0; while (val > 0) { - if ((val & 1) == 1) result.add(resource); + if ((val & 1) == 1) result[index++] = resource; val = val >> 1; resource++; } @@ -265,33 +274,40 @@ public final class NetworkCapabilities implements Parcelable { * {@code NetworkCapabilities.NET_CAPABILITY_*} listed above. * * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be added. + * @return This NetworkCapability to facilitate chaining. + * @hide */ - public void addTransportType(int transportType) { + public NetworkCapabilities addTransportType(int transportType) { if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { throw new IllegalArgumentException("TransportType out of range"); } mTransportTypes |= 1 << transportType; + return this; } /** * Removes (if found) the given transport from this {@code NetworkCapability} instance. * * @param transportType the {@code NetworkCapabilities.TRANSPORT_*} to be removed. + * @return This NetworkCapability to facilitate chaining. + * @hide */ - public void removeTransportType(int transportType) { + public NetworkCapabilities removeTransportType(int transportType) { if (transportType < MIN_TRANSPORT || transportType > MAX_TRANSPORT) { throw new IllegalArgumentException("TransportType out of range"); } mTransportTypes &= ~(1 << transportType); + return this; } /** * Gets all the transports set on this {@code NetworkCapability} instance. * - * @return a {@link Collection} of {@code NetworkCapabilities.TRANSPORT_*} values + * @return an array of {@code NetworkCapabilities.TRANSPORT_*} values * for this instance. + * @hide */ - public Collection getTransportTypes() { + public int[] getTransportTypes() { return enumerateBits(mTransportTypes); } @@ -340,6 +356,7 @@ public final class NetworkCapabilities implements Parcelable { * fast backhauls and slow backhauls. * * @param upKbps the estimated first hop upstream (device to network) bandwidth. + * @hide */ public void setLinkUpstreamBandwidthKbps(int upKbps) { mLinkUpBandwidthKbps = upKbps; @@ -368,6 +385,7 @@ public final class NetworkCapabilities implements Parcelable { * fast backhauls and slow backhauls. * * @param downKbps the estimated first hop downstream (network to device) bandwidth. + * @hide */ public void setLinkDownstreamBandwidthKbps(int downKbps) { mLinkDownBandwidthKbps = downKbps; @@ -464,24 +482,22 @@ public final class NetworkCapabilities implements Parcelable { }; public String toString() { - Collection types = getTransportTypes(); - String transports = (types.size() > 0 ? " Transports: " : ""); - Iterator i = types.iterator(); - while (i.hasNext()) { - switch (i.next()) { + int[] types = getTransportTypes(); + String transports = (types.length > 0 ? " Transports: " : ""); + for (int i = 0; i < types.length;) { + switch (types[i]) { case TRANSPORT_CELLULAR: transports += "CELLULAR"; break; case TRANSPORT_WIFI: transports += "WIFI"; break; case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break; case TRANSPORT_ETHERNET: transports += "ETHERNET"; break; } - if (i.hasNext()) transports += "|"; + if (++i < types.length) transports += "|"; } - types = getNetworkCapabilities(); - String capabilities = (types.size() > 0 ? " Capabilities: " : ""); - i = types.iterator(); - while (i.hasNext()) { - switch (i.next().intValue()) { + types = getCapabilities(); + String capabilities = (types.length > 0 ? " Capabilities: " : ""); + for (int i = 0; i < types.length; ) { + switch (types[i]) { case NET_CAPABILITY_MMS: capabilities += "MMS"; break; case NET_CAPABILITY_SUPL: capabilities += "SUPL"; break; case NET_CAPABILITY_DUN: capabilities += "DUN"; break; @@ -497,7 +513,7 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_INTERNET: capabilities += "INTERNET"; break; case NET_CAPABILITY_NOT_RESTRICTED: capabilities += "NOT_RESTRICTED"; break; } - if (i.hasNext()) capabilities += "&"; + if (++i < types.length) capabilities += "&"; } String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" + diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java index 47377e97be..7911c729d3 100644 --- a/core/java/android/net/NetworkRequest.java +++ b/core/java/android/net/NetworkRequest.java @@ -22,19 +22,14 @@ import android.os.Parcelable; import java.util.concurrent.atomic.AtomicInteger; /** - * Defines a request for a network, made by calling {@link ConnectivityManager#requestNetwork} - * or {@link ConnectivityManager#listenForNetwork}. - * - * This token records the {@link NetworkCapabilities} used to make the request and identifies - * the request. It should be used to release the request via - * {@link ConnectivityManager#releaseNetworkRequest} when the network is no longer desired. + * Defines a request for a network, made through {@link NetworkRequest.Builder} and used + * to request a network via {@link ConnectivityManager#requestNetwork} or listen for changes + * via {@link ConnectivityManager#listenForNetwork}. */ public class NetworkRequest implements Parcelable { /** - * The {@link NetworkCapabilities} that define this request. This should not be modified. - * The networkCapabilities of the request are set when - * {@link ConnectivityManager#requestNetwork} is called and the value is presented here - * as a convenient reminder of what was requested. + * The {@link NetworkCapabilities} that define this request. + * @hide */ public final NetworkCapabilities networkCapabilities; @@ -71,6 +66,95 @@ public class NetworkRequest implements Parcelable { this.legacyType = that.legacyType; } + /** + * Builder used to create {@link NetworkRequest} objects. Specify the Network features + * needed in terms of {@link NetworkCapabilities} features + */ + public static class Builder { + private final NetworkCapabilities mNetworkCapabilities = new NetworkCapabilities(); + + /** + * Default constructor for Builder. + */ + public Builder() {} + + /** + * Build {@link NetworkRequest} give the current set of capabilities. + */ + public NetworkRequest build() { + return new NetworkRequest(mNetworkCapabilities, ConnectivityManager.TYPE_NONE, + ConnectivityManager.REQUEST_ID_UNSET); + } + + /** + * Add the given capability requirement to this builder. These represent + * the requested network's required capabilities. Note that when searching + * for a network to satisfy a request, all capabilities requested must be + * satisfied. See {@link NetworkCapabilities} for {@code NET_CAPABILITIY_*} + * definitions. + * + * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to add. + * @return The builder to facilitate chaining + * {@code builder.addCapability(...).addCapability();}. + */ + public Builder addCapability(int capability) { + mNetworkCapabilities.addCapability(capability); + return this; + } + + /** + * Removes (if found) the given capability from this builder instance. + * + * @param capability The {@code NetworkCapabilities.NET_CAPABILITY_*} to remove. + * @return The builder to facilitate chaining. + */ + public Builder removeCapability(int capability) { + mNetworkCapabilities.removeCapability(capability); + return this; + } + + /** + * Adds the given transport requirement to this builder. These represent + * the set of allowed transports for the request. Only networks using one + * of these transports will satisfy the request. If no particular transports + * are required, none should be specified here. See {@link NetworkCapabilities} + * for {@code TRANSPORT_*} definitions. + * + * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to add. + * @return The builder to facilitate chaining. + */ + public Builder addTransportType(int transportType) { + mNetworkCapabilities.addTransportType(transportType); + return this; + } + + /** + * Removes (if found) the given transport from this builder instance. + * + * @param transportType The {@code NetworkCapabilities.TRANSPORT_*} to remove. + * @return The builder to facilitate chaining. + */ + public Builder removeTransportType(int transportType) { + mNetworkCapabilities.removeTransportType(transportType); + return this; + } + + /** + * @hide + */ + public Builder setLinkUpstreamBandwidthKbps(int upKbps) { + mNetworkCapabilities.setLinkUpstreamBandwidthKbps(upKbps); + return this; + } + /** + * @hide + */ + public Builder setLinkDownstreamBandwidthKbps(int downKbps) { + mNetworkCapabilities.setLinkDownstreamBandwidthKbps(downKbps); + return this; + } + } + // implement the Parcelable interface public int describeContents() { return 0; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 70b9d4410c..2ece189f8f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -630,8 +630,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (DBG) log("ConnectivityService starting up"); NetworkCapabilities netCap = new NetworkCapabilities(); - netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); - netCap.addNetworkCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); + netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); + netCap.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); mDefaultRequest = new NetworkRequest(netCap, TYPE_NONE, nextNetworkRequestId()); NetworkRequestInfo nri = new NetworkRequestInfo(null, mDefaultRequest, new Binder(), NetworkRequestInfo.REQUEST);