diff options
Diffstat (limited to 'core')
-rw-r--r-- | core/java/android/app/ActivityThread.java | 6 | ||||
-rw-r--r-- | core/java/android/bluetooth/BluetoothAdapter.java | 18 | ||||
-rw-r--r-- | core/java/android/bluetooth/IBluetooth.aidl | 1 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/BluetoothLeScanner.java | 39 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/ScanCallback.java | 10 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/ScanFilter.java | 10 | ||||
-rw-r--r-- | core/java/android/bluetooth/le/ScanSettings.java | 113 | ||||
-rw-r--r-- | core/java/android/net/ConnectivityManager.java | 135 | ||||
-rw-r--r-- | core/java/android/net/DhcpStateMachine.java | 177 | ||||
-rw-r--r-- | core/java/android/net/Network.java | 12 | ||||
-rw-r--r-- | core/java/android/net/NetworkUtils.java | 2 | ||||
-rw-r--r-- | core/java/android/net/Proxy.java | 16 | ||||
-rw-r--r-- | core/java/android/net/VpnService.java | 2 | ||||
-rw-r--r-- | core/jni/android_net_NetUtils.cpp | 4 |
14 files changed, 416 insertions, 129 deletions
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index ed05321..9ba3049 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -864,10 +864,10 @@ public final class ActivityThread { } public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) { - final Network network = ConnectivityManager.getProcessDefaultNetwork(); + final ConnectivityManager cm = ConnectivityManager.from(getSystemContext()); + final Network network = cm.getBoundNetworkForProcess(); if (network != null) { - Proxy.setHttpProxySystemProperty( - ConnectivityManager.from(getSystemContext()).getDefaultProxy()); + Proxy.setHttpProxySystemProperty(cm.getDefaultProxy()); } else { Proxy.setHttpProxySystemProperty(host, port, exclList, pacFileUrl); } diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index edb768d..2b3cf34 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -995,6 +995,24 @@ public final class BluetoothAdapter { } /** + * Return true if hardware has entries available for matching beacons + * + * @return true if there are hw entries available for matching beacons + * @hide + */ + public boolean isHardwareTrackingFiltersAvailable() { + if (getState() != STATE_ON) return false; + try { + synchronized(mManagerCallback) { + if(mService != null) return (mService.numOfHwTrackFiltersAvailable() != 0); + } + } catch (RemoteException e) { + Log.e(TAG, "", e); + } + return false; + } + + /** * Return the record of {@link BluetoothActivityEnergyInfo} object that * has the activity and energy info. This can be used to ascertain what * the controller has been up to, since the last sample. diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index dabb1ce..299f4c8 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -98,6 +98,7 @@ interface IBluetooth boolean isActivityAndEnergyReportingSupported(); void getActivityEnergyInfoFromController(); BluetoothActivityEnergyInfo reportActivityInfo(); + int numOfHwTrackFiltersAvailable(); // for dumpsys support String dump(); diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index 93ea299..73a1907 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -128,6 +128,16 @@ public final class BluetoothLeScanner { ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); return; } + if (!isHardwareResourcesAvailableForScan(settings)) { + postCallbackError(callback, + ScanCallback.SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES); + return; + } + if (!isSettingsAndFilterComboAllowed(settings, filters)) { + postCallbackError(callback, + ScanCallback.SCAN_FAILED_FEATURE_UNSUPPORTED); + return; + } BleScanCallbackWrapper wrapper = new BleScanCallbackWrapper(gatt, filters, settings, callback, resultStorages); wrapper.startRegisteration(); @@ -394,4 +404,33 @@ public final class BluetoothLeScanner { } return false; } + + private boolean isSettingsAndFilterComboAllowed(ScanSettings settings, + List <ScanFilter> filterList) { + final int callbackType = settings.getCallbackType(); + // If onlost/onfound is requested, a non-empty filter is expected + if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH + | ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) { + if (filterList == null) { + return false; + } + for (ScanFilter filter : filterList) { + if (filter.isAllFieldsEmpty()) { + return false; + } + } + } + return true; + } + + private boolean isHardwareResourcesAvailableForScan(ScanSettings settings) { + final int callbackType = settings.getCallbackType(); + if ((callbackType & ScanSettings.CALLBACK_TYPE_FIRST_MATCH) != 0 + || (callbackType & ScanSettings.CALLBACK_TYPE_MATCH_LOST) != 0) { + // For onlost/onfound, we required hw support be available + return (mBluetoothAdapter.isOffloadedFilteringSupported() && + mBluetoothAdapter.isHardwareTrackingFiltersAvailable()); + } + return true; + } } diff --git a/core/java/android/bluetooth/le/ScanCallback.java b/core/java/android/bluetooth/le/ScanCallback.java index 05782a8..27b96bd 100644 --- a/core/java/android/bluetooth/le/ScanCallback.java +++ b/core/java/android/bluetooth/le/ScanCallback.java @@ -45,10 +45,16 @@ public abstract class ScanCallback { public static final int SCAN_FAILED_FEATURE_UNSUPPORTED = 4; /** + * Fails to start scan as it is out of hardware resources. + * @hide + */ + public static final int SCAN_FAILED_OUT_OF_HARDWARE_RESOURCES = 5; + + /** * Callback when a BLE advertisement has been found. * - * @param callbackType Determines how this callback was triggered. Currently could only be - * {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES}. + * @param callbackType Determines how this callback was triggered. Could be of + * {@link ScanSettings#CALLBACK_TYPE_ALL_MATCHES} * @param result A Bluetooth LE scan result. */ public void onScanResult(int callbackType, ScanResult result) { diff --git a/core/java/android/bluetooth/le/ScanFilter.java b/core/java/android/bluetooth/le/ScanFilter.java index 5025218..92a3817 100644 --- a/core/java/android/bluetooth/le/ScanFilter.java +++ b/core/java/android/bluetooth/le/ScanFilter.java @@ -67,6 +67,8 @@ public final class ScanFilter implements Parcelable { private final byte[] mManufacturerData; @Nullable private final byte[] mManufacturerDataMask; + private static final ScanFilter EMPTY = new ScanFilter.Builder().build() ; + private ScanFilter(String name, String deviceAddress, ParcelUuid uuid, ParcelUuid uuidMask, ParcelUuid serviceDataUuid, @@ -410,6 +412,14 @@ public final class ScanFilter implements Parcelable { } /** + * Checks if the scanfilter is empty + * @hide + */ + public boolean isAllFieldsEmpty() { + return EMPTY.equals(this); + } + + /** * Builder class for {@link ScanFilter}. */ public static final class Builder { diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java index 0106686..f103cae 100644 --- a/core/java/android/bluetooth/le/ScanSettings.java +++ b/core/java/android/bluetooth/le/ScanSettings.java @@ -59,7 +59,6 @@ public final class ScanSettings implements Parcelable { /** * A result callback is only triggered for the first advertisement packet received that matches * the filter criteria. - * * @hide */ @SystemApi @@ -68,15 +67,53 @@ public final class ScanSettings implements Parcelable { /** * Receive a callback when advertisements are no longer received from a device that has been * previously reported by a first match callback. - * * @hide */ @SystemApi public static final int CALLBACK_TYPE_MATCH_LOST = 4; + + /** + * Determines how many advertisements to match per filter, as this is scarce hw resource + */ + /** + * Match one advertisement per filter + * @hide + */ + public static final int MATCH_NUM_ONE_ADVERTISEMENT = 1; + + /** + * Match few advertisement per filter, depends on current capability and availibility of + * the resources in hw + * @hide + */ + public static final int MATCH_NUM_FEW_ADVERTISEMENT = 2; + + /** + * Match as many advertisement per filter as hw could allow, depends on current + * capability and availibility of the resources in hw + * @hide + */ + public static final int MATCH_NUM_MAX_ADVERTISEMENT = 3; + + + /** + * In Aggressive mode, hw will determine a match sooner even with feeble signal strength + * and few number of sightings/match in a duration. + * @hide + */ + public static final int MATCH_MODE_AGGRESSIVE = 1; + /** - * Request full scan results which contain the device, rssi, advertising data, scan response as - * well as the scan timestamp. + * For sticky mode, higher threshold of signal strength and sightings is required + * before reporting by hw + * @hide + */ + public static final int MATCH_MODE_STICKY = 2; + + /** + * Request full scan results which contain the device, rssi, advertising data, scan response + * as well as the scan timestamp. * * @hide */ @@ -106,6 +143,10 @@ public final class ScanSettings implements Parcelable { // Time of delay for reporting the scan result private long mReportDelayMillis; + private int mMatchMode; + + private int mNumOfMatchesPerFilter; + public int getScanMode() { return mScanMode; } @@ -119,6 +160,20 @@ public final class ScanSettings implements Parcelable { } /** + * @hide + */ + public int getMatchMode() { + return mMatchMode; + } + + /** + * @hide + */ + public int getNumOfMatches() { + return mNumOfMatchesPerFilter; + } + + /** * Returns report delay timestamp based on the device clock. */ public long getReportDelayMillis() { @@ -126,11 +181,13 @@ public final class ScanSettings implements Parcelable { } private ScanSettings(int scanMode, int callbackType, int scanResultType, - long reportDelayMillis) { + long reportDelayMillis, int matchMode, int numOfMatchesPerFilter) { mScanMode = scanMode; mCallbackType = callbackType; mScanResultType = scanResultType; mReportDelayMillis = reportDelayMillis; + mNumOfMatchesPerFilter = numOfMatchesPerFilter; + mMatchMode = numOfMatchesPerFilter; } private ScanSettings(Parcel in) { @@ -138,6 +195,8 @@ public final class ScanSettings implements Parcelable { mCallbackType = in.readInt(); mScanResultType = in.readInt(); mReportDelayMillis = in.readLong(); + mMatchMode = in.readInt(); + mNumOfMatchesPerFilter = in.readInt(); } @Override @@ -146,6 +205,8 @@ public final class ScanSettings implements Parcelable { dest.writeInt(mCallbackType); dest.writeInt(mScanResultType); dest.writeLong(mReportDelayMillis); + dest.writeInt(mMatchMode); + dest.writeInt(mNumOfMatchesPerFilter); } @Override @@ -174,7 +235,8 @@ public final class ScanSettings implements Parcelable { private int mCallbackType = CALLBACK_TYPE_ALL_MATCHES; private int mScanResultType = SCAN_RESULT_TYPE_FULL; private long mReportDelayMillis = 0; - + private int mMatchMode = MATCH_MODE_AGGRESSIVE; + private int mNumOfMatchesPerFilter = MATCH_NUM_ONE_ADVERTISEMENT; /** * Set scan mode for Bluetooth LE scan. * @@ -255,11 +317,48 @@ public final class ScanSettings implements Parcelable { } /** + * Set the number of matches for Bluetooth LE scan filters hardware match + * + * @param numOfMatches The num of matches can be one of + * {@link ScanSettings#MATCH_NUM_ONE_ADVERTISEMENT} or + * {@link ScanSettings#MATCH_NUM_FEW_ADVERTISEMENT} or + * {@link ScanSettings#MATCH_NUM_MAX_ADVERTISEMENT} + * @throws IllegalArgumentException If the {@code matchMode} is invalid. + * @hide + */ + public Builder setNumOfMatches(int numOfMatches) { + if (numOfMatches < MATCH_NUM_ONE_ADVERTISEMENT + || numOfMatches > MATCH_NUM_MAX_ADVERTISEMENT) { + throw new IllegalArgumentException("invalid numOfMatches " + numOfMatches); + } + mNumOfMatchesPerFilter = numOfMatches; + return this; + } + + /** + * Set match mode for Bluetooth LE scan filters hardware match + * + * @param matchMode The match mode can be one of + * {@link ScanSettings#MATCH_MODE_AGGRESSIVE} or + * {@link ScanSettings#MATCH_MODE_STICKY} + * @throws IllegalArgumentException If the {@code matchMode} is invalid. + * @hide + */ + public Builder setMatchMode(int matchMode) { + if (matchMode < MATCH_MODE_AGGRESSIVE + || matchMode > MATCH_MODE_STICKY) { + throw new IllegalArgumentException("invalid matchMode " + matchMode); + } + mMatchMode = matchMode; + return this; + } + + /** * Build {@link ScanSettings}. */ public ScanSettings build() { return new ScanSettings(mScanMode, mCallbackType, mScanResultType, - mReportDelayMillis); + mReportDelayMillis, mMatchMode, mNumOfMatchesPerFilter); } } } diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 3abccbc..da2c5e0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -589,9 +589,9 @@ public class ConnectivityManager { * network. * * @return a {@link NetworkInfo} object for the current default network - * or {@code null} if no network default network is currently active + * or {@code null} if no default network is currently active * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. */ public NetworkInfo getActiveNetworkInfo() { @@ -738,9 +738,9 @@ public class ConnectivityManager { * network. * * @return a {@link NetworkInfo} object for the current default network - * or {@code null} if no network default network is currently active + * or {@code null} if no default network is currently active * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * * {@hide} @@ -760,7 +760,7 @@ public class ConnectivityManager { * for the current default network, or {@code null} if there * is no current default network. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -780,7 +780,7 @@ public class ConnectivityManager { * for the given networkType, or {@code null} if there is * no current default network. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -830,7 +830,7 @@ public class ConnectivityManager { * @return a boolean, {@code true} indicating success. All network types * will be tried, even if some fail. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ @@ -851,7 +851,7 @@ public class ConnectivityManager { * {@code} false to turn it off. * @return a boolean, {@code true} indicating success. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ @@ -1202,7 +1202,7 @@ public class ConnectivityManager { * @return {@code true} on success, {@code false} on failure * * @deprecated Deprecated in favor of the {@link #requestNetwork}, - * {@link #setProcessDefaultNetwork} and {@link Network#getSocketFactory} api. + * {@link #bindProcessToNetwork} and {@link Network#getSocketFactory} api. */ public boolean requestRouteToHost(int networkType, int hostAddress) { return requestRouteToHostAddress(networkType, NetworkUtils.intToInetAddress(hostAddress)); @@ -1220,7 +1220,7 @@ public class ConnectivityManager { * @return {@code true} on success, {@code false} on failure * @hide * @deprecated Deprecated in favor of the {@link #requestNetwork} and - * {@link #setProcessDefaultNetwork} api. + * {@link #bindProcessToNetwork} api. */ public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { try { @@ -1273,7 +1273,7 @@ public class ConnectivityManager { * network is active. Quota status can change rapidly, so these values * shouldn't be cached. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * * @hide @@ -1345,7 +1345,7 @@ public class ConnectivityManager { * listener. * <p> * If the process default network has been set with - * {@link ConnectivityManager#setProcessDefaultNetwork} this function will not + * {@link ConnectivityManager#bindProcessToNetwork} this function will not * reflect the process's default, but the system default. * * @param l The listener to be told when the network is active. @@ -1430,11 +1430,20 @@ public class ConnectivityManager { * situations where a Context pointer is unavailable. * @hide */ - public static ConnectivityManager getInstance() { - if (sInstance == null) { + static ConnectivityManager getInstanceOrNull() { + return sInstance; + } + + /** + * @deprecated - use getSystemService. This is a kludge to support static access in certain + * situations where a Context pointer is unavailable. + * @hide + */ + private static ConnectivityManager getInstance() { + if (getInstanceOrNull() == null) { throw new IllegalStateException("No ConnectivityManager yet constructed"); } - return sInstance; + return getInstanceOrNull(); } /** @@ -1443,7 +1452,7 @@ public class ConnectivityManager { * * @return an array of 0 or more Strings of tetherable interface names. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -1460,7 +1469,7 @@ public class ConnectivityManager { * * @return an array of 0 or more String of currently tethered interface names. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -1483,7 +1492,7 @@ public class ConnectivityManager { * @return an array of 0 or more String indicating the interface names * which failed to tether. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -1521,7 +1530,7 @@ public class ConnectivityManager { * @param iface the interface name to tether. * @return error a {@code TETHER_ERROR} value indicating success or failure type * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ @@ -1539,7 +1548,7 @@ public class ConnectivityManager { * @param iface the interface name to untether. * @return error a {@code TETHER_ERROR} value indicating success or failure type * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ @@ -1558,7 +1567,7 @@ public class ConnectivityManager { * * @return a boolean - {@code true} indicating Tethering is supported. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -1578,7 +1587,7 @@ public class ConnectivityManager { * @return an array of 0 or more regular expression Strings defining * what interfaces are considered tetherable usb interfaces. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -1598,7 +1607,7 @@ public class ConnectivityManager { * @return an array of 0 or more regular expression Strings defining * what interfaces are considered tetherable wifi interfaces. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -1618,7 +1627,7 @@ public class ConnectivityManager { * @return an array of 0 or more regular expression Strings defining * what interfaces are considered tetherable bluetooth interfaces. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -1640,7 +1649,7 @@ public class ConnectivityManager { * @param enable a boolean - {@code true} to enable tethering * @return error a {@code TETHER_ERROR} value indicating success or failure type * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. * {@hide} */ @@ -1683,7 +1692,7 @@ public class ConnectivityManager { * @return error The error code of the last error tethering or untethering the named * interface * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * {@hide} */ @@ -1702,7 +1711,7 @@ public class ConnectivityManager { * @param networkType The type of network you want to report on * @param percentage The quality of the connection 0 is bad, 100 is good * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#STATUS_BAR}. * {@hide} */ @@ -1738,7 +1747,7 @@ public class ConnectivityManager { * @param p The a {@link ProxyInfo} object defining the new global * HTTP proxy. A {@code null} value will clear the global HTTP proxy. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * android.Manifest.permission#CONNECTIVITY_INTERNAL. * @hide */ @@ -1755,7 +1764,7 @@ public class ConnectivityManager { * @return {@link ProxyInfo} for the current global HTTP proxy or {@code null} * if no global HTTP proxy is set. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * @hide */ @@ -1770,15 +1779,14 @@ public class ConnectivityManager { /** * Get the current default HTTP proxy settings. If a global proxy is set it will be returned, * otherwise if this process is bound to a {@link Network} using - * {@link #setProcessDefaultNetwork} then that {@code Network}'s proxy is returned, otherwise + * {@link #bindProcessToNetwork} then that {@code Network}'s proxy is returned, otherwise * the default network's proxy is returned. * * @return the {@link ProxyInfo} for the current HTTP proxy, or {@code null} if no * HTTP proxy is active. - * @hide */ public ProxyInfo getDefaultProxy() { - final Network network = getProcessDefaultNetwork(); + final Network network = getBoundNetworkForProcess(); if (network != null) { final ProxyInfo globalProxy = getGlobalProxy(); if (globalProxy != null) return globalProxy; @@ -1804,7 +1812,7 @@ public class ConnectivityManager { * @param networkType The network type we'd like to check * @return {@code true} if supported, else {@code false} * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. * @hide */ @@ -1826,7 +1834,7 @@ public class ConnectivityManager { * @return {@code true} if large transfers should be avoided, otherwise * {@code false}. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}. */ public boolean isActiveNetworkMetered() { @@ -1862,7 +1870,7 @@ public class ConnectivityManager { * in question. * @param isCaptivePortal true/false. * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. * {@hide} */ @@ -1937,7 +1945,7 @@ public class ConnectivityManager { * * @param enable whether to enable airplane mode or not * - * <p>This method requires the call to hold the permission + * <p>This method requires the caller to hold the permission * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. * @hide */ @@ -2338,9 +2346,8 @@ public class ConnectivityManager { * successfully finding a network for the applications request. Retrieve it with * {@link android.content.Intent#getParcelableExtra(String)}. * <p> - * Note that if you intend to invoke {@link #setProcessDefaultNetwork} or - * {@link Network#openConnection(java.net.URL)} then you must get a - * ConnectivityManager instance before doing so. + * Note that if you intend to invoke {@link Network#openConnection(java.net.URL)} + * then you must get a ConnectivityManager instance before doing so. */ public static final String EXTRA_NETWORK = "android.net.extra.NETWORK"; @@ -2491,15 +2498,42 @@ public class ConnectivityManager { * Sockets created by Network.getSocketFactory().createSocket() and * performing network-specific host name resolutions via * {@link Network#getAllByName Network.getAllByName} is preferred to calling + * {@code bindProcessToNetwork}. + * + * @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 boolean bindProcessToNetwork(Network network) { + // Forcing callers to call thru non-static function ensures ConnectivityManager + // instantiated. + return setProcessDefaultNetwork(network); + } + + /** + * 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. + * @deprecated This function can throw {@link IllegalStateException}. Use + * {@link #bindProcessToNetwork} instead. {@code bindProcessToNetwork} + * is a direct replacement. */ public static boolean setProcessDefaultNetwork(Network network) { int netId = (network == null) ? NETID_UNSET : network.netId; - if (netId == NetworkUtils.getNetworkBoundToProcess()) { + if (netId == NetworkUtils.getBoundNetworkForProcess()) { return true; } if (NetworkUtils.bindProcessToNetwork(netId)) { @@ -2519,19 +2553,34 @@ public class ConnectivityManager { /** * Returns the {@link Network} currently bound to this process via - * {@link #setProcessDefaultNetwork}, or {@code null} if no {@link Network} is explicitly bound. + * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound. + * + * @return {@code Network} to which this process is bound, or {@code null}. + */ + public Network getBoundNetworkForProcess() { + // Forcing callers to call thru non-static function ensures ConnectivityManager + // instantiated. + return getProcessDefaultNetwork(); + } + + /** + * Returns the {@link Network} currently bound to this process via + * {@link #bindProcessToNetwork}, or {@code null} if no {@link Network} is explicitly bound. * * @return {@code Network} to which this process is bound, or {@code null}. + * @deprecated Using this function can lead to other functions throwing + * {@link IllegalStateException}. Use {@link #getBoundNetworkForProcess} instead. + * {@code getBoundNetworkForProcess} is a direct replacement. */ public static Network getProcessDefaultNetwork() { - int netId = NetworkUtils.getNetworkBoundToProcess(); + int netId = NetworkUtils.getBoundNetworkForProcess(); if (netId == NETID_UNSET) return null; return new Network(netId); } /** * Binds host resolutions performed by this process to {@code network}. - * {@link #setProcessDefaultNetwork} takes precedence over this setting. + * {@link #bindProcessToNetwork} 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. diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java index 1b8adc8..73ef78e 100644 --- a/core/java/android/net/DhcpStateMachine.java +++ b/core/java/android/net/DhcpStateMachine.java @@ -37,7 +37,7 @@ import android.util.Log; * StateMachine that interacts with the native DHCP client and can talk to * a controller that also needs to be a StateMachine * - * The Dhcp state machine provides the following features: + * The DhcpStateMachine provides the following features: * - Wakeup and renewal using the native DHCP client (which will not renew * on its own when the device is in suspend state and this can lead to device * holding IP address beyond expiry) @@ -72,11 +72,6 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { //Used for sanity check on setting up renewal private static final int MIN_RENEWAL_TIME_SECS = 5 * 60; // 5 minutes - private enum DhcpAction { - START, - RENEW - }; - private final String mInterfaceName; private boolean mRegisteredForPreDhcpNotification = false; @@ -99,6 +94,9 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { * after pre DHCP action is complete */ public static final int CMD_PRE_DHCP_ACTION_COMPLETE = BASE + 7; + /* Command from ourselves to see if DHCP results are available */ + private static final int CMD_GET_DHCP_RESULTS = BASE + 8; + /* Message.arg1 arguments to CMD_POST_DHCP notification */ public static final int DHCP_SUCCESS = 1; public static final int DHCP_FAILURE = 2; @@ -108,6 +106,7 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { private State mWaitBeforeStartState = new WaitBeforeStartState(); private State mRunningState = new RunningState(); private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(); + private State mPollingState = new PollingState(); private DhcpStateMachine(Context context, StateMachine controller, String intf) { super(TAG); @@ -139,6 +138,7 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { addState(mDefaultState); addState(mStoppedState, mDefaultState); addState(mWaitBeforeStartState, mDefaultState); + addState(mPollingState, mDefaultState); addState(mRunningState, mDefaultState); addState(mWaitBeforeRenewalState, mDefaultState); @@ -206,6 +206,10 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { @Override public void enter() { if (DBG) Log.d(TAG, getName() + "\n"); + if (!NetworkUtils.stopDhcp(mInterfaceName)) { + Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); + } + mDhcpResults = null; } @Override @@ -219,7 +223,7 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { mController.sendMessage(CMD_PRE_DHCP_ACTION); transitionTo(mWaitBeforeStartState); } else { - if (runDhcp(DhcpAction.START)) { + if (runDhcpStart()) { transitionTo(mRunningState); } } @@ -247,10 +251,10 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); switch (message.what) { case CMD_PRE_DHCP_ACTION_COMPLETE: - if (runDhcp(DhcpAction.START)) { + if (runDhcpStart()) { transitionTo(mRunningState); } else { - transitionTo(mStoppedState); + transitionTo(mPollingState); } break; case CMD_STOP_DHCP: @@ -267,6 +271,55 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { } } + class PollingState extends State { + private static final long MAX_DELAY_SECONDS = 32; + private long delaySeconds; + + private void scheduleNextResultsCheck() { + sendMessageDelayed(obtainMessage(CMD_GET_DHCP_RESULTS), delaySeconds * 1000); + delaySeconds *= 2; + if (delaySeconds > MAX_DELAY_SECONDS) { + delaySeconds = MAX_DELAY_SECONDS; + } + } + + @Override + public void enter() { + if (DBG) Log.d(TAG, "Entering " + getName() + "\n"); + delaySeconds = 1; + scheduleNextResultsCheck(); + } + + @Override + public boolean processMessage(Message message) { + boolean retValue = HANDLED; + if (DBG) Log.d(TAG, getName() + message.toString() + "\n"); + switch (message.what) { + case CMD_GET_DHCP_RESULTS: + if (DBG) Log.d(TAG, "GET_DHCP_RESULTS on " + mInterfaceName); + if (dhcpSucceeded()) { + transitionTo(mRunningState); + } else { + scheduleNextResultsCheck(); + } + break; + case CMD_STOP_DHCP: + transitionTo(mStoppedState); + break; + default: + retValue = NOT_HANDLED; + break; + } + return retValue; + } + + @Override + public void exit() { + if (DBG) Log.d(TAG, "Exiting " + getName() + "\n"); + removeMessages(CMD_GET_DHCP_RESULTS); + } + } + class RunningState extends State { @Override public void enter() { @@ -280,9 +333,6 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { switch (message.what) { case CMD_STOP_DHCP: mAlarmManager.cancel(mDhcpRenewalIntent); - if (!NetworkUtils.stopDhcp(mInterfaceName)) { - Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); - } transitionTo(mStoppedState); break; case CMD_RENEW_DHCP: @@ -292,7 +342,7 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { transitionTo(mWaitBeforeRenewalState); //mDhcpRenewWakeLock is released in WaitBeforeRenewalState } else { - if (!runDhcp(DhcpAction.RENEW)) { + if (!runDhcpRenew()) { transitionTo(mStoppedState); } mDhcpRenewWakeLock.release(); @@ -321,13 +371,10 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { switch (message.what) { case CMD_STOP_DHCP: mAlarmManager.cancel(mDhcpRenewalIntent); - if (!NetworkUtils.stopDhcp(mInterfaceName)) { - Log.e(TAG, "Failed to stop Dhcp on " + mInterfaceName); - } transitionTo(mStoppedState); break; case CMD_PRE_DHCP_ACTION_COMPLETE: - if (runDhcp(DhcpAction.RENEW)) { + if (runDhcpRenew()) { transitionTo(mRunningState); } else { transitionTo(mStoppedState); @@ -348,52 +395,68 @@ public class DhcpStateMachine extends BaseDhcpStateMachine { } } - private boolean runDhcp(DhcpAction dhcpAction) { - boolean success = false; + private boolean dhcpSucceeded() { DhcpResults dhcpResults = new DhcpResults(); - - if (dhcpAction == DhcpAction.START) { - /* Stop any existing DHCP daemon before starting new */ - NetworkUtils.stopDhcp(mInterfaceName); - if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName); - success = NetworkUtils.runDhcp(mInterfaceName, dhcpResults); - } else if (dhcpAction == DhcpAction.RENEW) { - if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName); - success = NetworkUtils.runDhcpRenew(mInterfaceName, dhcpResults); - if (success) dhcpResults.updateFromDhcpRequest(mDhcpResults); + if (!NetworkUtils.getDhcpResults(mInterfaceName, dhcpResults)) { + return false; } - if (success) { - if (DBG) Log.d(TAG, "DHCP succeeded on " + mInterfaceName); - long leaseDuration = dhcpResults.leaseDuration; //int to long conversion - - //Sanity check for renewal - if (leaseDuration >= 0) { - //TODO: would be good to notify the user that his network configuration is - //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS - if (leaseDuration < MIN_RENEWAL_TIME_SECS) { - leaseDuration = MIN_RENEWAL_TIME_SECS; - } - //Do it a bit earlier than half the lease duration time - //to beat the native DHCP client and avoid extra packets - //48% for one hour lease time = 29 minutes - mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, - SystemClock.elapsedRealtime() + - leaseDuration * 480, //in milliseconds - mDhcpRenewalIntent); - } else { - //infinite lease time, no renewal needed - } - mDhcpResults = dhcpResults; - mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults) - .sendToTarget(); + if (DBG) Log.d(TAG, "DHCP results found for " + mInterfaceName); + long leaseDuration = dhcpResults.leaseDuration; //int to long conversion + + //Sanity check for renewal + if (leaseDuration >= 0) { + //TODO: would be good to notify the user that his network configuration is + //bad and that the device cannot renew below MIN_RENEWAL_TIME_SECS + if (leaseDuration < MIN_RENEWAL_TIME_SECS) { + leaseDuration = MIN_RENEWAL_TIME_SECS; + } + //Do it a bit earlier than half the lease duration time + //to beat the native DHCP client and avoid extra packets + //48% for one hour lease time = 29 minutes + mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, + SystemClock.elapsedRealtime() + + leaseDuration * 480, //in milliseconds + mDhcpRenewalIntent); } else { - Log.e(TAG, "DHCP failed on " + mInterfaceName + ": " + + //infinite lease time, no renewal needed + } + + // Fill in any missing fields in dhcpResults from the previous results. + // If mDhcpResults is null (i.e. this is the first server response), + // this is a noop. + dhcpResults.updateFromDhcpRequest(mDhcpResults); + mDhcpResults = dhcpResults; + mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_SUCCESS, 0, dhcpResults) + .sendToTarget(); + return true; + } + + private boolean runDhcpStart() { + /* Stop any existing DHCP daemon before starting new */ + NetworkUtils.stopDhcp(mInterfaceName); + mDhcpResults = null; + + if (DBG) Log.d(TAG, "DHCP request on " + mInterfaceName); + if (!NetworkUtils.startDhcp(mInterfaceName) || !dhcpSucceeded()) { + Log.e(TAG, "DHCP request failed on " + mInterfaceName + ": " + + NetworkUtils.getDhcpError()); + mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0) + .sendToTarget(); + return false; + } + return true; + } + + private boolean runDhcpRenew() { + if (DBG) Log.d(TAG, "DHCP renewal on " + mInterfaceName); + if (!NetworkUtils.startDhcpRenew(mInterfaceName) || !dhcpSucceeded()) { + Log.e(TAG, "DHCP renew failed on " + mInterfaceName + ": " + NetworkUtils.getDhcpError()); - NetworkUtils.stopDhcp(mInterfaceName); mController.obtainMessage(CMD_POST_DHCP_ACTION, DHCP_FAILURE, 0) - .sendToTarget(); + .sendToTarget(); + return false; } - return success; + return true; } } diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index ab57c9b..65d325a1 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -48,7 +48,7 @@ import com.android.okhttp.internal.Internal; * {@link ConnectivityManager#registerNetworkCallback} calls. * 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 ConnectivityManager#setProcessDefaultNetwork}. + * {@link ConnectivityManager#bindProcessToNetwork}. */ public class Network implements Parcelable { @@ -242,7 +242,10 @@ public class Network implements Parcelable { * @see java.net.URL#openConnection() */ public URLConnection openConnection(URL url) throws IOException { - final ConnectivityManager cm = ConnectivityManager.getInstance(); + final ConnectivityManager cm = ConnectivityManager.getInstanceOrNull(); + if (cm == null) { + throw new IOException("No ConnectivityManager yet constructed, please construct one"); + } // TODO: Should this be optimized to avoid fetching the global proxy for every request? ProxyInfo proxyInfo = cm.getGlobalProxy(); if (proxyInfo == null) { @@ -269,7 +272,6 @@ public class Network implements Parcelable { * @throws IllegalArgumentException if the argument proxy is null. * @throws IOException if an error occurs while opening the connection. * @see java.net.URL#openConnection() - * @hide */ public URLConnection openConnection(URL url, java.net.Proxy proxy) throws IOException { if (proxy == null) throw new IllegalArgumentException("proxy is null"); @@ -299,7 +301,7 @@ public class Network implements Parcelable { /** * Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the * socket will be sent on this {@code Network}, irrespective of any process-wide network binding - * set by {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be + * set by {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be * connected. */ public void bindSocket(DatagramSocket socket) throws IOException { @@ -316,7 +318,7 @@ public class Network implements Parcelable { /** * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket * will be sent on this {@code Network}, irrespective of any process-wide network binding set by - * {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be connected. + * {@link ConnectivityManager#bindProcessToNetwork}. The socket must not be connected. */ public void bindSocket(Socket socket) throws IOException { // Apparently, the kernel doesn't update a connected TCP socket's routing upon mark changes. diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index 02fbe73..29dd8ad 100644 --- a/core/java/android/net/NetworkUtils.java +++ b/core/java/android/net/NetworkUtils.java @@ -159,7 +159,7 @@ public class NetworkUtils { * 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(); + public native static int getBoundNetworkForProcess(); /** * Binds host resolutions performed by this process to the network designated by {@code netId}. diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 17a84a7..7172c09 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -40,14 +40,9 @@ public final class Proxy { private static final ProxySelector sDefaultProxySelector; /** - * Used to notify an app that's caching the default connection proxy - * that either the default connection or its proxy has changed. - * The intent will have the following extra value:</p> - * <ul> - * <li><em>EXTRA_PROXY_INFO</em> - The ProxyProperties for the proxy. Non-null, - * though if the proxy is undefined the host string - * will be empty. - * </ul> + * Used to notify an app that's caching the proxy that either the default + * connection has changed or any connection's proxy has changed. The new + * proxy should be queried using {@link ConnectivityManager#getDefaultProxy()}. * * <p class="note">This is a protected intent that can only be sent by the system */ @@ -56,6 +51,11 @@ public final class Proxy { /** * Intent extra included with {@link #PROXY_CHANGE_ACTION} intents. * It describes the new proxy being used (as a {@link ProxyInfo} object). + * @deprecated Because {@code PROXY_CHANGE_ACTION} is sent whenever the proxy + * for any network on the system changes, applications should always use + * {@link ConnectivityManager#getDefaultProxy()} or + * {@link ConnectivityManager#getLinkProperties(Network)}.{@link LinkProperties#getHttpProxy()} + * to get the proxy for the Network(s) they are using. */ public static final String EXTRA_PROXY_INFO = "android.intent.extra.PROXY_INFO"; diff --git a/core/java/android/net/VpnService.java b/core/java/android/net/VpnService.java index c26af06..a0e65eb 100644 --- a/core/java/android/net/VpnService.java +++ b/core/java/android/net/VpnService.java @@ -679,7 +679,7 @@ public class VpnService extends Service { * * By default, all traffic from apps is forwarded through the VPN interface and it is not * possible for apps to side-step the VPN. If this method is called, apps may use methods - * such as {@link ConnectivityManager#setProcessDefaultNetwork} to instead send/receive + * such as {@link ConnectivityManager#bindProcessToNetwork} to instead send/receive * directly over the underlying network or any other network they have permissions for. * * @return this {@link Builder} object to facilitate chaining of method calls. diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp index 0174f82..60e8ed0 100644 --- a/core/jni/android_net_NetUtils.cpp +++ b/core/jni/android_net_NetUtils.cpp @@ -269,7 +269,7 @@ static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz return (jboolean) !setNetworkForProcess(netId); } -static jint android_net_utils_getNetworkBoundToProcess(JNIEnv *env, jobject thiz) +static jint android_net_utils_getBoundNetworkForProcess(JNIEnv *env, jobject thiz) { return getNetworkForProcess(); } @@ -307,7 +307,7 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease }, { "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError }, { "bindProcessToNetwork", "(I)Z", (void*) android_net_utils_bindProcessToNetwork }, - { "getNetworkBoundToProcess", "()I", (void*) android_net_utils_getNetworkBoundToProcess }, + { "getBoundNetworkForProcess", "()I", (void*) android_net_utils_getBoundNetworkForProcess }, { "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution }, { "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork }, { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn }, |