From b2d47200c776567e8f0067ee8673cb77e39b2e60 Mon Sep 17 00:00:00 2001 From: Remi NGUYEN VAN Date: Thu, 12 Aug 2021 10:11:06 +0900 Subject: [PATCH] Remove unused directories in Connectivity The directories were imported by mistake from old git log in the frameworks/base repository, and are unused. Bug: 192995539 Test: m Merged-In: I0d4bd06e79adedbf582d2fed551d9f1bde521fd1 Merged-In: Ie3a058b904cb2e3704c3a0725c8f720f81bb235e Change-Id: Ic3ed5d6d25fd87b136d9ae359e7444c4b1289744 --- .../java/android/net/ConnectivityManager.java | 2416 ------- core/java/android/net/DhcpInfo.java | 105 - .../android/net/IConnectivityManager.aidl | 175 - core/java/android/net/IpConfiguration.java | 151 - core/java/android/net/IpPrefix.java | 173 - core/java/android/net/LinkAddress.java | 332 - core/java/android/net/LinkProperties.java | 880 --- core/java/android/net/Network.java | 201 - core/java/android/net/NetworkAgent.java | 207 - .../java/android/net/NetworkCapabilities.java | 526 -- core/java/android/net/NetworkConfig.java | 80 - core/java/android/net/NetworkInfo.java | 506 -- core/java/android/net/NetworkRequest.java | 200 - core/java/android/net/NetworkState.java | 84 - core/java/android/net/NetworkUtils.java | 328 - core/java/android/net/ProxyInfo.java | 366 - core/java/android/net/RouteInfo.java | 453 -- core/jni/android_net_NetUtils.cpp | 337 - .../res/raw/xt_qtaguid_iface_fmt_typical | 4 - .../res/raw/xt_qtaguid_iface_typical | 6 - .../coretests/res/raw/xt_qtaguid_typical | 71 - .../src/android/net/LinkAddressTest.java | 331 - .../src/android/net/LinkPropertiesTest.java | 440 -- .../android/net/NetworkStatsHistoryTest.java | 521 -- .../src/android/net/NetworkStatsTest.java | 337 - .../src/android/net/RouteInfoTest.java | 214 - .../internal/net/NetworkStatsFactoryTest.java | 175 - .../android/server/ConnectivityService.java | 6047 ----------------- .../server/connectivity/Nat464Xlat.java | 219 - .../server/connectivity/NetworkAgentInfo.java | 83 - .../servicestests/res/raw/netstats_uid_v4 | Bin 156516 -> 0 bytes .../tests/servicestests/res/raw/netstats_v1 | Bin 18742 -> 0 bytes .../server/ConnectivityServiceTest.java | 231 - .../server/NetworkManagementServiceTest.java | 226 - .../server/NetworkStatsServiceTest.java | 1057 --- .../net/NetworkStatsCollectionTest.java | 193 - .../android/core/NsdServiceInfoTest.java | 163 - 37 files changed, 17838 deletions(-) delete mode 100644 core/java/android/net/ConnectivityManager.java delete mode 100644 core/java/android/net/DhcpInfo.java delete mode 100644 core/java/android/net/IConnectivityManager.aidl delete mode 100644 core/java/android/net/IpConfiguration.java delete mode 100644 core/java/android/net/IpPrefix.java delete mode 100644 core/java/android/net/LinkAddress.java delete mode 100644 core/java/android/net/LinkProperties.java delete mode 100644 core/java/android/net/Network.java delete mode 100644 core/java/android/net/NetworkAgent.java delete mode 100644 core/java/android/net/NetworkCapabilities.java delete mode 100644 core/java/android/net/NetworkConfig.java delete mode 100644 core/java/android/net/NetworkInfo.java delete mode 100644 core/java/android/net/NetworkRequest.java delete mode 100644 core/java/android/net/NetworkState.java delete mode 100644 core/java/android/net/NetworkUtils.java delete mode 100644 core/java/android/net/ProxyInfo.java delete mode 100644 core/java/android/net/RouteInfo.java delete mode 100644 core/jni/android_net_NetUtils.cpp delete mode 100644 core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical delete mode 100644 core/tests/coretests/res/raw/xt_qtaguid_iface_typical delete mode 100644 core/tests/coretests/res/raw/xt_qtaguid_typical delete mode 100644 core/tests/coretests/src/android/net/LinkAddressTest.java delete mode 100644 core/tests/coretests/src/android/net/LinkPropertiesTest.java delete mode 100644 core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java delete mode 100644 core/tests/coretests/src/android/net/NetworkStatsTest.java delete mode 100644 core/tests/coretests/src/android/net/RouteInfoTest.java delete mode 100644 core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java delete mode 100644 services/core/java/com/android/server/ConnectivityService.java delete mode 100644 services/core/java/com/android/server/connectivity/Nat464Xlat.java delete mode 100644 services/core/java/com/android/server/connectivity/NetworkAgentInfo.java delete mode 100644 services/tests/servicestests/res/raw/netstats_uid_v4 delete mode 100644 services/tests/servicestests/res/raw/netstats_v1 delete mode 100644 services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java delete mode 100644 services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java delete mode 100644 services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java delete mode 100644 services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java delete mode 100644 tests/CoreTests/android/core/NsdServiceInfoTest.java diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java deleted file mode 100644 index ff90e789a4..0000000000 --- a/core/java/android/net/ConnectivityManager.java +++ /dev/null @@ -1,2416 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package android.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.content.Intent; -import android.net.NetworkUtils; -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.telephony.TelephonyManager; -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; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.HashMap; - -/** - * Class that answers queries about the state of network connectivity. It also - * notifies applications when network connectivity changes. Get an instance - * of this class by calling - * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context.CONNECTIVITY_SERVICE)}. - *

- * The primary responsibilities of this class are to: - *

    - *
  1. Monitor network connections (Wi-Fi, GPRS, UMTS, etc.)
  2. - *
  3. Send broadcast intents when network connectivity changes
  4. - *
  5. Attempt to "fail over" to another network when connectivity to a network - * is lost
  6. - *
  7. Provide an API that allows applications to query the coarse-grained or fine-grained - * state of the available networks
  8. - *
  9. Provide an API that allows applications to request and select networks for their data - * traffic
  10. - *
- */ -public class ConnectivityManager { - private static final String TAG = "ConnectivityManager"; - - /** - * 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. - *

- * If this is a connection that was the result of failing over from a - * disconnected network, then the FAILOVER_CONNECTION boolean extra is - * set to true. - *

- * For a loss of connectivity, if the connectivity manager is attempting - * to connect (or has already connected) to another network, the - * 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 - * 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. - *

- * 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"; - - /** - * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any - * applicable {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}. - * - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String CONNECTIVITY_ACTION_IMMEDIATE = - "android.net.conn.CONNECTIVITY_CHANGE_IMMEDIATE"; - - /** - * The lookup key for a {@link NetworkInfo} object. Retrieve with - * {@link android.content.Intent#getParcelableExtra(String)}. - * - * @deprecated Since {@link NetworkInfo} can vary based on UID, applications - * should always obtain network information through - * {@link #getActiveNetworkInfo()} or - * {@link #getAllNetworkInfo()}. - * @see #EXTRA_NETWORK_TYPE - */ - @Deprecated - public static final String EXTRA_NETWORK_INFO = "networkInfo"; - - /** - * Network type which triggered a {@link #CONNECTIVITY_ACTION} broadcast. - * Can be used with {@link #getNetworkInfo(int)} to get {@link NetworkInfo} - * state based on the calling application. - * - * @see android.content.Intent#getIntExtra(String, int) - */ - public static final String EXTRA_NETWORK_TYPE = "networkType"; - - /** - * The lookup key for a boolean that indicates whether a connect event - * is for a network to which the connectivity manager was failing over - * following a disconnect on another network. - * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. - */ - public static final String EXTRA_IS_FAILOVER = "isFailover"; - /** - * The lookup key for a {@link NetworkInfo} object. This is supplied when - * there is another network that it may be possible to connect to. Retrieve with - * {@link android.content.Intent#getParcelableExtra(String)}. - */ - public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork"; - /** - * The lookup key for a boolean that indicates whether there is a - * complete lack of connectivity, i.e., no network is available. - * Retrieve it with {@link android.content.Intent#getBooleanExtra(String,boolean)}. - */ - public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity"; - /** - * The lookup key for a string that indicates why an attempt to connect - * to a network failed. The string has no particular structure. It is - * intended to be used in notifications presented to users. Retrieve - * it with {@link android.content.Intent#getStringExtra(String)}. - */ - public static final String EXTRA_REASON = "reason"; - /** - * The lookup key for a string that provides optionally supplied - * extra information about the network state. The information - * may be passed up from the lower networking layers, and its - * meaning may be specific to a particular network type. Retrieve - * it with {@link android.content.Intent#getStringExtra(String)}. - */ - public static final String EXTRA_EXTRA_INFO = "extraInfo"; - /** - * The lookup key for an int that provides information about - * our connection to the internet at large. 0 indicates no connection, - * 100 indicates a great connection. Retrieve it with - * {@link android.content.Intent#getIntExtra(String, int)}. - * {@hide} - */ - public static final String EXTRA_INET_CONDITION = "inetCondition"; - - /** - * 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 transmission is started, or - * idle if there is no data transmission for a period of time. - * {@hide} - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_DATA_ACTIVITY_CHANGE = "android.net.conn.DATA_ACTIVITY_CHANGE"; - /** - * The lookup key for an enum that indicates the network device type on which this data activity - * change happens. - * {@hide} - */ - public static final String EXTRA_DEVICE_TYPE = "deviceType"; - /** - * The lookup key for a boolean that indicates the device is active or not. {@code true} means - * it is actively sending or receiving data and {@code false} means it is idle. - * {@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 - * values. Use {@link #getBackgroundDataSetting()} to get the current value. - *

- * If an application uses the network in the background, it should listen - * for this broadcast and stop using the background data if the value is - * {@code false}. - *

- * - * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability - * of background data depends on several combined factors, and - * this broadcast is no longer sent. Instead, when background - * data is unavailable, {@link #getActiveNetworkInfo()} will now - * appear disconnected. During first boot after a platform - * upgrade, this broadcast will be sent once if - * {@link #getBackgroundDataSetting()} was {@code false} before - * the upgrade. - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - @Deprecated - public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = - "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; - - /** - * Broadcast Action: The network connection may not be good - * uses {@code ConnectivityManager.EXTRA_INET_CONDITION} and - * {@code ConnectivityManager.EXTRA_NETWORK_INFO} to specify - * 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"; - - /** - * 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) - public static final String ACTION_TETHER_STATE_CHANGED = - "android.net.conn.TETHER_STATE_CHANGED"; - - /** - * @hide - * 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[] 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[] 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"; - - /** - * Broadcast Action: The captive portal tracker has finished its test. - * Sent only while running Setup Wizard, in lieu of showing a user - * notification. - * @hide - */ - @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - 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 a connection type. - * @hide - */ - public static final int TYPE_NONE = -1; - - /** - * 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 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 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 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 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 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 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 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; - - /** - * Dummy data connection. This should not be used on shipping devices. - */ - public static final int TYPE_DUMMY = 8; - - /** - * 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 Administration. - * {@hide} - */ - public static final int TYPE_MOBILE_FOTA = 10; - - /** - * IP Multimedia Subsystem. - * {@hide} - */ - public static final int TYPE_MOBILE_IMS = 11; - - /** - * Carrier Branded Services. - * {@hide} - */ - public static final int TYPE_MOBILE_CBS = 12; - - /** - * A Wi-Fi p2p connection. Only requesting processes will have access to - * the peers connected. - * {@hide} - */ - public static final int TYPE_WIFI_P2P = 13; - - /** - * The network to use for initially attaching to the network - * {@hide} - */ - public static final int TYPE_MOBILE_IA = 14; - - /** - * The network that uses proxy to achieve connectivity. - * {@hide} - */ - public static final int TYPE_PROXY = 16; - - /** {@hide} */ - 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 - * 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 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. - */ - @Deprecated - public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; - - /** - * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in - * 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 - */ - public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000; - - /** - * @hide - */ - 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; - - private INetworkManagementService mNMService; - - /** - * 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; - } - - /** - * 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: - return "MOBILE"; - case TYPE_WIFI: - return "WIFI"; - case TYPE_MOBILE_MMS: - return "MOBILE_MMS"; - case TYPE_MOBILE_SUPL: - return "MOBILE_SUPL"; - case TYPE_MOBILE_DUN: - return "MOBILE_DUN"; - case TYPE_MOBILE_HIPRI: - return "MOBILE_HIPRI"; - case TYPE_WIMAX: - return "WIMAX"; - case TYPE_BLUETOOTH: - return "BLUETOOTH"; - case TYPE_DUMMY: - return "DUMMY"; - case TYPE_ETHERNET: - return "ETHERNET"; - case TYPE_MOBILE_FOTA: - return "MOBILE_FOTA"; - case TYPE_MOBILE_IMS: - return "MOBILE_IMS"; - case TYPE_MOBILE_CBS: - return "MOBILE_CBS"; - case TYPE_WIFI_P2P: - return "WIFI_P2P"; - case TYPE_MOBILE_IA: - return "MOBILE_IA"; - case TYPE_PROXY: - return "PROXY"; - default: - return Integer.toString(type); - } - } - - /** - * 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: - case TYPE_MOBILE_MMS: - case TYPE_MOBILE_SUPL: - case TYPE_MOBILE_DUN: - case TYPE_MOBILE_HIPRI: - case TYPE_MOBILE_FOTA: - case TYPE_MOBILE_IMS: - case TYPE_MOBILE_CBS: - case TYPE_MOBILE_IA: - return true; - default: - return false; - } - } - - /** - * 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; - } - } - - /** - * 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: - case TYPE_MOBILE_IA: - 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. - * - * @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) { - } - - /** - * Retrieves the current preferred network type. - * - * @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() { - return TYPE_NONE; - } - - /** - * 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() { - try { - return mService.getActiveNetworkInfo(); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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(); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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. - * - * @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(); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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.getLinkPropertiesForType(networkType); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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} - */ -// 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. - * - * @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} - */ -// 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 - * begin using the named feature. The interpretation of {@code feature} - * is completely up to each networking implementation. - *

This method requires the caller to hold the permission - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. - * @param networkType specifies which network the request pertains to - * @param feature the name of the feature to be used - * @return an integer value representing the outcome of the request. - * 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) { - 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; - } - } - - /** - * Tells the underlying networking system that the caller is finished - * using the named feature. The interpretation of {@code feature} - * is completely up to each networking implementation. - *

This method requires the caller to hold the permission - * {@link android.Manifest.permission#CHANGE_NETWORK_STATE}. - * @param networkType specifies which network the request pertains to - * @param feature the name of the feature that is no longer needed - * @return an integer value representing the outcome of the request. - * 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) { - 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; - } - - /** - * Removes the NET_CAPABILITY_NOT_RESTRICTED capability from the given - * 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 (int capability : nc.getCapabilities()) { - switch (capability) { - 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: - 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 - // networks. Conclude that this network is unrestricted. - return; - } - } - // All the capabilities are typically provided by restricted networks. - // Conclude that this network is restricted. - nc.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); - } - - 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).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.addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P); - maybeMarkCapabilitiesRestricted(netCap); - return netCap; - } - } - return null; - } - - private int legacyTypeForNetworkCapabilities(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; - } - if (netCap.hasCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)) { - return TYPE_WIFI_P2P; - } - 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); - setProcessDefaultNetworkForHostResolution(network); - } - @Override - public void onLost(NetworkRequest request, Network network) { - if (network.equals(currentNetwork)) { - currentNetwork = null; - setProcessDefaultNetworkForHostResolution(null); - } - 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 = legacyTypeForNetworkCapabilities(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, type); - 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; - } - } - - /** - * 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 - * @return {@code true} on success, {@code false} on failure - * - * @deprecated Deprecated in favor of the {@link #requestNetwork}, - * {@link #setProcessDefaultNetwork} and {@link Network#getSocketFactory} api. - */ - public boolean requestRouteToHost(int networkType, int hostAddress) { - InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); - - if (inetAddress == null) { - return false; - } - - return requestRouteToHostAddress(networkType, inetAddress); - } - - /** - * 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 - * @return {@code true} on success, {@code false} on failure - * @hide - * @deprecated Deprecated in favor of the {@link #requestNetwork} and - * {@link #setProcessDefaultNetwork} api. - */ - public boolean requestRouteToHostAddress(int networkType, InetAddress hostAddress) { - byte[] address = hostAddress.getAddress(); - try { - return mService.requestRouteToHostAddress(networkType, address, mPackageName); - } catch (RemoteException e) { - return false; - } - } - - /** - * Returns the value of the setting for background data usage. If false, - * applications should not use the network if the application is not in the - * foreground. Developers should respect this setting, and check the value - * of this before performing any background data operations. - *

- * All applications that have background services that use the network - * should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}. - *

- * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, availability of - * background data depends on several combined factors, and this method will - * always return {@code true}. Instead, when background data is unavailable, - * {@link #getActiveNetworkInfo()} will now appear disconnected. - * - * @return Whether background data usage is allowed. - */ - @Deprecated - public boolean getBackgroundDataSetting() { - // assume that background data is allowed; final authority is - // NetworkInfo which may be blocked. - return true; - } - - /** - * Sets the value of the setting for background data usage. - * - * @param allowBackgroundData Whether an application should use data while - * it is in the background. - * - * @attr ref android.Manifest.permission#CHANGE_BACKGROUND_DATA_SETTING - * @see #getBackgroundDataSetting() - * @hide - */ - @Deprecated - public void setBackgroundDataSetting(boolean allowBackgroundData) { - // ignored - } - - /** - * Return quota status for the current active network, or {@code null} if no - * 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() { - try { - return mService.getActiveNetworkQuotaInfo(); - } catch (RemoteException e) { - return null; - } - } - - /** - * @hide - * @deprecated Talk to TelephonyManager directly - */ - public boolean getMobileDataEnabled() { - 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; - } - - /** - * 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} - */ - public ConnectivityManager(IConnectivityManager service, String packageName) { - mService = checkNotNull(service, "missing IConnectivityManager"); - mPackageName = checkNotNull(packageName, "missing package name"); - } - - /** {@hide} */ - public static ConnectivityManager from(Context context) { - return (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - } - - /** - * 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() { - try { - return mService.getTetherableIfaces(); - } catch (RemoteException e) { - return new String[0]; - } - } - - /** - * 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() { - try { - return mService.getTetheredIfaces(); - } catch (RemoteException e) { - return new String[0]; - } - } - - /** - * 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() { - try { - return mService.getTetheringErroredIfaces(); - } catch (RemoteException e) { - return new String[0]; - } - } - - /** - * 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) { - try { - return mService.tether(iface); - } catch (RemoteException e) { - return TETHER_ERROR_SERVICE_UNAVAIL; - } - } - - /** - * 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) { - try { - return mService.untether(iface); - } catch (RemoteException e) { - return TETHER_ERROR_SERVICE_UNAVAIL; - } - } - - /** - * Check if the device allows for tethering. It may be disabled via - * {@code ro.tether.denied} system property, 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() { - try { - return mService.isTetheringSupported(); - } catch (RemoteException e) { - return false; - } - } - - /** - * 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() { - try { - return mService.getTetherableUsbRegexs(); - } catch (RemoteException e) { - return new String[0]; - } - } - - /** - * 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() { - try { - return mService.getTetherableWifiRegexs(); - } catch (RemoteException e) { - return new String[0]; - } - } - - /** - * 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() { - try { - return mService.getTetherableBluetoothRegexs(); - } catch (RemoteException e) { - return new String[0]; - } - } - - /** - * 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) { - try { - return mService.setUsbTethering(enable); - } catch (RemoteException e) { - return TETHER_ERROR_SERVICE_UNAVAIL; - } - } - - /** {@hide} */ - public static final int TETHER_ERROR_NO_ERROR = 0; - /** {@hide} */ - public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; - /** {@hide} */ - public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; - /** {@hide} */ - public static final int TETHER_ERROR_UNSUPPORTED = 3; - /** {@hide} */ - public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; - /** {@hide} */ - public static final int TETHER_ERROR_MASTER_ERROR = 5; - /** {@hide} */ - public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; - /** {@hide} */ - public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; - /** {@hide} */ - public static final int TETHER_ERROR_ENABLE_NAT_ERROR = 8; - /** {@hide} */ - public static final int TETHER_ERROR_DISABLE_NAT_ERROR = 9; - /** {@hide} */ - public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; - - /** - * 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) { - try { - return mService.getLastTetherError(iface); - } catch (RemoteException e) { - return TETHER_ERROR_SERVICE_UNAVAIL; - } - } - - /** - * 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) { - try { - mService.requestNetworkTransitionWakelock(forWhom); - return true; - } catch (RemoteException e) { - return false; - } - } - - /** - * 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) { - try { - mService.reportInetCondition(networkType, percentage); - } catch (RemoteException e) { - } - } - - /** - * 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 {@link Network} the application was attempting to use - * or {@code null} to indicate the current default network. - */ - 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 - * 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 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 - * android.Manifest.permission#CONNECTIVITY_INTERNAL. - * @hide - */ - public void setGlobalProxy(ProxyInfo p) { - try { - mService.setGlobalProxy(p); - } catch (RemoteException e) { - } - } - - /** - * Retrieve any network-independent global HTTP proxy. - * - * @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 ProxyInfo getGlobalProxy() { - try { - return mService.getGlobalProxy(); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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 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} - * @deprecated Deprecated in favor of {@link #getLinkProperties} - */ - public ProxyInfo getProxy() { - try { - return mService.getProxy(); - } catch (RemoteException e) { - return null; - } - } - - /** - * 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 - * - *

This method requires the call to hold the permission - * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. - * {@hide} - */ - public void setDataDependency(int networkType, boolean met) { - try { - mService.setDataDependency(networkType, met); - } catch (RemoteException e) { - } - } - - /** - * 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 {@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) { - try { - return mService.isNetworkSupported(networkType); - } catch (RemoteException e) {} - return false; - } - - /** - * 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 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 { - return mService.isActiveNetworkMetered(); - } catch (RemoteException e) { - return false; - } - } - - /** - * 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(); - } catch (RemoteException e) { - return false; - } - } - - /** - * 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 - * - * @param networkType NetworkType to set - * @param messenger {@link Messenger} - * {@hide} - */ - public void supplyMessenger(int networkType, Messenger messenger) { - try { - mService.supplyMessenger(networkType, messenger); - } catch (RemoteException e) { - } - } - - /** - * Check mobile provisioning. - * - * @param suggestedTimeOutMs, timeout in milliseconds - * - * @return time out that will be used, maybe less that suggestedTimeOutMs - * -1 if an error. - * - * {@hide} - */ - public int checkMobileProvisioning(int suggestedTimeOutMs) { - int timeOutMs = -1; - try { - timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs); - } catch (RemoteException e) { - } - return timeOutMs; - } - - /** - * Get the mobile provisioning url. - * {@hide} - */ - public String getMobileProvisioningUrl() { - try { - return mService.getMobileProvisioningUrl(); - } catch (RemoteException e) { - } - return null; - } - - /** - * Get the mobile redirected provisioning url. - * {@hide} - */ - public String getMobileRedirectedProvisioningUrl() { - try { - return mService.getMobileRedirectedProvisioningUrl(); - } catch (RemoteException e) { - } - return null; - } - - /** - * get the information about a specific network link - * @hide - */ - public LinkQualityInfo getLinkQualityInfo(int networkType) { - try { - LinkQualityInfo li = mService.getLinkQualityInfo(networkType); - return li; - } catch (RemoteException e) { - return null; - } - } - - /** - * get the information of currently active network link - * @hide - */ - public LinkQualityInfo getActiveLinkQualityInfo() { - try { - LinkQualityInfo li = mService.getActiveLinkQualityInfo(); - return li; - } catch (RemoteException e) { - return null; - } - } - - /** - * get the information of all network links - * @hide - */ - public LinkQualityInfo[] getAllLinkQualityInfo() { - try { - LinkQualityInfo[] li = mService.getAllLinkQualityInfo(); - return li; - } catch (RemoteException e) { - 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) { - } - } - - /** - * 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) { - } - } - - /** {@hide} */ - public void registerNetworkFactory(Messenger messenger, String name) { - try { - mService.registerNetworkFactory(messenger, name); - } catch (RemoteException e) { } - } - - /** {@hide} */ - public void unregisterNetworkFactory(Messenger messenger) { - try { - mService.unregisterNetworkFactory(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) { } - } - - /** - * Base class for NetworkRequest callbacks. Used for notifications about network - * changes. Should be extended by applications wanting notifications. - */ - public static class NetworkCallbackListener { - /** @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; - - /** - * @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 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 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. - * - * @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 {@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 {@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) {} - } - - 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; - /** @hide obj = NetworkCapabilities, arg1 = seq number */ - private static final int EXPIRE_LEGACY_REQUEST = BASE + 10; - - private 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); - NetworkCallbackListener 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); - NetworkCallbackListener 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); - NetworkCallbackListener 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); - NetworkCallbackListener 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; - NetworkCallbackListener 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); - NetworkCallbackListener 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); - NetworkCallbackListener 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; - NetworkCallbackListener 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; - } - case EXPIRE_LEGACY_REQUEST: { - expireRequest((NetworkCapabilities)message.obj, message.arg1); - break; - } - } - } - - private NetworkRequest getNetworkRequest(Message msg) { - return (NetworkRequest)(msg.obj); - } - private NetworkCallbackListener getCallbacks(NetworkRequest req) { - synchronized(mCallbackMap) { - return mCallbackMap.get(req); - } - } - private Network getNetwork(Message msg) { - return new Network(msg.arg2); - } - private NetworkCallbackListener 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(), - sNetworkCallbackListener, sCallbackRefCount, this); - } - } - } - - private void removeCallbackListener() { - synchronized(sCallbackRefCount) { - if (sCallbackRefCount.decrementAndGet() == 0) { - sCallbackHandler.obtainMessage(CALLBACK_EXIT).sendToTarget(); - sCallbackHandler = null; - } - } - } - - static final HashMap sNetworkCallbackListener = - 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 sendRequestForNetwork(NetworkCapabilities need, - NetworkCallbackListener networkCallbackListener, int timeoutSec, int action, - int legacyType) { - NetworkRequest networkRequest = null; - if (networkCallbackListener == null) { - throw new IllegalArgumentException("null NetworkCallbackListener"); - } - 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(), legacyType); - } - if (networkRequest != null) { - synchronized(sNetworkCallbackListener) { - sNetworkCallbackListener.put(networkRequest, networkCallbackListener); - } - } - } 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 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 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. - */ - public NetworkRequest requestNetwork(NetworkCapabilities need, - NetworkCallbackListener networkCallbackListener) { - return sendRequestForNetwork(need, networkCallbackListener, 0, REQUEST, TYPE_NONE); - } - - /** - * Request a network to satisfy a set of {@link NetworkCapabilities}, limited - * by a timeout. - * - * 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 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 NetworkCallbackListener#unavailable} is called. - * @return A {@link NetworkRequest} object identifying the request. - * @hide - */ - public NetworkRequest requestNetwork(NetworkCapabilities need, - NetworkCallbackListener networkCallbackListener, int timeoutSec) { - return sendRequestForNetwork(need, networkCallbackListener, timeoutSec, REQUEST, - TYPE_NONE); - } - - /** - * 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; - - /** - * 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 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_CAPABILITIES} containing - * the original requests parameters. It is important to create a new, - * {@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 - * replaced by this one, effectively releasing the previous {@link NetworkRequest}. - *

- * The request may be released normally by calling {@link #releaseNetworkRequest}. - * - * @param need {@link NetworkCapabilities} required by this request. - * @param operation Action to perform when the network is available (corresponds - * to the {@link NetworkCallbackListener#onAvailable} call. Typically - * comes from {@link PendingIntent#getBroadcast}. - * @return A {@link NetworkRequest} object identifying the request. - */ - 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 networkCallbackListener The {@link NetworkCallbackListener} to be called as suitable - * networks change state. - * @return A {@link NetworkRequest} object identifying the request. - */ - public NetworkRequest listenForNetwork(NetworkCapabilities need, - NetworkCallbackListener networkCallbackListener) { - return sendRequestForNetwork(need, networkCallbackListener, 0, LISTEN, TYPE_NONE); - } - - /** - * 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}. - */ - public void releaseNetworkRequest(NetworkRequest networkRequest) { - if (networkRequest == null) throw new IllegalArgumentException("null NetworkRequest"); - try { - 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/DhcpInfo.java b/core/java/android/net/DhcpInfo.java deleted file mode 100644 index 788d7d94f6..0000000000 --- a/core/java/android/net/DhcpInfo.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcelable; -import android.os.Parcel; - -/** - * A simple object for retrieving the results of a DHCP request. - */ -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() { - super(); - } - - /** copy constructor {@hide} */ - public DhcpInfo(DhcpInfo source) { - if (source != null) { - ipAddress = source.ipAddress; - gateway = source.gateway; - netmask = source.netmask; - dns1 = source.dns1; - dns2 = source.dns2; - serverAddress = source.serverAddress; - leaseDuration = source.leaseDuration; - } - } - - public String toString() { - StringBuffer str = new StringBuffer(); - - str.append("ipaddr "); putAddress(str, ipAddress); - str.append(" gateway "); putAddress(str, gateway); - str.append(" netmask "); putAddress(str, netmask); - str.append(" dns1 "); putAddress(str, dns1); - str.append(" dns2 "); putAddress(str, dns2); - str.append(" DHCP server "); putAddress(str, serverAddress); - str.append(" lease ").append(leaseDuration).append(" seconds"); - - return str.toString(); - } - - private static void putAddress(StringBuffer buf, int addr) { - buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress()); - } - - /** Implement the Parcelable interface {@hide} */ - public int describeContents() { - return 0; - } - - /** Implement the Parcelable interface {@hide} */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeInt(ipAddress); - dest.writeInt(gateway); - dest.writeInt(netmask); - dest.writeInt(dns1); - dest.writeInt(dns2); - dest.writeInt(serverAddress); - dest.writeInt(leaseDuration); - } - - /** Implement the Parcelable interface {@hide} */ - public static final Creator CREATOR = - new Creator() { - public DhcpInfo createFromParcel(Parcel in) { - DhcpInfo info = new DhcpInfo(); - info.ipAddress = in.readInt(); - info.gateway = in.readInt(); - info.netmask = in.readInt(); - info.dns1 = in.readInt(); - info.dns2 = in.readInt(); - info.serverAddress = in.readInt(); - info.leaseDuration = in.readInt(); - return info; - } - - public DhcpInfo[] newArray(int size) { - return new DhcpInfo[size]; - } - }; -} diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl deleted file mode 100644 index 5f1ff3e1d9..0000000000 --- a/core/java/android/net/IConnectivityManager.aidl +++ /dev/null @@ -1,175 +0,0 @@ -/** - * Copyright (c) 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.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; -import android.os.Messenger; -import android.os.ParcelFileDescriptor; -import android.os.ResultReceiver; - -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 - * state of network connectivity. - */ -/** {@hide} */ -interface IConnectivityManager -{ - // Keep this in sync with framework/native/services/connectivitymanager/ConnectivityManager.h - void markSocketAsUser(in ParcelFileDescriptor socket, int uid); - - NetworkInfo getActiveNetworkInfo(); - NetworkInfo getActiveNetworkInfoForUid(int uid); - NetworkInfo getNetworkInfo(int networkType); - NetworkInfo[] getAllNetworkInfo(); - - NetworkInfo getProvisioningOrActiveNetworkInfo(); - - boolean isNetworkSupported(int networkType); - - LinkProperties getActiveLinkProperties(); - LinkProperties getLinkPropertiesForType(int networkType); - LinkProperties getLinkProperties(in Network network); - - NetworkCapabilities getNetworkCapabilities(in Network network); - - NetworkState[] getAllNetworkState(); - - NetworkQuotaInfo getActiveNetworkQuotaInfo(); - boolean isActiveNetworkMetered(); - - int startUsingNetworkFeature(int networkType, in String feature, - in IBinder binder); - - int stopUsingNetworkFeature(int networkType, in String feature); - - boolean requestRouteToHost(int networkType, int hostAddress, String packageName); - - boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress, String packageName); - - /** Policy control over specific {@link NetworkStateTracker}. */ - void setPolicyDataEnable(int networkType, boolean enabled); - - int tether(String iface); - - int untether(String iface); - - int getLastTetherError(String iface); - - boolean isTetheringSupported(); - - String[] getTetherableIfaces(); - - String[] getTetheredIfaces(); - - String[] getTetheringErroredIfaces(); - - String[] getTetherableUsbRegexs(); - - String[] getTetherableWifiRegexs(); - - String[] getTetherableBluetoothRegexs(); - - int setUsbTethering(boolean enable); - - void requestNetworkTransitionWakelock(in String forWhom); - - void reportInetCondition(int networkType, int percentage); - - void reportBadNetwork(in Network network); - - ProxyInfo getGlobalProxy(); - - void setGlobalProxy(in ProxyInfo p); - - ProxyInfo getProxy(); - - void setDataDependency(int networkType, boolean met); - - boolean protectVpn(in ParcelFileDescriptor socket); - - boolean prepareVpn(String oldPackage, String newPackage); - - ParcelFileDescriptor establishVpn(in VpnConfig config); - - VpnConfig getVpnConfig(); - - void startLegacyVpn(in VpnProfile profile); - - LegacyVpnInfo getLegacyVpnInfo(); - - boolean updateLockdownVpn(); - - void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); - - void supplyMessenger(int networkType, in Messenger messenger); - - int findConnectionTypeForIface(in String iface); - - int checkMobileProvisioning(int suggestedTimeOutMs); - - String getMobileProvisioningUrl(); - - String getMobileRedirectedProvisioningUrl(); - - LinkQualityInfo getLinkQualityInfo(int networkType); - - LinkQualityInfo getActiveLinkQualityInfo(); - - LinkQualityInfo[] getAllLinkQualityInfo(); - - void setProvisioningNotificationVisible(boolean visible, int networkType, in String extraInfo, - in String url); - - void setAirplaneMode(boolean enable); - - 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); - - NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities, - in Messenger messenger, int timeoutSec, in IBinder binder, int legacy); - - 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); - - int getRestoreDefaultNetworkDelay(int networkType); -} diff --git a/core/java/android/net/IpConfiguration.java b/core/java/android/net/IpConfiguration.java deleted file mode 100644 index 4730bab38c..0000000000 --- a/core/java/android/net/IpConfiguration.java +++ /dev/null @@ -1,151 +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 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]; - } - }; -} diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java deleted file mode 100644 index dfe03849ae..0000000000 --- a/core/java/android/net/IpPrefix.java +++ /dev/null @@ -1,173 +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.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: - * - *

- * - * 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/LinkAddress.java b/core/java/android/net/LinkAddress.java deleted file mode 100644 index 524607822d..0000000000 --- a/core/java/android/net/LinkAddress.java +++ /dev/null @@ -1,332 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.net.Inet4Address; -import java.net.InetAddress; -import java.net.InterfaceAddress; -import java.net.UnknownHostException; - -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. - * - * 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 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 { - /** - * IPv4 or IPv6 address. - */ - private InetAddress address; - - /** - * Prefix length. - */ - private int prefixLength; - - /** - * 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 + - "/" + prefixLength); - } - 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. - * @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); - } - - /** - * 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. - * @hide - */ - public LinkAddress(InetAddress address, int 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. - * @hide - */ - public LinkAddress(InterfaceAddress interfaceAddress) { - 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". 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); - 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. - * @hide - */ - public LinkAddress(String address, int flags, int scope) { - 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, 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 {@code obj}. Two addresses are equal if - * 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. - */ - @Override - public boolean equals(Object obj) { - if (!(obj instanceof LinkAddress)) { - return false; - } - LinkAddress linkAddress = (LinkAddress) obj; - return this.address.equals(linkAddress.address) && - this.prefixLength == linkAddress.prefixLength && - this.flags == linkAddress.flags && - this.scope == linkAddress.scope; - } - - /** - * Returns a hashcode for this address. - */ - @Override - public int hashCode() { - return address.hashCode() + 11 * prefixLength + 19 * flags + 43 * scope; - } - - /** - * 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} - * otherwise. - * @hide - */ - public boolean isSameAddressAs(LinkAddress other) { - return address.equals(other.address) && prefixLength == other.prefixLength; - } - - /** - * Returns the {@link InetAddress} of this {@code LinkAddress}. - */ - public InetAddress getAddress() { - return address; - } - - /** - * Returns the prefix length of this {@code LinkAddress}. - */ - 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}. - */ - public int getFlags() { - return flags; - } - - /** - * Returns the scope of this {@code LinkAddress}. - */ - public int getScope() { - return scope; - } - - /** - * Returns true if this {@code LinkAddress} is global scope and preferred. - * @hide - */ - public boolean isGlobalPreferred() { - return (scope == RT_SCOPE_UNIVERSE && - (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED | IFA_F_TENTATIVE)) == 0L); - } - - /** - * 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.getAddress()); - dest.writeInt(prefixLength); - dest.writeInt(this.flags); - dest.writeInt(scope); - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public static final Creator CREATOR = - new Creator() { - public LinkAddress createFromParcel(Parcel in) { - InetAddress address = null; - 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(); - int flags = in.readInt(); - int scope = in.readInt(); - return new LinkAddress(address, prefixLength, flags, scope); - } - - public LinkAddress[] newArray(int size) { - return new LinkAddress[size]; - } - }; -} diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java deleted file mode 100644 index bb05936a16..0000000000 --- a/core/java/android/net/LinkProperties.java +++ /dev/null @@ -1,880 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.net.ProxyInfo; -import android.os.Parcelable; -import android.os.Parcel; -import android.text.TextUtils; - -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.Inet6Address; - -import java.net.UnknownHostException; -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. - * - * A link represents a connection to a network. - * It may have multiple addresses and multiple gateways, - * multiple dns servers but only one http proxy and one - * network interface. - * - * Note that this is just a holder of data. Modifying it - * does not affect live networks. - * - */ -public class LinkProperties implements Parcelable { - // The interface described by the network link. - private String mIfaceName; - private ArrayList mLinkAddresses = new ArrayList(); - private ArrayList mDnses = new ArrayList(); - private String mDomains; - private ArrayList mRoutes = new ArrayList(); - private ProxyInfo 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. - private Hashtable mStackedLinks = - new Hashtable(); - - /** - * @hide - */ - public static class CompareResult { - public List removed = new ArrayList(); - public List added = new ArrayList(); - - @Override - public String toString() { - String retVal = "removed=["; - for (T addr : removed) retVal += addr.toString() + ","; - retVal += "] added=["; - for (T addr : added) retVal += addr.toString() + ","; - retVal += "]"; - return retVal; - } - } - - /** - * @hide - */ - public LinkProperties() { - } - - /** - * @hide - */ - public LinkProperties(LinkProperties source) { - if (source != null) { - mIfaceName = source.getInterfaceName(); - for (LinkAddress l : source.getLinkAddresses()) mLinkAddresses.add(l); - for (InetAddress i : source.getDnsServers()) mDnses.add(i); - mDomains = source.getDomains(); - for (RouteInfo r : source.getRoutes()) mRoutes.add(r); - mHttpProxy = (source.getHttpProxy() == null) ? - null : new ProxyInfo(source.getHttpProxy()); - for (LinkProperties l: source.mStackedLinks.values()) { - addStackedLink(l); - } - setMtu(source.getMtu()); - } - } - - /** - * 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. - * @hide - */ - public void setInterfaceName(String iface) { - mIfaceName = iface; - ArrayList newRoutes = new ArrayList(mRoutes.size()); - for (RouteInfo route : mRoutes) { - newRoutes.add(routeWithInterface(route)); - } - 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 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()); - } - return interfaceNames; - } - - /** - * 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 List} of {@link InetAddress} for this link. - * @hide - */ - public List getAddresses() { - List addresses = new ArrayList(); - for (LinkAddress linkAddress : mLinkAddresses) { - addresses.add(linkAddress.getAddress()); - } - return Collections.unmodifiableList(addresses); - } - - /** - * Returns all the addresses on this link and all the links stacked above it. - * @hide - */ - public List getAllAddresses() { - List addresses = new ArrayList(); - for (LinkAddress linkAddress : mLinkAddresses) { - addresses.add(linkAddress.getAddress()); - } - for (LinkProperties stacked: mStackedLinks.values()) { - addresses.addAll(stacked.getAllAddresses()); - } - return addresses; - } - - private int findLinkAddressIndex(LinkAddress address) { - for (int i = 0; i < mLinkAddresses.size(); i++) { - if (mLinkAddresses.get(i).isSameAddressAs(address)) { - return i; - } - } - return -1; - } - - /** - * 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. - * @hide - */ - 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 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. - * @hide - */ - public boolean removeLinkAddress(LinkAddress toRemove) { - int i = findLinkAddressIndex(toRemove); - if (i >= 0) { - mLinkAddresses.remove(i); - return true; - } - return false; - } - - /** - * 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 List} of {@link LinkAddress} for this link. - */ - public List getLinkAddresses() { - return Collections.unmodifiableList(mLinkAddresses); - } - - /** - * Returns all the addresses on this link and all the links stacked above it. - * @hide - */ - public List getAllLinkAddresses() { - List addresses = new ArrayList(); - addresses.addAll(mLinkAddresses); - for (LinkProperties stacked: mStackedLinks.values()) { - addresses.addAll(stacked.getAllLinkAddresses()); - } - return 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. - * @hide - */ - public void setLinkAddresses(Collection addresses) { - mLinkAddresses.clear(); - for (LinkAddress address: addresses) { - addLinkAddress(address); - } - } - - /** - * Adds the given {@link InetAddress} to the list of DNS servers. - * - * @param dnsServer The {@link InetAddress} to add to the list of DNS servers. - * @hide - */ - public void addDnsServer(InetAddress dnsServer) { - if (dnsServer != null) mDnses.add(dnsServer); - } - - /** - * 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. - */ - public List getDnsServers() { - return Collections.unmodifiableList(mDnses); - } - - /** - * 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. - * @hide - */ - 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; - } - - private RouteInfo routeWithInterface(RouteInfo route) { - return new RouteInfo( - route.getDestination(), - route.getGateway(), - 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. - * @hide - */ - public void addRoute(RouteInfo route) { - if (route != null) { - String routeIface = route.getInterface(); - if (routeIface != null && !routeIface.equals(mIfaceName)) { - throw new IllegalArgumentException( - "Route added with non-matching interface: " + routeIface + - " vs. " + mIfaceName); - } - mRoutes.add(routeWithInterface(route)); - } - } - - /** - * Returns all the {@link RouteInfo} set on this link. - * - * @return An unmodifiable {@link List} of {@link RouteInfo} for this link. - */ - public List getRoutes() { - return Collections.unmodifiableList(mRoutes); - } - - /** - * Returns all the routes on this link and all the links stacked above it. - * @hide - */ - public List getAllRoutes() { - List routes = new ArrayList(); - routes.addAll(mRoutes); - for (LinkProperties stacked: mStackedLinks.values()) { - routes.addAll(stacked.getAllRoutes()); - } - 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. - * @hide - */ - 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; - } - - /** - * 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. - * @return true if the link was stacked, false otherwise. - * @hide - */ - public boolean addStackedLink(LinkProperties link) { - if (link != null && link.getInterfaceName() != null) { - mStackedLinks.put(link.getInterfaceName(), link); - return true; - } - return false; - } - - /** - * 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 remove. - * @return true if the link was removed, false otherwise. - * @hide - */ - public boolean removeStackedLink(LinkProperties link) { - if (link != null && link.getInterfaceName() != null) { - LinkProperties removed = mStackedLinks.remove(link.getInterfaceName()); - return removed != null; - } - return false; - } - - /** - * Returns all the links stacked on top of this link. - * @hide - */ - public List getStackedLinks() { - List stacked = new ArrayList(); - for (LinkProperties link : mStackedLinks.values()) { - stacked.add(new LinkProperties(link)); - } - return Collections.unmodifiableList(stacked); - } - - /** - * Clears this object to its initial state. - * @hide - */ - public void clear() { - mIfaceName = null; - mLinkAddresses.clear(); - mDnses.clear(); - mDomains = null; - mRoutes.clear(); - mHttpProxy = null; - mStackedLinks.clear(); - mMtu = 0; - } - - /** - * Implement the Parcelable interface - * @hide - */ - public int describeContents() { - return 0; - } - - @Override - public String toString() { - String ifaceName = (mIfaceName == null ? "" : "InterfaceName: " + mIfaceName + " "); - - String linkAddresses = "LinkAddresses: ["; - for (LinkAddress addr : mLinkAddresses) linkAddresses += addr.toString() + ","; - linkAddresses += "] "; - - String dns = "DnsAddresses: ["; - for (InetAddress addr : mDnses) dns += addr.getHostAddress() + ","; - dns += "] "; - - String domainName = "Domains: " + mDomains; - - String mtu = " MTU: " + mMtu; - - String routes = " Routes: ["; - for (RouteInfo route : mRoutes) routes += route.toString() + ","; - routes += "] "; - String proxy = (mHttpProxy == null ? "" : " HttpProxy: " + mHttpProxy.toString() + " "); - - String stacked = ""; - if (mStackedLinks.values().size() > 0) { - stacked += " Stacked: ["; - for (LinkProperties link: mStackedLinks.values()) { - stacked += " [" + link.toString() + " ],"; - } - stacked += "] "; - } - return "{" + ifaceName + linkAddresses + routes + dns + domainName + mtu - + proxy + stacked + "}"; - } - - /** - * 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) { - if (address.getAddress() instanceof Inet4Address) { - return true; - } - } - return false; - } - - /** - * 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) { - if (address.getAddress() instanceof Inet6Address) { - return true; - } - } - return false; - } - - /** - * Compares this {@code LinkProperties} interface name against the target - * - * @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()); - } - - /** - * Compares this {@code LinkProperties} interface addresses against the target - * - * @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(); - Collection sourceAddresses = getAddresses(); - return (sourceAddresses.size() == targetAddresses.size()) ? - sourceAddresses.containsAll(targetAddresses) : false; - } - - /** - * Compares this {@code LinkProperties} DNS addresses against the target - * - * @param target LinkProperties to compare. - * @return {@code true} if both are identical, {@code false} otherwise. - * @hide - */ - public boolean isIdenticalDnses(LinkProperties target) { - Collection targetDnses = target.getDnsServers(); - 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; - } - - /** - * Compares this {@code LinkProperties} Routes against the target - * - * @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(); - return (mRoutes.size() == targetRoutes.size()) ? - mRoutes.containsAll(targetRoutes) : false; - } - - /** - * Compares this {@code LinkProperties} HttpProxy against the target - * - * @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 : - 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. - * @hide - */ - public boolean isIdenticalStackedLinks(LinkProperties target) { - if (!mStackedLinks.keySet().equals(target.mStackedLinks.keySet())) { - 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; - } - - /** - * Compares this {@code LinkProperties} MTU against the target - * - * @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(); - } - - @Override - /** - * Compares this {@code LinkProperties} instance against the target - * LinkProperties in {@code obj}. Two LinkPropertieses are equal if - * all their fields are equal in values. - * - * For collection fields, such as mDnses, containsAll() is used to check - * if two collections contains the same elements, independent of order. - * There are two thoughts regarding containsAll() - * 1. Duplicated elements. eg, (A, B, B) and (A, A, B) are equal. - * 2. Worst case performance is O(n^2). - * - * @param obj the object to be tested for equality. - * @return {@code true} if both objects are equal, {@code false} otherwise. - */ - public boolean equals(Object obj) { - if (this == obj) return true; - - 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) && - isIdenticalRoutes(target) && - isIdenticalHttpProxy(target) && - isIdenticalStackedLinks(target) && - isIdenticalMtu(target); - } - - /** - * Compares the addresses in this LinkProperties with another - * LinkProperties, examining only addresses on the base link. - * - * @param target a LinkProperties with the new list of addresses - * @return the differences between the addresses. - * @hide - */ - public CompareResult compareAddresses(LinkProperties target) { - /* - * Duplicate the LinkAddresses into removed, we will be removing - * address which are common between mLinkAddresses and target - * leaving the addresses that are different. And address which - * are in target but not in mLinkAddresses are placed in the - * addedAddresses. - */ - CompareResult result = new CompareResult(); - result.removed = new ArrayList(mLinkAddresses); - result.added.clear(); - if (target != null) { - for (LinkAddress newAddress : target.getLinkAddresses()) { - if (! result.removed.remove(newAddress)) { - result.added.add(newAddress); - } - } - } - return result; - } - - /** - * Compares the DNS addresses in this LinkProperties with another - * LinkProperties, examining only DNS addresses on the base link. - * - * @param target a LinkProperties with the new list of dns addresses - * @return the differences between the DNS addresses. - * @hide - */ - public CompareResult compareDnses(LinkProperties target) { - /* - * Duplicate the InetAddresses into removed, we will be removing - * dns address which are common between mDnses and target - * leaving the addresses that are different. And dns address which - * are in target but not in mDnses are placed in the - * addedAddresses. - */ - CompareResult result = new CompareResult(); - - result.removed = new ArrayList(mDnses); - result.added.clear(); - if (target != null) { - for (InetAddress newAddress : target.getDnsServers()) { - if (! result.removed.remove(newAddress)) { - result.added.add(newAddress); - } - } - } - return result; - } - - /** - * Compares all routes 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 routes - * @return the differences between the routes. - * @hide - */ - public CompareResult compareAllRoutes(LinkProperties target) { - /* - * Duplicate the RouteInfos into removed, we will be removing - * 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. - */ - CompareResult result = new CompareResult(); - - result.removed = getAllRoutes(); - result.added.clear(); - if (target != null) { - for (RouteInfo r : target.getAllRoutes()) { - if (! result.removed.remove(r)) { - result.added.add(r); - } - } - } - 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 - /** - * generate hashcode based on significant fields - * Equal objects must produce the same hash code, while unequal objects - * may have the same hash codes. - */ - public int hashCode() { - 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()) - + mStackedLinks.hashCode() * 47) - + mMtu * 51; - } - - /** - * Implement the Parcelable interface. - */ - public void writeToParcel(Parcel dest, int flags) { - dest.writeString(getInterfaceName()); - dest.writeInt(mLinkAddresses.size()); - for(LinkAddress linkAddress : mLinkAddresses) { - dest.writeParcelable(linkAddress, flags); - } - - dest.writeInt(mDnses.size()); - for(InetAddress d : mDnses) { - dest.writeByteArray(d.getAddress()); - } - dest.writeString(mDomains); - dest.writeInt(mMtu); - dest.writeInt(mRoutes.size()); - for(RouteInfo route : mRoutes) { - dest.writeParcelable(route, flags); - } - - if (mHttpProxy != null) { - dest.writeByte((byte)1); - dest.writeParcelable(mHttpProxy, flags); - } else { - dest.writeByte((byte)0); - } - ArrayList stackedLinks = new ArrayList(mStackedLinks.values()); - dest.writeList(stackedLinks); - } - - /** - * Implement the Parcelable interface. - */ - public static final Creator CREATOR = - new Creator() { - public LinkProperties createFromParcel(Parcel in) { - LinkProperties netProp = new LinkProperties(); - - String iface = in.readString(); - if (iface != null) { - netProp.setInterfaceName(iface); - } - int addressCount = in.readInt(); - for (int i=0; i stackedLinks = new ArrayList(); - in.readList(stackedLinks, LinkProperties.class.getClassLoader()); - for (LinkProperties stackedLink: stackedLinks) { - netProp.addStackedLink(stackedLink); - } - return netProp; - } - - public LinkProperties[] newArray(int size) { - return new LinkProperties[size]; - } - }; -} diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java deleted file mode 100644 index d933f26c78..0000000000 --- a/core/java/android/net/Network.java +++ /dev/null @@ -1,201 +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.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; - -/** - * Identifies a {@code Network}. This is supplied to applications via - * {@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 ConnectivityManager#setProcessDefaultNetwork}. - */ -public class Network implements Parcelable { - - /** - * @hide - */ - public final int netId; - - private NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; - - /** - * @hide - */ - public Network(int netId) { - this.netId = netId; - } - - /** - * @hide - */ - public Network(Network that) { - 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); - } - - /** - * 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; - } - - 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)); - connectToHost(socket, 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(); - connectToHost(socket, 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 - * {@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 getSocketFactory() { - if (mNetworkBoundSocketFactory == null) { - mNetworkBoundSocketFactory = new NetworkBoundSocketFactory(netId); - } - return mNetworkBoundSocketFactory; - } - - // 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]; - } - }; - - 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; - } -} diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java deleted file mode 100644 index 3d0874beda..0000000000 --- a/core/java/android/net/NetworkAgent.java +++ /dev/null @@ -1,207 +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.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 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 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). - * - * @hide - */ -public abstract class NetworkAgent extends Handler { - private volatile AsyncChannel mAsyncChannel; - private final String LOG_TAG; - private static final boolean DBG = true; - private static final boolean VDBG = true; - private final Context mContext; - private final ArrayListmPreConnectedQueue = new ArrayList(); - - private static final int BASE = Protocol.BASE_NETWORK_AGENT; - - /** - * 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; - - /** - * 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 + 1; - - /** - * Sent by the NetworkAgent to ConnectivityService to pass the current - * NetworkCapabilties. - * obj = NetworkCapabilities - */ - 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 + 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. - * obj = network score Integer - */ - public static final int EVENT_NETWORK_SCORE_CHANGED = BASE + 4; - - public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni, - NetworkCapabilities nc, LinkProperties lp, int score) { - super(looper); - LOG_TAG = logTag; - mContext = context; - 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: { - 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; - } - 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"); - // let the client know CS is done with us. - unwanted(); - synchronized (mPreConnectedQueue) { - mAsyncChannel = null; - } - break; - } - case CMD_SUSPECT_BAD: { - log("Unhandled Message " + msg); - break; - } - } - } - - 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); - } - } - } - - /** - * Called by the bearer code when it has new LinkProperties data. - */ - public void sendLinkProperties(LinkProperties linkProperties) { - queueOrSendMessage(EVENT_NETWORK_PROPERTIES_CHANGED, new LinkProperties(linkProperties)); - } - - /** - * Called by the bearer code when it has new NetworkInfo data. - */ - public void sendNetworkInfo(NetworkInfo networkInfo) { - queueOrSendMessage(EVENT_NETWORK_INFO_CHANGED, new NetworkInfo(networkInfo)); - } - - /** - * Called by the bearer code when it has new NetworkCapabilities data. - */ - public void sendNetworkCapabilities(NetworkCapabilities networkCapabilities) { - queueOrSendMessage(EVENT_NETWORK_CAPABILITIES_CHANGED, - new NetworkCapabilities(networkCapabilities)); - } - - /** - * Called by the bearer code when it has a new score for this network. - */ - public void sendNetworkScore(int score) { - queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new Integer(score)); - } - - /** - * 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/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java deleted file mode 100644 index fe96287c83..0000000000 --- a/core/java/android/net/NetworkCapabilities.java +++ /dev/null @@ -1,526 +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.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; - -/** - * 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; - - /** - * @hide - */ - 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 - * by any Network that matches all of them. - */ - private long mNetworkCapabilities = (1 << NET_CAPABILITY_NOT_RESTRICTED); - - /** - * 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; - - /** - * 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 capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be added. - * @return This NetworkCapability to facilitate chaining. - * @hide - */ - public NetworkCapabilities addCapability(int capability) { - if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { - throw new IllegalArgumentException("NetworkCapability out of range"); - } - mNetworkCapabilities |= 1 << capability; - return this; - } - - /** - * Removes (if found) the given capability from this {@code NetworkCapability} instance. - * - * @param capability the {@code NetworkCapabilities.NET_CAPABILTIY_*} to be removed. - * @return This NetworkCapability to facilitate chaining. - * @hide - */ - public NetworkCapabilities removeCapability(int capability) { - if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { - throw new IllegalArgumentException("NetworkCapability out of range"); - } - mNetworkCapabilities &= ~(1 << capability); - return this; - } - - /** - * Gets all the capabilities set on this {@code NetworkCapability} instance. - * - * @return an array of {@code NetworkCapabilities.NET_CAPABILITY_*} values - * for this instance. - * @hide - */ - public int[] getCapabilities() { - return enumerateBits(mNetworkCapabilities); - } - - /** - * Tests for the presence of a capabilitity on this instance. - * - * @param capability the {@code NetworkCapabilities.NET_CAPABILITY_*} to be tested for. - * @return {@code true} if set on this instance. - */ - public boolean hasCapability(int capability) { - if (capability < MIN_NET_CAPABILITY || capability > MAX_NET_CAPABILITY) { - return false; - } - return ((mNetworkCapabilities & (1 << capability)) != 0); - } - - 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[index++] = 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; - - /** - * 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. - * @return This NetworkCapability to facilitate chaining. - * @hide - */ - 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 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 an array of {@code NetworkCapabilities.TRANSPORT_*} values - * for this instance. - * @hide - */ - public int[] 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; - } - return ((mTransportTypes & (1 << transportType)) != 0); - } - - 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; - - /** - * 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. - * @hide - */ - 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. - * @hide - */ - 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; - } - - 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 (nc != null && - 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 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() { - 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 < types.length) transports += "|"; - } - - 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; - 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 < types.length) capabilities += "&"; - } - - String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" + - mLinkUpBandwidthKbps + "Kbps" : ""); - String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" + - mLinkDownBandwidthKbps + "Kbps" : ""); - - return "[" + transports + capabilities + upBand + dnBand + "]"; - } -} diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java deleted file mode 100644 index 32a2cda003..0000000000 --- a/core/java/android/net/NetworkConfig.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.util.Locale; - -/** - * Describes the buildtime configuration of a network. - * Holds settings read from resources. - * @hide - */ -public class NetworkConfig { - /** - * Human readable string - */ - public String name; - - /** - * Type from ConnectivityManager - */ - public int type; - - /** - * the radio number from radio attributes config - */ - public int radio; - - /** - * higher number == higher priority when turning off connections - */ - public int priority; - - /** - * indicates the boot time dependencyMet setting - */ - public boolean dependencyMet; - - /** - * indicates the default restoral timer in seconds - * if the network is used as a special network feature - * -1 indicates no restoration of default - */ - public int restoreTime; - - /** - * input string from config.xml resource. Uses the form: - * [Connection name],[ConnectivityManager connection type], - * [associated radio-type],[priority],[dependencyMet] - */ - public NetworkConfig(String init) { - String fragments[] = init.split(","); - name = fragments[0].trim().toLowerCase(Locale.ROOT); - type = Integer.parseInt(fragments[1]); - radio = Integer.parseInt(fragments[2]); - priority = Integer.parseInt(fragments[3]); - restoreTime = Integer.parseInt(fragments[4]); - dependencyMet = Boolean.parseBoolean(fragments[5]); - } - - /** - * Indicates if this network is supposed to be default-routable - */ - public boolean isDefault() { - return (type == radio); - } -} diff --git a/core/java/android/net/NetworkInfo.java b/core/java/android/net/NetworkInfo.java deleted file mode 100644 index d2794127f5..0000000000 --- a/core/java/android/net/NetworkInfo.java +++ /dev/null @@ -1,506 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcelable; -import android.os.Parcel; - -import com.android.internal.annotations.VisibleForTesting; - -import java.util.EnumMap; - -/** - * Describes the status of a network interface. - *

Use {@link ConnectivityManager#getActiveNetworkInfo()} to get an instance that represents - * the current network connection. - */ -public class NetworkInfo implements Parcelable { - - /** - * Coarse-grained network state. This is probably what most applications should - * use, rather than {@link android.net.NetworkInfo.DetailedState DetailedState}. - * The mapping between the two is as follows: - *

- * - * - * - * - * - * - * - * - * - * - * - *
Detailed stateCoarse-grained state
IDLEDISCONNECTED
SCANNINGCONNECTING
CONNECTINGCONNECTING
AUTHENTICATINGCONNECTING
CONNECTEDCONNECTED
DISCONNECTINGDISCONNECTING
DISCONNECTEDDISCONNECTED
UNAVAILABLEDISCONNECTED
FAILEDDISCONNECTED
- */ - public enum State { - CONNECTING, CONNECTED, SUSPENDED, DISCONNECTING, DISCONNECTED, UNKNOWN - } - - /** - * The fine-grained state of a network connection. This level of detail - * is probably of interest to few applications. Most should use - * {@link android.net.NetworkInfo.State State} instead. - */ - public enum DetailedState { - /** Ready to start data connection setup. */ - IDLE, - /** Searching for an available access point. */ - SCANNING, - /** Currently setting up data connection. */ - CONNECTING, - /** Network link established, performing authentication. */ - AUTHENTICATING, - /** Awaiting response from DHCP server in order to assign IP address information. */ - OBTAINING_IPADDR, - /** IP traffic should be available. */ - CONNECTED, - /** IP traffic is suspended */ - SUSPENDED, - /** Currently tearing down data connection. */ - DISCONNECTING, - /** IP traffic not available. */ - DISCONNECTED, - /** Attempt to connect failed. */ - FAILED, - /** Access to this network is blocked. */ - BLOCKED, - /** Link has poor connectivity. */ - VERIFYING_POOR_LINK, - /** Checking if network is a captive portal */ - CAPTIVE_PORTAL_CHECK - } - - /** - * This is the map described in the Javadoc comment above. The positions - * of the elements of the array must correspond to the ordinal values - * of DetailedState. - */ - private static final EnumMap stateMap = - new EnumMap(DetailedState.class); - - static { - stateMap.put(DetailedState.IDLE, State.DISCONNECTED); - stateMap.put(DetailedState.SCANNING, State.DISCONNECTED); - stateMap.put(DetailedState.CONNECTING, State.CONNECTING); - 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); - stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED); - stateMap.put(DetailedState.FAILED, State.DISCONNECTED); - stateMap.put(DetailedState.BLOCKED, State.DISCONNECTED); - } - - private int mNetworkType; - private int mSubtype; - private String mTypeName; - private String mSubtypeName; - private State mState; - private DetailedState mDetailedState; - private String mReason; - private String mExtraInfo; - private boolean mIsFailover; - private boolean mIsRoaming; - private boolean mIsConnectedToProvisioningNetwork; - - /** - * Indicates whether network connectivity is possible: - */ - private boolean mIsAvailable; - - /** - * @param type network type - * @deprecated - * @hide because this constructor was only meant for internal use (and - * has now been superseded by the package-private constructor below). - */ - public NetworkInfo(int type) {} - - /** - * @hide - */ - public NetworkInfo(int type, int subtype, String typeName, String subtypeName) { - if (!ConnectivityManager.isNetworkTypeValid(type)) { - throw new IllegalArgumentException("Invalid network type: " + type); - } - mNetworkType = type; - mSubtype = subtype; - mTypeName = typeName; - mSubtypeName = subtypeName; - setDetailedState(DetailedState.IDLE, null, null); - mState = State.UNKNOWN; - mIsAvailable = false; // until we're told otherwise, assume unavailable - mIsRoaming = false; - mIsConnectedToProvisioningNetwork = false; - } - - /** {@hide} */ - public NetworkInfo(NetworkInfo source) { - if (source != null) { - 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; - } - } - } - - /** - * Reports the type of network to which the - * info in this {@code NetworkInfo} pertains. - * @return one of {@link ConnectivityManager#TYPE_MOBILE}, {@link - * ConnectivityManager#TYPE_WIFI}, {@link ConnectivityManager#TYPE_WIMAX}, {@link - * ConnectivityManager#TYPE_ETHERNET}, {@link ConnectivityManager#TYPE_BLUETOOTH}, or other - * types defined by {@link ConnectivityManager} - */ - public int getType() { - synchronized (this) { - return mNetworkType; - } - } - - /** - * @hide - */ - public void setType(int type) { - synchronized (this) { - mNetworkType = type; - } - } - - /** - * Return a network-type-specific integer describing the subtype - * of the network. - * @return the network subtype - */ - public int getSubtype() { - synchronized (this) { - return mSubtype; - } - } - - /** - * @hide - */ - public void setSubtype(int subtype, String subtypeName) { - synchronized (this) { - mSubtype = subtype; - mSubtypeName = subtypeName; - } - } - - /** - * Return a human-readable name describe the type of the network, - * for example "WIFI" or "MOBILE". - * @return the name of the network type - */ - public String getTypeName() { - synchronized (this) { - return mTypeName; - } - } - - /** - * Return a human-readable name describing the subtype of the network. - * @return the name of the network subtype - */ - public String getSubtypeName() { - synchronized (this) { - return mSubtypeName; - } - } - - /** - * Indicates whether network connectivity exists or is in the process - * of being established. This is good for applications that need to - * do anything related to the network other than read or write data. - * For the latter, call {@link #isConnected()} instead, which guarantees - * that the network is fully usable. - * @return {@code true} if network connectivity exists or is in the process - * of being established, {@code false} otherwise. - */ - public boolean isConnectedOrConnecting() { - synchronized (this) { - return mState == State.CONNECTED || mState == State.CONNECTING; - } - } - - /** - * Indicates whether network connectivity exists and it is possible to establish - * connections and pass data. - *

Always call this before attempting to perform data transactions. - * @return {@code true} if network connectivity exists, {@code false} otherwise. - */ - public boolean isConnected() { - synchronized (this) { - return mState == State.CONNECTED; - } - } - - /** - * Indicates whether network connectivity is possible. A network is unavailable - * when a persistent or semi-persistent condition prevents the possibility - * of connecting to that network. Examples include - *

    - *
  • The device is out of the coverage area for any network of this type.
  • - *
  • The device is on a network other than the home network (i.e., roaming), and - * data roaming has been disabled.
  • - *
  • The device's radio is turned off, e.g., because airplane mode is enabled.
  • - *
- * @return {@code true} if the network is available, {@code false} otherwise - */ - public boolean isAvailable() { - synchronized (this) { - return mIsAvailable; - } - } - - /** - * Sets if the network is available, ie, if the connectivity is possible. - * @param isAvailable the new availability value. - * - * @hide - */ - public void setIsAvailable(boolean isAvailable) { - synchronized (this) { - mIsAvailable = isAvailable; - } - } - - /** - * Indicates whether the current attempt to connect to the network - * resulted from the ConnectivityManager trying to fail over to this - * network following a disconnect from another network. - * @return {@code true} if this is a failover attempt, {@code false} - * otherwise. - */ - public boolean isFailover() { - synchronized (this) { - return mIsFailover; - } - } - - /** - * Set the failover boolean. - * @param isFailover {@code true} to mark the current connection attempt - * as a failover. - * @hide - */ - public void setFailover(boolean isFailover) { - synchronized (this) { - mIsFailover = isFailover; - } - } - - /** - * Indicates whether the device is currently roaming on this network. - * When {@code true}, it suggests that use of data on this network - * may incur extra costs. - * @return {@code true} if roaming is in effect, {@code false} otherwise. - */ - public boolean isRoaming() { - synchronized (this) { - return mIsRoaming; - } - } - - /** {@hide} */ - @VisibleForTesting - public void setRoaming(boolean isRoaming) { - synchronized (this) { - mIsRoaming = isRoaming; - } - } - - /** {@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 - */ - public State getState() { - synchronized (this) { - return mState; - } - } - - /** - * Reports the current fine-grained state of the network. - * @return the fine-grained state - */ - public DetailedState getDetailedState() { - synchronized (this) { - return mDetailedState; - } - } - - /** - * Sets the fine-grained state of the network. - * @param detailedState the {@link DetailedState}. - * @param reason a {@code String} indicating the reason for the state change, - * if one was supplied. May be {@code null}. - * @param extraInfo an optional {@code String} providing addditional network state - * information passed up from the lower networking layers. - * @hide - */ - public void setDetailedState(DetailedState detailedState, String reason, String extraInfo) { - synchronized (this) { - this.mDetailedState = detailedState; - this.mState = stateMap.get(detailedState); - this.mReason = reason; - this.mExtraInfo = extraInfo; - } - } - - /** - * Set the extraInfo field. - * @param extraInfo an optional {@code String} providing addditional network state - * information passed up from the lower networking layers. - * @hide - */ - public void setExtraInfo(String extraInfo) { - synchronized (this) { - this.mExtraInfo = extraInfo; - } - } - - /** - * Report the reason an attempt to establish connectivity failed, - * if one is available. - * @return the reason for failure, or null if not available - */ - public String getReason() { - synchronized (this) { - return mReason; - } - } - - /** - * Report the extra information about the network state, if any was - * provided by the lower networking layers., - * if one is available. - * @return the extra information, or null if not available - */ - public String getExtraInfo() { - synchronized (this) { - return mExtraInfo; - } - } - - @Override - public String toString() { - synchronized (this) { - 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). - append(", extra: ").append(mExtraInfo == null ? "(none)" : mExtraInfo). - append(", roaming: ").append(mIsRoaming). - append(", failover: ").append(mIsFailover). - append(", isAvailable: ").append(mIsAvailable). - append(", isConnectedToProvisioningNetwork: "). - append(mIsConnectedToProvisioningNetwork). - append("]"); - return builder.toString(); - } - } - - /** - * Implement the Parcelable interface - * @hide - */ - public int describeContents() { - return 0; - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public void writeToParcel(Parcel dest, int flags) { - synchronized (this) { - dest.writeInt(mNetworkType); - dest.writeInt(mSubtype); - dest.writeString(mTypeName); - dest.writeString(mSubtypeName); - dest.writeString(mState.name()); - dest.writeString(mDetailedState.name()); - 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); - } - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public static final Creator CREATOR = - new Creator() { - public NetworkInfo createFromParcel(Parcel in) { - int netType = in.readInt(); - int subtype = in.readInt(); - String typeName = in.readString(); - String subtypeName = in.readString(); - NetworkInfo netInfo = new NetworkInfo(netType, subtype, typeName, subtypeName); - netInfo.mState = State.valueOf(in.readString()); - netInfo.mDetailedState = DetailedState.valueOf(in.readString()); - 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; - } - - public NetworkInfo[] newArray(int size) { - return new NetworkInfo[size]; - } - }; -} diff --git a/core/java/android/net/NetworkRequest.java b/core/java/android/net/NetworkRequest.java deleted file mode 100644 index 7911c729d3..0000000000 --- a/core/java/android/net/NetworkRequest.java +++ /dev/null @@ -1,200 +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.os.Parcel; -import android.os.Parcelable; - -import java.util.concurrent.atomic.AtomicInteger; - -/** - * 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. - * @hide - */ - 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. - * @hide - */ - public final int requestId; - - /** - * Set for legacy requests and the default. Set to TYPE_NONE for none. - * Causes CONNECTIVITY_ACTION broadcasts to be sent. - * @hide - */ - public final int legacyType; - - /** - * @hide - */ - public NetworkRequest(NetworkCapabilities nc, int legacyType, int rId) { - requestId = rId; - networkCapabilities = nc; - this.legacyType = legacyType; - } - - /** - * @hide - */ - public NetworkRequest(NetworkRequest that) { - networkCapabilities = new NetworkCapabilities(that.networkCapabilities); - requestId = that.requestId; - 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; - } - public void writeToParcel(Parcel dest, int flags) { - dest.writeParcelable(networkCapabilities, flags); - dest.writeInt(legacyType); - dest.writeInt(requestId); - } - public static final Creator CREATOR = - new Creator() { - public NetworkRequest createFromParcel(Parcel in) { - NetworkCapabilities nc = (NetworkCapabilities)in.readParcelable(null); - int legacyType = in.readInt(); - int requestId = in.readInt(); - NetworkRequest result = new NetworkRequest(nc, legacyType, requestId); - return result; - } - public NetworkRequest[] newArray(int size) { - return new NetworkRequest[size]; - } - }; - - public String toString() { - 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.legacyType == this.legacyType && - that.requestId == this.requestId && - ((that.networkCapabilities == null && this.networkCapabilities == null) || - (that.networkCapabilities != null && - that.networkCapabilities.equals(this.networkCapabilities)))); - } - - public int hashCode() { - return requestId + (legacyType * 1013) + - (networkCapabilities.hashCode() * 1051); - } -} diff --git a/core/java/android/net/NetworkState.java b/core/java/android/net/NetworkState.java deleted file mode 100644 index 2e0e9e432b..0000000000 --- a/core/java/android/net/NetworkState.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -/** - * Snapshot of network state. - * - * @hide - */ -public class NetworkState implements Parcelable { - - public final NetworkInfo networkInfo; - public final LinkProperties linkProperties; - public final NetworkCapabilities networkCapabilities; - /** Currently only used by testing. */ - public final String subscriberId; - public final String networkId; - - public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - NetworkCapabilities networkCapabilities) { - this(networkInfo, linkProperties, networkCapabilities, null, null); - } - - public NetworkState(NetworkInfo networkInfo, LinkProperties linkProperties, - NetworkCapabilities networkCapabilities, String subscriberId, String networkId) { - this.networkInfo = networkInfo; - this.linkProperties = linkProperties; - this.networkCapabilities = networkCapabilities; - this.subscriberId = subscriberId; - this.networkId = networkId; - } - - public NetworkState(Parcel in) { - networkInfo = in.readParcelable(null); - linkProperties = in.readParcelable(null); - networkCapabilities = in.readParcelable(null); - subscriberId = in.readString(); - networkId = in.readString(); - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(networkInfo, flags); - out.writeParcelable(linkProperties, flags); - out.writeParcelable(networkCapabilities, flags); - out.writeString(subscriberId); - out.writeString(networkId); - } - - public static final Creator CREATOR = new Creator() { - @Override - public NetworkState createFromParcel(Parcel in) { - return new NetworkState(in); - } - - @Override - public NetworkState[] newArray(int size) { - return new NetworkState[size]; - } - }; - -} diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java deleted file mode 100644 index b02f88ec81..0000000000 --- a/core/java/android/net/NetworkUtils.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.Inet6Address; -import java.net.UnknownHostException; -import java.util.Collection; -import java.util.Locale; - -import android.util.Log; - -/** - * Native methods for managing network interfaces. - * - * {@hide} - */ -public class NetworkUtils { - - private static final String TAG = "NetworkUtils"; - - /** Bring the named network interface up. */ - public native static int enableInterface(String interfaceName); - - /** Bring the named network interface down. */ - public native static int disableInterface(String interfaceName); - - /** Setting bit 0 indicates reseting of IPv4 addresses required */ - public static final int RESET_IPV4_ADDRESSES = 0x01; - - /** Setting bit 1 indicates reseting of IPv4 addresses required */ - public static final int RESET_IPV6_ADDRESSES = 0x02; - - /** Reset all addresses */ - public static final int RESET_ALL_ADDRESSES = RESET_IPV4_ADDRESSES | RESET_IPV6_ADDRESSES; - - /** - * Reset IPv6 or IPv4 sockets that are connected via the named interface. - * - * @param interfaceName is the interface to reset - * @param mask {@see #RESET_IPV4_ADDRESSES} and {@see #RESET_IPV6_ADDRESSES} - */ - public native static int resetConnections(String interfaceName, int mask); - - /** - * Start the DHCP client daemon, in order to have it request addresses - * for the named interface, and then configure the interface with those - * addresses. This call blocks until it obtains a result (either success - * or failure) from the daemon. - * @param interfaceName the name of the interface to configure - * @param dhcpResults if the request succeeds, this object is filled in with - * the IP address information. - * @return {@code true} for success, {@code false} for failure - */ - public native static boolean runDhcp(String interfaceName, DhcpResults dhcpResults); - - /** - * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains - * a result (either success or failure) from the daemon. - * @param interfaceName the name of the interface to configure - * @param dhcpResults if the request succeeds, this object is filled in with - * the IP address information. - * @return {@code true} for success, {@code false} for failure - */ - public native static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults); - - /** - * Shut down the DHCP client daemon. - * @param interfaceName the name of the interface for which the daemon - * should be stopped - * @return {@code true} for success, {@code false} for failure - */ - public native static boolean stopDhcp(String interfaceName); - - /** - * Release the current DHCP lease. - * @param interfaceName the name of the interface for which the lease should - * be released - * @return {@code true} for success, {@code false} for failure - */ - public native static boolean releaseDhcpLease(String interfaceName); - - /** - * Return the last DHCP-related error message that was recorded. - *

NOTE: This string is not localized, but currently it is only - * used in logging. - * @return the most recent error message, if any - */ - public native static String getDhcpError(); - - /** - * Set the SO_MARK of {@code socketfd} to {@code mark} - */ - 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#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}. - */ - 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 - */ - public static InetAddress intToInetAddress(int hostAddress) { - byte[] addressBytes = { (byte)(0xff & hostAddress), - (byte)(0xff & (hostAddress >> 8)), - (byte)(0xff & (hostAddress >> 16)), - (byte)(0xff & (hostAddress >> 24)) }; - - try { - return InetAddress.getByAddress(addressBytes); - } catch (UnknownHostException e) { - throw new AssertionError(); - } - } - - /** - * Convert a IPv4 address from an InetAddress to an integer - * @param inetAddr is an InetAddress corresponding to the IPv4 address - * @return the IP address as an integer in network byte order - */ - public static int inetAddressToInt(Inet4Address inetAddr) - throws IllegalArgumentException { - byte [] addr = inetAddr.getAddress(); - return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) | - ((addr[1] & 0xff) << 8) | (addr[0] & 0xff); - } - - /** - * Convert a network prefix length to an IPv4 netmask integer - * @param prefixLength - * @return the IPv4 netmask as an integer in network byte order - */ - public static int prefixLengthToNetmaskInt(int prefixLength) - throws IllegalArgumentException { - if (prefixLength < 0 || prefixLength > 32) { - throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)"); - } - int value = 0xffffffff << (32 - prefixLength); - return Integer.reverseBytes(value); - } - - /** - * Convert a IPv4 netmask integer to a prefix length - * @param netmask as an integer in network byte order - * @return the network prefix length - */ - public static int netmaskIntToPrefixLength(int netmask) { - return Integer.bitCount(netmask); - } - - /** - * Create an InetAddress from a string where the string must be a standard - * representation of a V4 or V6 address. Avoids doing a DNS lookup on failure - * but it will throw an IllegalArgumentException in that case. - * @param addrString - * @return the InetAddress - * @hide - */ - public static InetAddress numericToInetAddress(String addrString) - throws IllegalArgumentException { - return InetAddress.parseNumericAddress(addrString); - } - - /** - * Get InetAddress masked with prefixLength. Will never return null. - * @param IP address which will be masked with specified prefixLength - * @param prefixLength the prefixLength used to mask the IP - */ - public static InetAddress getNetworkPart(InetAddress address, int prefixLength) { - if (address == null) { - throw new RuntimeException("getNetworkPart doesn't accept null address"); - } - - byte[] array = address.getAddress(); - - if (prefixLength < 0 || prefixLength > array.length * 8) { - throw new RuntimeException("getNetworkPart - bad prefixLength"); - } - - int offset = prefixLength / 8; - int reminder = prefixLength % 8; - byte mask = (byte)(0xFF << (8 - reminder)); - - if (offset < array.length) array[offset] = (byte)(array[offset] & mask); - - offset++; - - for (; offset < array.length; offset++) { - array[offset] = 0; - } - - InetAddress netPart = null; - try { - netPart = InetAddress.getByAddress(array); - } catch (UnknownHostException e) { - throw new RuntimeException("getNetworkPart error - " + e.toString()); - } - return netPart; - } - - /** - * Check if IP address type is consistent between two InetAddress. - * @return true if both are the same type. False otherwise. - */ - public static boolean addressTypeMatches(InetAddress left, InetAddress right) { - return (((left instanceof Inet4Address) && (right instanceof Inet4Address)) || - ((left instanceof Inet6Address) && (right instanceof Inet6Address))); - } - - /** - * Convert a 32 char hex string into a Inet6Address. - * throws a runtime exception if the string isn't 32 chars, isn't hex or can't be - * made into an Inet6Address - * @param addrHexString a 32 character hex string representing an IPv6 addr - * @return addr an InetAddress representation for the string - */ - public static InetAddress hexToInet6Address(String addrHexString) - throws IllegalArgumentException { - try { - 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), - addrHexString.substring(24,28), addrHexString.substring(28,32))); - } catch (Exception e) { - Log.e("NetworkUtils", "error in hexToInet6Address(" + addrHexString + "): " + e); - throw new IllegalArgumentException(e); - } - } - - /** - * Create a string array of host addresses from a collection of InetAddresses - * @param addrs a Collection of InetAddresses - * @return an array of Strings containing their host addresses - */ - public static String[] makeStrings(Collection addrs) { - String[] result = new String[addrs.size()]; - int i = 0; - for (InetAddress addr : addrs) { - result[i++] = addr.getHostAddress(); - } - return result; - } - - /** - * Trim leading zeros from IPv4 address strings - * Our base libraries will interpret that as octel.. - * Must leave non v4 addresses and host names alone. - * For example, 192.168.000.010 -> 192.168.0.10 - * TODO - fix base libraries and remove this function - * @param addr a string representing an ip addr - * @return a string propertly trimmed - */ - public static String trimV4AddrZeros(String addr) { - if (addr == null) return null; - String[] octets = addr.split("\\."); - if (octets.length != 4) return addr; - StringBuilder builder = new StringBuilder(16); - String result = null; - for (int i = 0; i < 4; i++) { - try { - if (octets[i].length() > 3) return addr; - builder.append(Integer.parseInt(octets[i])); - } catch (NumberFormatException e) { - return addr; - } - if (i < 3) builder.append('.'); - } - result = builder.toString(); - return result; - } -} diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java deleted file mode 100644 index 7ea6bae83d..0000000000 --- a/core/java/android/net/ProxyInfo.java +++ /dev/null @@ -1,366 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - - -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; - -/** - * 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 ProxyInfo implements Parcelable { - - private String mHost; - private int mPort; - private String mExclusionList; - private String[] mParsedExclusionList; - - private Uri 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"; - - /** - * 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); - } - - /** - * Create a ProxyProperties that points at a HTTP Proxy. - * @hide - */ - public ProxyInfo(String host, int port, String exclList) { - 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; - } - - /** - * 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 = Uri.parse(pacFileUrl); - } - - /** - * Only used in PacManager after Local Proxy is bound. - * @hide - */ - public ProxyInfo(Uri pacFileUrl, int localProxyPort) { - mHost = LOCAL_HOST; - mPort = localProxyPort; - setExclusionList(LOCAL_EXCL_LIST); - if (pacFileUrl == null) { - throw new NullPointerException(); - } - mPacFileUrl = pacFileUrl; - } - - private ProxyInfo(String host, int port, String exclList, String[] parsedExclList) { - mHost = host; - mPort = port; - mExclusionList = exclList; - mParsedExclusionList = parsedExclList; - mPacFileUrl = Uri.EMPTY; - } - - // copy constructor instead of clone - /** - * @hide - */ - public ProxyInfo(ProxyInfo source) { - if (source != null) { - mHost = source.getHost(); - mPort = source.getPort(); - mPacFileUrl = source.mPacFileUrl; - mExclusionList = source.getExclusionListAsString(); - mParsedExclusionList = source.mParsedExclusionList; - } else { - mPacFileUrl = Uri.EMPTY; - } - } - - /** - * @hide - */ - public InetSocketAddress getSocketAddress() { - InetSocketAddress inetSocketAddress = null; - try { - inetSocketAddress = new InetSocketAddress(mHost, mPort); - } catch (IllegalArgumentException e) { } - return inetSocketAddress; - } - - /** - * Returns the URL of the current PAC script or null if there is - * no PAC script. - */ - public Uri getPacFileUrl() { - return 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; - } - - /** - * 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; - } - - // comma separated - private void setExclusionList(String exclusionList) { - mExclusionList = exclusionList; - if (mExclusionList == null) { - mParsedExclusionList = new String[0]; - } else { - mParsedExclusionList = exclusionList.toLowerCase(Locale.ROOT).split(","); - } - } - - /** - * @hide - */ - public boolean isValid() { - if (!Uri.EMPTY.equals(mPacFileUrl)) return true; - return Proxy.PROXY_VALID == Proxy.validate(mHost == null ? "" : mHost, - mPort == 0 ? "" : Integer.toString(mPort), - mExclusionList == null ? "" : mExclusionList); - } - - /** - * @hide - */ - public java.net.Proxy makeProxy() { - java.net.Proxy proxy = java.net.Proxy.NO_PROXY; - if (mHost != null) { - try { - InetSocketAddress inetSocketAddress = new InetSocketAddress(mHost, mPort); - proxy = new java.net.Proxy(java.net.Proxy.Type.HTTP, inetSocketAddress); - } catch (IllegalArgumentException e) { - } - } - return proxy; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - if (!Uri.EMPTY.equals(mPacFileUrl)) { - sb.append("PAC Script: "); - sb.append(mPacFileUrl); - } else if (mHost != null) { - sb.append("["); - sb.append(mHost); - sb.append("] "); - sb.append(Integer.toString(mPort)); - if (mExclusionList != null) { - sb.append(" xl=").append(mExclusionList); - } - } else { - sb.append("[ProxyProperties.mHost == null]"); - } - return sb.toString(); - } - - @Override - public boolean equals(Object 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 (!Uri.EMPTY.equals(mPacFileUrl)) { - return mPacFileUrl.equals(p.getPacFileUrl()) && mPort == p.mPort; - } - if (!Uri.EMPTY.equals(p.mPacFileUrl)) { - return false; - } - if (mExclusionList != null && !mExclusionList.equals(p.getExclusionListAsString())) { - return false; - } - if (mHost != null && p.getHost() != null && mHost.equals(p.getHost()) == false) { - return false; - } - if (mHost != null && p.mHost == null) return false; - if (mHost == null && p.mHost != null) return false; - if (mPort != p.mPort) return false; - return true; - } - - /** - * Implement the Parcelable interface - * @hide - */ - public int describeContents() { - return 0; - } - - @Override - /* - * generate hashcode based on significant fields - */ - public int hashCode() { - return ((null == mHost) ? 0 : mHost.hashCode()) - + ((null == mExclusionList) ? 0 : mExclusionList.hashCode()) - + mPort; - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public void writeToParcel(Parcel dest, int flags) { - if (!Uri.EMPTY.equals(mPacFileUrl)) { - dest.writeByte((byte)1); - mPacFileUrl.writeToParcel(dest, 0); - dest.writeInt(mPort); - return; - } else { - dest.writeByte((byte)0); - } - if (mHost != null) { - dest.writeByte((byte)1); - dest.writeString(mHost); - dest.writeInt(mPort); - } else { - dest.writeByte((byte)0); - } - dest.writeString(mExclusionList); - dest.writeStringArray(mParsedExclusionList); - } - - /** - * Implement the Parcelable interface. - * @hide - */ - public static final Creator CREATOR = - new Creator() { - public ProxyInfo createFromParcel(Parcel in) { - String host = null; - int port = 0; - if (in.readByte() != 0) { - Uri url = Uri.CREATOR.createFromParcel(in); - int localPort = in.readInt(); - return new ProxyInfo(url, localPort); - } - if (in.readByte() != 0) { - host = in.readString(); - port = in.readInt(); - } - String exclList = in.readString(); - String[] parsedExclList = in.readStringArray(); - ProxyInfo proxyProperties = - new ProxyInfo(host, port, exclList, parsedExclList); - return proxyProperties; - } - - public ProxyInfo[] newArray(int size) { - return new ProxyInfo[size]; - } - }; -} diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java deleted file mode 100644 index 8b42bcd5cb..0000000000 --- a/core/java/android/net/RouteInfo.java +++ /dev/null @@ -1,453 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.net.UnknownHostException; -import java.net.InetAddress; -import java.net.Inet4Address; -import java.net.Inet6Address; - -import java.util.Collection; -import java.util.Objects; - -/** - * Represents a network route. - *

- * This is used both to describe static network configuration and live network - * configuration information. - * - * A route contains three pieces of information: - *

    - *
  • 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} indicating the next hop to use. 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 { - /** - * The IP destination address for this route. - * TODO: Make this an IpPrefix. - */ - private final LinkAddress mDestination; - - /** - * The gateway address for this route. - */ - private final InetAddress mGateway; - - /** - * The interface for this route. - */ - private final String mInterface; - - private final boolean mIsDefault; - private final boolean mIsHost; - private final boolean mHasGateway; - - /** - * 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 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 - * - * 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) { - if (gateway != null) { - if (gateway instanceof Inet4Address) { - destination = new LinkAddress(Inet4Address.ANY, 0); - } else { - destination = new LinkAddress(Inet6Address.ANY, 0); - } - } else { - // no destination, no gateway. invalid. - throw new IllegalArgumentException("Invalid arguments passed in: " + gateway + "," + - destination); - } - } - if (gateway == null) { - if (destination.getAddress() instanceof Inet4Address) { - gateway = Inet4Address.ANY; - } else { - gateway = Inet6Address.ANY; - } - } - mHasGateway = (!gateway.isAnyLocalAddress()); - - mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(), - destination.getPrefixLength()), destination.getPrefixLength()); - 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(); - 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 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); - } - - /** - * Constructs a default {@code RouteInfo} object. - * - * @param gateway the {@link InetAddress} to route packets through - * - * @hide - */ - public RouteInfo(InetAddress gateway) { - this((LinkAddress) null, gateway, null); - } - - /** - * Constructs a {@code RouteInfo} object representing a direct connected subnet. - * - * @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); - } - - /** - * @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; - - if (host instanceof Inet4Address) { - return new RouteInfo(new LinkAddress(host, 32), gateway, iface); - } else { - return new RouteInfo(new LinkAddress(host, 128), gateway, iface); - } - } - - private boolean isHost() { - return (mDestination.getAddress() instanceof Inet4Address && - mDestination.getPrefixLength() == 32) || - (mDestination.getAddress() instanceof Inet6Address && - mDestination.getPrefixLength() == 128); - } - - private boolean isDefault() { - boolean val = false; - if (mGateway != null) { - if (mGateway instanceof Inet4Address) { - val = (mDestination == null || mDestination.getPrefixLength() == 0); - } else { - val = (mDestination == null || mDestination.getPrefixLength() == 0); - } - } - return val; - } - - /** - * Retrieves the destination address and prefix length in the form of an {@link IpPrefix}. - * - * @return {@link IpPrefix} specifying the destination. This is never {@code null}. - */ - 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; - } - - /** - * Retrieves the gateway or next hop {@link InetAddress} for this route. - * - * @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 specified, else {@code null}. - * - * @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 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 or 128 for IPv4 or IPv6, - * respectively. - * @hide - */ - 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 - * @hide - */ - public boolean hasGateway() { - return mHasGateway; - } - - /** - * 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. - */ - public boolean matches(InetAddress destination) { - if (destination == null) return false; - - // match the route destination and destination with prefix length - InetAddress dstNet = NetworkUtils.getNetworkPart(destination, - mDestination.getPrefixLength()); - - 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.getPrefixLength() >= - route.mDestination.getPrefixLength())) { - continue; - } - if (route.matches(dest)) bestRoute = route; - } - } - return bestRoute; - } - - /** - * Returns a human-readable description of this object. - */ - public String toString() { - String val = ""; - if (mDestination != null) val = mDestination.toString(); - 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; - - if (!(obj instanceof RouteInfo)) return false; - - RouteInfo target = (RouteInfo) obj; - - return Objects.equals(mDestination, target.getDestinationLinkAddress()) && - Objects.equals(mGateway, target.getGateway()) && - 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) - + (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.getPrefixLength()); - } - - 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) { - InetAddress destAddr = null; - int prefix = 0; - InetAddress gateway = null; - - if (in.readByte() == 1) { - byte[] addr = in.createByteArray(); - prefix = in.readInt(); - - try { - destAddr = InetAddress.getByAddress(addr); - } catch (UnknownHostException e) {} - } - - if (in.readByte() == 1) { - byte[] addr = in.createByteArray(); - - try { - gateway = InetAddress.getByAddress(addr); - } catch (UnknownHostException e) {} - } - - String iface = in.readString(); - - LinkAddress dest = null; - - if (destAddr != null) { - dest = new LinkAddress(destAddr, prefix); - } - - return new RouteInfo(dest, gateway, iface); - } - - public RouteInfo[] newArray(int size) { - return new RouteInfo[size]; - } - }; -} diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp deleted file mode 100644 index bc5e1b3237..0000000000 --- a/core/jni/android_net_NetUtils.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright 2008, The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "NetUtils" - -#include "jni.h" -#include "JNIHelp.h" -#include "NetdClient.h" -#include "resolv_netid.h" -#include -#include -#include -#include -#include - -extern "C" { -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 * const ifname, - const char *ipaddr, - const char *gateway, - uint32_t *prefixLength, - const char *dns[], - const char *server, - uint32_t *lease, - const char *vendorInfo, - const char *domains, - const char *mtu); - -int dhcp_do_request_renew(const char * const ifname, - const char *ipaddr, - const char *gateway, - uint32_t *prefixLength, - const char *dns[], - const char *server, - uint32_t *lease, - const char *vendorInfo, - const char *domains, - const char *mtu); - -int dhcp_stop(const char *ifname); -int dhcp_release_lease(const char *ifname); -char *dhcp_get_errmsg(); -} - -#define NETUTILS_PKG_NAME "android/net/NetworkUtils" - -namespace android { - -/* - * The following remembers the jfieldID's of the fields - * of the DhcpInfo Java object, so that we don't have - * to look them up every time. - */ -static struct fieldIds { - jmethodID clear; - jmethodID setInterfaceName; - jmethodID addLinkAddress; - jmethodID addGateway; - jmethodID addDns; - jmethodID setDomains; - jmethodID setServerAddress; - jmethodID setLeaseDuration; - jmethodID setVendorInfo; -} dhcpResultsFieldIds; - -static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname) -{ - int result; - - const char *nameStr = env->GetStringUTFChars(ifname, NULL); - result = ::ifc_enable(nameStr); - env->ReleaseStringUTFChars(ifname, nameStr); - return (jint)result; -} - -static jint android_net_utils_disableInterface(JNIEnv* env, jobject clazz, jstring ifname) -{ - int result; - - const char *nameStr = env->GetStringUTFChars(ifname, NULL); - result = ::ifc_disable(nameStr); - env->ReleaseStringUTFChars(ifname, nameStr); - return (jint)result; -} - -static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, - jstring ifname, jint mask) -{ - int result; - - const char *nameStr = env->GetStringUTFChars(ifname, NULL); - - ALOGD("android_net_utils_resetConnections in env=%p clazz=%p iface=%s mask=0x%x\n", - env, clazz, nameStr, mask); - - result = ::ifc_reset_connections(nameStr, mask); - env->ReleaseStringUTFChars(ifname, nameStr); - return (jint)result; -} - -static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname, - jobject dhcpResults, bool renew) -{ - int result; - char ipaddr[PROPERTY_VALUE_MAX]; - uint32_t prefixLength; - char gateway[PROPERTY_VALUE_MAX]; - char dns1[PROPERTY_VALUE_MAX]; - char dns2[PROPERTY_VALUE_MAX]; - char dns3[PROPERTY_VALUE_MAX]; - char dns4[PROPERTY_VALUE_MAX]; - const char *dns[5] = {dns1, dns2, dns3, dns4, NULL}; - char server[PROPERTY_VALUE_MAX]; - uint32_t lease; - char vendorInfo[PROPERTY_VALUE_MAX]; - char domains[PROPERTY_VALUE_MAX]; - char mtu[PROPERTY_VALUE_MAX]; - - const char *nameStr = env->GetStringUTFChars(ifname, NULL); - if (nameStr == NULL) return (jboolean)false; - - if (renew) { - result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength, - dns, server, &lease, vendorInfo, domains, mtu); - } else { - result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength, - dns, server, &lease, vendorInfo, domains, mtu); - } - if (result != 0) { - ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new"); - } - - env->ReleaseStringUTFChars(ifname, nameStr); - if (result == 0) { - 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 - // dhcpResults->addGateway(gateway) - result = env->CallBooleanMethod(dhcpResults, - dhcpResultsFieldIds.addGateway, env->NewStringUTF(gateway)); - } - - if (result == 0) { - // dhcpResults->addDns(new InetAddress(dns1)) - result = env->CallBooleanMethod(dhcpResults, - dhcpResultsFieldIds.addDns, env->NewStringUTF(dns1)); - } - - if (result == 0) { - env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setDomains, - env->NewStringUTF(domains)); - - result = env->CallBooleanMethod(dhcpResults, - dhcpResultsFieldIds.addDns, env->NewStringUTF(dns2)); - - if (result == 0) { - result = env->CallBooleanMethod(dhcpResults, - dhcpResultsFieldIds.addDns, env->NewStringUTF(dns3)); - if (result == 0) { - result = env->CallBooleanMethod(dhcpResults, - dhcpResultsFieldIds.addDns, env->NewStringUTF(dns4)); - } - } - } - - if (result == 0) { - // dhcpResults->setServerAddress(new InetAddress(server)) - result = env->CallBooleanMethod(dhcpResults, dhcpResultsFieldIds.setServerAddress, - env->NewStringUTF(server)); - } - - if (result == 0) { - // dhcpResults->setLeaseDuration(lease) - env->CallVoidMethod(dhcpResults, - dhcpResultsFieldIds.setLeaseDuration, lease); - - // dhcpResults->setVendorInfo(vendorInfo) - env->CallVoidMethod(dhcpResults, dhcpResultsFieldIds.setVendorInfo, - env->NewStringUTF(vendorInfo)); - } - return (jboolean)(result == 0); -} - - -static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info) -{ - return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false); -} - -static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info) -{ - return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true); -} - - -static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname) -{ - int result; - - const char *nameStr = env->GetStringUTFChars(ifname, NULL); - result = ::dhcp_stop(nameStr); - env->ReleaseStringUTFChars(ifname, nameStr); - return (jboolean)(result == 0); -} - -static jboolean android_net_utils_releaseDhcpLease(JNIEnv* env, jobject clazz, jstring ifname) -{ - int result; - - const char *nameStr = env->GetStringUTFChars(ifname, NULL); - result = ::dhcp_release_lease(nameStr); - env->ReleaseStringUTFChars(ifname, nameStr); - return (jboolean)(result == 0); -} - -static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz) -{ - return env->NewStringUTF(::dhcp_get_errmsg()); -} - -static void android_net_utils_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"); - } -} - -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); -} - -// ---------------------------------------------------------------------------- - -/* - * JNI registration. - */ -static JNINativeMethod gNetworkUtilMethods[] = { - /* name, signature, funcPtr */ - - { "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/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 }, - { "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) -{ - 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.setDomains = - env->GetMethodID(dhcpResultsClass, "setDomains", "(Ljava/lang/String;)V"); - 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)); -} - -}; // namespace android diff --git a/core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical b/core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical deleted file mode 100644 index 656d5bb82d..0000000000 --- a/core/tests/coretests/res/raw/xt_qtaguid_iface_fmt_typical +++ /dev/null @@ -1,4 +0,0 @@ -ifname total_skb_rx_bytes total_skb_rx_packets total_skb_tx_bytes total_skb_tx_packets -rmnet2 4968 35 3081 39 -rmnet1 11153922 8051 190226 2468 -rmnet0 6824 16 5692 10 diff --git a/core/tests/coretests/res/raw/xt_qtaguid_iface_typical b/core/tests/coretests/res/raw/xt_qtaguid_iface_typical deleted file mode 100644 index 610723aef2..0000000000 --- a/core/tests/coretests/res/raw/xt_qtaguid_iface_typical +++ /dev/null @@ -1,6 +0,0 @@ -rmnet3 1 0 0 0 0 20822 501 1149991 815 -rmnet2 1 0 0 0 0 1594 15 1313 15 -rmnet1 1 0 0 0 0 207398 458 166918 565 -rmnet0 1 0 0 0 0 2112 24 700 10 -test1 1 1 2 3 4 5 6 7 8 -test2 0 1 2 3 4 5 6 7 8 diff --git a/core/tests/coretests/res/raw/xt_qtaguid_typical b/core/tests/coretests/res/raw/xt_qtaguid_typical deleted file mode 100644 index c1b0d25995..0000000000 --- a/core/tests/coretests/res/raw/xt_qtaguid_typical +++ /dev/null @@ -1,71 +0,0 @@ -idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets -2 wlan0 0x0 0 0 18621 96 2898 44 312 6 15897 58 2412 32 312 6 1010 16 1576 22 -3 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -4 wlan0 0x0 1000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -5 wlan0 0x0 1000 1 1949 13 1078 14 0 0 1600 10 349 3 0 0 600 10 478 4 -6 wlan0 0x0 10005 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -7 wlan0 0x0 10005 1 32081 38 5315 50 32081 38 0 0 0 0 5315 50 0 0 0 0 -8 wlan0 0x0 10011 0 35777 53 5718 57 0 0 0 0 35777 53 0 0 0 0 5718 57 -9 wlan0 0x0 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -10 wlan0 0x0 10014 0 0 0 1098 13 0 0 0 0 0 0 0 0 0 0 1098 13 -11 wlan0 0x0 10014 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -12 wlan0 0x0 10021 0 562386 573 49228 549 0 0 0 0 562386 573 0 0 0 0 49228 549 -13 wlan0 0x0 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -14 wlan0 0x0 10031 0 3425 5 586 6 0 0 0 0 3425 5 0 0 0 0 586 6 -15 wlan0 0x0 10031 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -16 wlan0 0x7fffff0100000000 10021 0 562386 573 49228 549 0 0 0 0 562386 573 0 0 0 0 49228 549 -17 wlan0 0x7fffff0100000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -18 wlan0 0x7fffff0100000000 10031 0 3425 5 586 6 0 0 0 0 3425 5 0 0 0 0 586 6 -19 wlan0 0x7fffff0100000000 10031 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -20 rmnet2 0x0 0 0 547 5 118 2 40 1 243 1 264 3 0 0 62 1 56 1 -21 rmnet2 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -22 rmnet2 0x0 10001 0 1125899906842624 5 984 11 632 5 0 0 0 0 984 11 0 0 0 0 -23 rmnet2 0x0 10001 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -24 rmnet1 0x0 0 0 26736 174 7098 130 7210 97 18382 64 1144 13 2932 64 4054 64 112 2 -25 rmnet1 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -26 rmnet1 0x0 1000 0 75774 77 18038 78 75335 72 439 5 0 0 17668 73 370 5 0 0 -27 rmnet1 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -28 rmnet1 0x0 10007 0 269945 578 111632 586 269945 578 0 0 0 0 111632 586 0 0 0 0 -29 rmnet1 0x0 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -30 rmnet1 0x0 10011 0 1741256 6918 769778 7019 1741256 6918 0 0 0 0 769778 7019 0 0 0 0 -31 rmnet1 0x0 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -32 rmnet1 0x0 10014 0 0 0 786 12 0 0 0 0 0 0 786 12 0 0 0 0 -33 rmnet1 0x0 10014 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -34 rmnet1 0x0 10021 0 433533 1454 393420 1604 433533 1454 0 0 0 0 393420 1604 0 0 0 0 -35 rmnet1 0x0 10021 1 21215 33 10278 33 21215 33 0 0 0 0 10278 33 0 0 0 0 -36 rmnet1 0x0 10036 0 6310 25 3284 29 6310 25 0 0 0 0 3284 29 0 0 0 0 -37 rmnet1 0x0 10036 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -38 rmnet1 0x0 10047 0 34264 47 3936 34 34264 47 0 0 0 0 3936 34 0 0 0 0 -39 rmnet1 0x0 10047 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -40 rmnet1 0x4e7700000000 10011 0 9187 27 4248 33 9187 27 0 0 0 0 4248 33 0 0 0 0 -41 rmnet1 0x4e7700000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -42 rmnet1 0x1000000000000000 10007 0 2109 4 791 4 2109 4 0 0 0 0 791 4 0 0 0 0 -43 rmnet1 0x1000000000000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -44 rmnet1 0x1000000400000000 10007 0 9811 22 6286 22 9811 22 0 0 0 0 6286 22 0 0 0 0 -45 rmnet1 0x1000000400000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -46 rmnet1 0x1010000000000000 10021 0 164833 426 135392 527 164833 426 0 0 0 0 135392 527 0 0 0 0 -47 rmnet1 0x1010000000000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -48 rmnet1 0x1144000400000000 10011 0 10112 18 3334 17 10112 18 0 0 0 0 3334 17 0 0 0 0 -49 rmnet1 0x1144000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -50 rmnet1 0x1244000400000000 10011 0 1300 3 848 2 1300 3 0 0 0 0 848 2 0 0 0 0 -51 rmnet1 0x1244000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -52 rmnet1 0x3000000000000000 10007 0 10389 14 1521 12 10389 14 0 0 0 0 1521 12 0 0 0 0 -53 rmnet1 0x3000000000000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -54 rmnet1 0x3000000400000000 10007 0 238070 380 93938 404 238070 380 0 0 0 0 93938 404 0 0 0 0 -55 rmnet1 0x3000000400000000 10007 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -56 rmnet1 0x3010000000000000 10021 0 219110 578 227423 676 219110 578 0 0 0 0 227423 676 0 0 0 0 -57 rmnet1 0x3010000000000000 10021 1 742 3 1265 3 742 3 0 0 0 0 1265 3 0 0 0 0 -58 rmnet1 0x3020000000000000 10021 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -59 rmnet1 0x3020000000000000 10021 1 20473 30 9013 30 20473 30 0 0 0 0 9013 30 0 0 0 0 -60 rmnet1 0x3144000400000000 10011 0 43963 92 34414 116 43963 92 0 0 0 0 34414 116 0 0 0 0 -61 rmnet1 0x3144000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -62 rmnet1 0x3244000400000000 10011 0 3486 8 1520 9 3486 8 0 0 0 0 1520 9 0 0 0 0 -63 rmnet1 0x3244000400000000 10011 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -64 rmnet1 0x7fffff0100000000 10021 0 29102 56 8865 60 29102 56 0 0 0 0 8865 60 0 0 0 0 -65 rmnet1 0x7fffff0100000000 10021 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -66 rmnet1 0x7fffff0300000000 1000 0 995 13 14145 14 995 13 0 0 0 0 14145 14 0 0 0 0 -67 rmnet1 0x7fffff0300000000 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -68 rmnet0 0x0 0 0 4312 49 1288 23 0 0 0 0 4312 49 0 0 0 0 1288 23 -69 rmnet0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -70 rmnet0 0x0 10080 0 22266 30 20976 30 0 0 0 0 22266 30 0 0 0 0 20976 30 -71 rmnet0 0x0 10080 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/core/tests/coretests/src/android/net/LinkAddressTest.java b/core/tests/coretests/src/android/net/LinkAddressTest.java deleted file mode 100644 index 814ecdd95b..0000000000 --- a/core/tests/coretests/src/android/net/LinkAddressTest.java +++ /dev/null @@ -1,331 +0,0 @@ -/* - * 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.Arrays; -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; - -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}. - */ -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.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.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.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.getPrefixLength()); - 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(); - - // 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.getPrefixLength()); - - assertEquals(NetworkUtils.numericToInetAddress("::1"), ipv6Loopback.getAddress()); - assertEquals(128, ipv6Loopback.getPrefixLength()); - - // 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, IFA_F_PERMANENT, RT_SCOPE_UNIVERSE); - 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_ADDRESS, -1); - fail("Negative IPv4 prefix length should cause IllegalArgumentException"); - } catch(IllegalArgumentException expected) {} - - try { - address = new LinkAddress(V6_ADDRESS, -1); - fail("Negative IPv6 prefix length should cause IllegalArgumentException"); - } catch(IllegalArgumentException expected) {} - - try { - address = new LinkAddress(V4_ADDRESS, 33); - fail("/33 IPv4 prefix length should cause IllegalArgumentException"); - } catch(IllegalArgumentException expected) {} - - try { - 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) { - 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 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("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. - String addressString = V4 + "/24"; - l1 = new LinkAddress(addressString); - l2 = new LinkAddress("::ffff:" + addressString); - assertLinkAddressesEqual(l1, l2); - assertIsSameAddressAs(l1, l2); - } - - public void testHashCode() { - LinkAddress l; - - 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()); - - l = new LinkAddress(V6_ADDRESS, 64); - assertEquals(1076522926, l.hashCode()); - - 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) { - 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, 123, 456); - assertParcelingIsLossless(l); - - 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 deleted file mode 100644 index e649baa070..0000000000 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ /dev/null @@ -1,440 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package 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; - -public class LinkPropertiesTest extends TestCase { - 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 int MTU = 1500; - - 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)); - 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)); - - assertTrue(source.isIdenticalMtu(target)); - assertTrue(target.isIdenticalMtu(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); - assertLinkPropertiesEqual(source, target); - } - - @SmallTest - public void testEqualsSameOrder() { - try { - LinkProperties source = new LinkProperties(); - source.setInterfaceName(NAME); - // set 2 link addresses - source.addLinkAddress(LINKADDRV4); - source.addLinkAddress(LINKADDRV6); - // set 2 dnses - source.addDnsServer(DNS1); - source.addDnsServer(DNS2); - // set 2 gateways - source.addRoute(new RouteInfo(GATEWAY1)); - source.addRoute(new RouteInfo(GATEWAY2)); - source.setMtu(MTU); - - LinkProperties target = new LinkProperties(); - - // All fields are same - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - - assertLinkPropertiesEqual(source, target); - - target.clear(); - // change Interface Name - target.setInterfaceName("qmi1"); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - assertFalse(source.equals(target)); - - target.clear(); - target.setInterfaceName(NAME); - // change link addresses - target.addLinkAddress(new LinkAddress( - NetworkUtils.numericToInetAddress("75.208.6.2"), 32)); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - assertFalse(source.equals(target)); - - target.clear(); - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - // change dnses - target.addDnsServer(NetworkUtils.numericToInetAddress("75.208.7.2")); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - assertFalse(source.equals(target)); - - target.clear(); - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - // change gateway - target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2"))); - target.addRoute(new RouteInfo(GATEWAY2)); - target.setMtu(MTU); - assertFalse(source.equals(target)); - - target.clear(); - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addDnsServer(DNS1); - target.addDnsServer(DNS2); - target.addRoute(new RouteInfo(GATEWAY1)); - target.addRoute(new RouteInfo(GATEWAY2)); - // change mtu - target.setMtu(1440); - assertFalse(source.equals(target)); - - } catch (Exception e) { - throw new RuntimeException(e.toString()); - //fail(); - } - } - - @SmallTest - public void testEqualsDifferentOrder() { - try { - LinkProperties source = new LinkProperties(); - source.setInterfaceName(NAME); - // set 2 link addresses - source.addLinkAddress(LINKADDRV4); - source.addLinkAddress(LINKADDRV6); - // set 2 dnses - source.addDnsServer(DNS1); - source.addDnsServer(DNS2); - // set 2 gateways - source.addRoute(new RouteInfo(GATEWAY1)); - source.addRoute(new RouteInfo(GATEWAY2)); - source.setMtu(MTU); - - LinkProperties target = new LinkProperties(); - // Exchange order - target.setInterfaceName(NAME); - target.addLinkAddress(LINKADDRV6); - target.addLinkAddress(LINKADDRV4); - target.addDnsServer(DNS2); - target.addDnsServer(DNS1); - target.addRoute(new RouteInfo(GATEWAY2)); - target.addRoute(new RouteInfo(GATEWAY1)); - target.setMtu(MTU); - - assertLinkPropertiesEqual(source, target); - } catch (Exception e) { - fail(); - } - } - - @SmallTest - public void testEqualsDuplicated() { - try { - LinkProperties source = new LinkProperties(); - // set 3 link addresses, eg, [A, A, B] - source.addLinkAddress(LINKADDRV4); - source.addLinkAddress(LINKADDRV4); - source.addLinkAddress(LINKADDRV6); - - LinkProperties target = new LinkProperties(); - // set 3 link addresses, eg, [A, B, B] - target.addLinkAddress(LINKADDRV4); - target.addLinkAddress(LINKADDRV6); - target.addLinkAddress(LINKADDRV6); - - assertLinkPropertiesEqual(source, target); - } catch (Exception e) { - fail(); - } - } - - 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 = 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(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.compareAllRoutes(lp2).added.size()); - assertEquals(0, lp.compareAllRoutes(lp2).removed.size()); - - lp2.setInterfaceName("p2p0"); - assertAllRoutesHaveInterface("p2p0", lp2); - 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(LINKADDRV6); - - LinkProperties clat4 = new LinkProperties(); - clat4.setInterfaceName("clat4"); - clat4.addLinkAddress(LINKADDRV4); - - 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. - for (LinkProperties link : rmnet0.getStackedLinks()) { - if (link.getInterfaceName().equals("clat4")) { - link.setInterfaceName("newname"); - } - } - 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)); - } - - private LinkAddress getFirstLinkAddress(LinkProperties lp) { - return lp.getLinkAddresses().iterator().next(); - } - - @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. - 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 - 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)); - } -} diff --git a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java b/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java deleted file mode 100644 index b1811225a2..0000000000 --- a/core/tests/coretests/src/android/net/NetworkStatsHistoryTest.java +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.net.NetworkStatsHistory.FIELD_ALL; -import static android.net.NetworkStatsHistory.FIELD_OPERATIONS; -import static android.net.NetworkStatsHistory.FIELD_RX_BYTES; -import static android.net.NetworkStatsHistory.FIELD_RX_PACKETS; -import static android.net.NetworkStatsHistory.FIELD_TX_BYTES; -import static android.net.NetworkStatsHistory.DataStreamUtils.readVarLong; -import static android.net.NetworkStatsHistory.DataStreamUtils.writeVarLong; -import static android.net.NetworkStatsHistory.Entry.UNKNOWN; -import static android.net.TrafficStats.GB_IN_BYTES; -import static android.net.TrafficStats.MB_IN_BYTES; -import static android.text.format.DateUtils.DAY_IN_MILLIS; -import static android.text.format.DateUtils.HOUR_IN_MILLIS; -import static android.text.format.DateUtils.MINUTE_IN_MILLIS; -import static android.text.format.DateUtils.SECOND_IN_MILLIS; -import static android.text.format.DateUtils.WEEK_IN_MILLIS; -import static android.text.format.DateUtils.YEAR_IN_MILLIS; - -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; -import android.test.suitebuilder.annotation.Suppress; -import android.util.Log; - -import com.android.frameworks.coretests.R; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.util.Random; - -@SmallTest -public class NetworkStatsHistoryTest extends AndroidTestCase { - private static final String TAG = "NetworkStatsHistoryTest"; - - private static final long TEST_START = 1194220800000L; - - private NetworkStatsHistory stats; - - @Override - protected void tearDown() throws Exception { - super.tearDown(); - if (stats != null) { - assertConsistent(stats); - } - } - - public void testReadOriginalVersion() throws Exception { - final DataInputStream in = new DataInputStream( - getContext().getResources().openRawResource(R.raw.history_v1)); - - NetworkStatsHistory.Entry entry = null; - try { - final NetworkStatsHistory history = new NetworkStatsHistory(in); - assertEquals(15 * SECOND_IN_MILLIS, history.getBucketDuration()); - - entry = history.getValues(0, entry); - assertEquals(29143L, entry.rxBytes); - assertEquals(6223L, entry.txBytes); - - entry = history.getValues(history.size() - 1, entry); - assertEquals(1476L, entry.rxBytes); - assertEquals(838L, entry.txBytes); - - entry = history.getValues(Long.MIN_VALUE, Long.MAX_VALUE, entry); - assertEquals(332401L, entry.rxBytes); - assertEquals(64314L, entry.txBytes); - - } finally { - in.close(); - } - } - - public void testRecordSingleBucket() throws Exception { - final long BUCKET_SIZE = HOUR_IN_MILLIS; - stats = new NetworkStatsHistory(BUCKET_SIZE); - - // record data into narrow window to get single bucket - stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, - new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L)); - - assertEquals(1, stats.size()); - assertValues(stats, 0, SECOND_IN_MILLIS, 1024L, 10L, 2048L, 20L, 2L); - } - - public void testRecordEqualBuckets() throws Exception { - final long bucketDuration = HOUR_IN_MILLIS; - stats = new NetworkStatsHistory(bucketDuration); - - // split equally across two buckets - final long recordStart = TEST_START + (bucketDuration / 2); - stats.recordData(recordStart, recordStart + bucketDuration, - new NetworkStats.Entry(1024L, 10L, 128L, 2L, 2L)); - - assertEquals(2, stats.size()); - assertValues(stats, 0, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L); - assertValues(stats, 1, HOUR_IN_MILLIS / 2, 512L, 5L, 64L, 1L, 1L); - } - - public void testRecordTouchingBuckets() throws Exception { - final long BUCKET_SIZE = 15 * MINUTE_IN_MILLIS; - stats = new NetworkStatsHistory(BUCKET_SIZE); - - // split almost completely into middle bucket, but with a few minutes - // overlap into neighboring buckets. total record is 20 minutes. - final long recordStart = (TEST_START + BUCKET_SIZE) - MINUTE_IN_MILLIS; - final long recordEnd = (TEST_START + (BUCKET_SIZE * 2)) + (MINUTE_IN_MILLIS * 4); - stats.recordData(recordStart, recordEnd, - new NetworkStats.Entry(1000L, 2000L, 5000L, 10000L, 100L)); - - assertEquals(3, stats.size()); - // first bucket should have (1/20 of value) - assertValues(stats, 0, MINUTE_IN_MILLIS, 50L, 100L, 250L, 500L, 5L); - // second bucket should have (15/20 of value) - assertValues(stats, 1, 15 * MINUTE_IN_MILLIS, 750L, 1500L, 3750L, 7500L, 75L); - // final bucket should have (4/20 of value) - assertValues(stats, 2, 4 * MINUTE_IN_MILLIS, 200L, 400L, 1000L, 2000L, 20L); - } - - public void testRecordGapBuckets() throws Exception { - final long BUCKET_SIZE = HOUR_IN_MILLIS; - stats = new NetworkStatsHistory(BUCKET_SIZE); - - // record some data today and next week with large gap - final long firstStart = TEST_START; - final long lastStart = TEST_START + WEEK_IN_MILLIS; - stats.recordData(firstStart, firstStart + SECOND_IN_MILLIS, - new NetworkStats.Entry(128L, 2L, 256L, 4L, 1L)); - stats.recordData(lastStart, lastStart + SECOND_IN_MILLIS, - new NetworkStats.Entry(64L, 1L, 512L, 8L, 2L)); - - // we should have two buckets, far apart from each other - assertEquals(2, stats.size()); - assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L); - assertValues(stats, 1, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L); - - // now record something in middle, spread across two buckets - final long middleStart = TEST_START + DAY_IN_MILLIS; - final long middleEnd = middleStart + (HOUR_IN_MILLIS * 2); - stats.recordData(middleStart, middleEnd, - new NetworkStats.Entry(2048L, 4L, 2048L, 4L, 2L)); - - // now should have four buckets, with new record in middle two buckets - assertEquals(4, stats.size()); - assertValues(stats, 0, SECOND_IN_MILLIS, 128L, 2L, 256L, 4L, 1L); - assertValues(stats, 1, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L); - assertValues(stats, 2, HOUR_IN_MILLIS, 1024L, 2L, 1024L, 2L, 1L); - assertValues(stats, 3, SECOND_IN_MILLIS, 64L, 1L, 512L, 8L, 2L); - } - - public void testRecordOverlapBuckets() throws Exception { - final long BUCKET_SIZE = HOUR_IN_MILLIS; - stats = new NetworkStatsHistory(BUCKET_SIZE); - - // record some data in one bucket, and another overlapping buckets - stats.recordData(TEST_START, TEST_START + SECOND_IN_MILLIS, - new NetworkStats.Entry(256L, 2L, 256L, 2L, 1L)); - final long midStart = TEST_START + (HOUR_IN_MILLIS / 2); - stats.recordData(midStart, midStart + HOUR_IN_MILLIS, - new NetworkStats.Entry(1024L, 10L, 1024L, 10L, 10L)); - - // should have two buckets, with some data mixed together - assertEquals(2, stats.size()); - assertValues(stats, 0, SECOND_IN_MILLIS + (HOUR_IN_MILLIS / 2), 768L, 7L, 768L, 7L, 6L); - assertValues(stats, 1, (HOUR_IN_MILLIS / 2), 512L, 5L, 512L, 5L, 5L); - } - - public void testRecordEntireGapIdentical() throws Exception { - // first, create two separate histories far apart - final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); - stats1.recordData(TEST_START, TEST_START + 2 * HOUR_IN_MILLIS, 2000L, 1000L); - - final long TEST_START_2 = TEST_START + DAY_IN_MILLIS; - final NetworkStatsHistory stats2 = new NetworkStatsHistory(HOUR_IN_MILLIS); - stats2.recordData(TEST_START_2, TEST_START_2 + 2 * HOUR_IN_MILLIS, 1000L, 500L); - - // combine together with identical bucket size - stats = new NetworkStatsHistory(HOUR_IN_MILLIS); - stats.recordEntireHistory(stats1); - stats.recordEntireHistory(stats2); - - // first verify that totals match up - assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 3000L, 1500L); - - // now inspect internal buckets - assertValues(stats, 0, 1000L, 500L); - assertValues(stats, 1, 1000L, 500L); - assertValues(stats, 2, 500L, 250L); - assertValues(stats, 3, 500L, 250L); - } - - public void testRecordEntireOverlapVaryingBuckets() throws Exception { - // create history just over hour bucket boundary - final NetworkStatsHistory stats1 = new NetworkStatsHistory(HOUR_IN_MILLIS); - stats1.recordData(TEST_START, TEST_START + MINUTE_IN_MILLIS * 60, 600L, 600L); - - final long TEST_START_2 = TEST_START + MINUTE_IN_MILLIS; - final NetworkStatsHistory stats2 = new NetworkStatsHistory(MINUTE_IN_MILLIS); - stats2.recordData(TEST_START_2, TEST_START_2 + MINUTE_IN_MILLIS * 5, 50L, 50L); - - // combine together with minute bucket size - stats = new NetworkStatsHistory(MINUTE_IN_MILLIS); - stats.recordEntireHistory(stats1); - stats.recordEntireHistory(stats2); - - // first verify that totals match up - assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); - - // now inspect internal buckets - assertValues(stats, 0, 10L, 10L); - assertValues(stats, 1, 20L, 20L); - assertValues(stats, 2, 20L, 20L); - assertValues(stats, 3, 20L, 20L); - assertValues(stats, 4, 20L, 20L); - assertValues(stats, 5, 20L, 20L); - assertValues(stats, 6, 10L, 10L); - - // now combine using 15min buckets - stats = new NetworkStatsHistory(HOUR_IN_MILLIS / 4); - stats.recordEntireHistory(stats1); - stats.recordEntireHistory(stats2); - - // first verify that totals match up - assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 650L, 650L); - - // and inspect buckets - assertValues(stats, 0, 200L, 200L); - assertValues(stats, 1, 150L, 150L); - assertValues(stats, 2, 150L, 150L); - assertValues(stats, 3, 150L, 150L); - } - - public void testRemove() throws Exception { - stats = new NetworkStatsHistory(HOUR_IN_MILLIS); - - // record some data across 24 buckets - stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 24L, 24L); - assertEquals(24, stats.size()); - - // try removing invalid data; should be no change - stats.removeBucketsBefore(0 - DAY_IN_MILLIS); - assertEquals(24, stats.size()); - - // try removing far before buckets; should be no change - stats.removeBucketsBefore(TEST_START - YEAR_IN_MILLIS); - assertEquals(24, stats.size()); - - // try removing just moments into first bucket; should be no change - // since that bucket contains data beyond the cutoff - stats.removeBucketsBefore(TEST_START + SECOND_IN_MILLIS); - assertEquals(24, stats.size()); - - // try removing single bucket - stats.removeBucketsBefore(TEST_START + HOUR_IN_MILLIS); - assertEquals(23, stats.size()); - - // try removing multiple buckets - stats.removeBucketsBefore(TEST_START + (4 * HOUR_IN_MILLIS)); - assertEquals(20, stats.size()); - - // try removing all buckets - stats.removeBucketsBefore(TEST_START + YEAR_IN_MILLIS); - assertEquals(0, stats.size()); - } - - public void testTotalData() throws Exception { - final long BUCKET_SIZE = HOUR_IN_MILLIS; - stats = new NetworkStatsHistory(BUCKET_SIZE); - - // record uniform data across day - stats.recordData(TEST_START, TEST_START + DAY_IN_MILLIS, 2400L, 4800L); - - // verify that total outside range is 0 - assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START - DAY_IN_MILLIS, 0L, 0L); - - // verify total in first hour - assertValues(stats, TEST_START, TEST_START + HOUR_IN_MILLIS, 100L, 200L); - - // verify total across 1.5 hours - assertValues(stats, TEST_START, TEST_START + (long) (1.5 * HOUR_IN_MILLIS), 150L, 300L); - - // verify total beyond end - assertValues(stats, TEST_START + (23 * HOUR_IN_MILLIS), TEST_START + WEEK_IN_MILLIS, 100L, 200L); - - // verify everything total - assertValues(stats, TEST_START - WEEK_IN_MILLIS, TEST_START + WEEK_IN_MILLIS, 2400L, 4800L); - - } - - @Suppress - public void testFuzzing() throws Exception { - try { - // fuzzing with random events, looking for crashes - final NetworkStats.Entry entry = new NetworkStats.Entry(); - final Random r = new Random(); - for (int i = 0; i < 500; i++) { - stats = new NetworkStatsHistory(r.nextLong()); - for (int j = 0; j < 10000; j++) { - if (r.nextBoolean()) { - // add range - final long start = r.nextLong(); - final long end = start + r.nextInt(); - entry.rxBytes = nextPositiveLong(r); - entry.rxPackets = nextPositiveLong(r); - entry.txBytes = nextPositiveLong(r); - entry.txPackets = nextPositiveLong(r); - entry.operations = nextPositiveLong(r); - stats.recordData(start, end, entry); - } else { - // trim something - stats.removeBucketsBefore(r.nextLong()); - } - } - assertConsistent(stats); - } - } catch (Throwable e) { - Log.e(TAG, String.valueOf(stats)); - throw new RuntimeException(e); - } - } - - private static long nextPositiveLong(Random r) { - final long value = r.nextLong(); - return value < 0 ? -value : value; - } - - public void testIgnoreFields() throws Exception { - final NetworkStatsHistory history = new NetworkStatsHistory( - MINUTE_IN_MILLIS, 0, FIELD_RX_BYTES | FIELD_TX_BYTES); - - history.recordData(0, MINUTE_IN_MILLIS, - new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L)); - history.recordData(0, 2 * MINUTE_IN_MILLIS, - new NetworkStats.Entry(2L, 2L, 2L, 2L, 2L)); - - assertFullValues(history, UNKNOWN, 1026L, UNKNOWN, 2050L, UNKNOWN, UNKNOWN); - } - - public void testIgnoreFieldsRecordIn() throws Exception { - final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL); - final NetworkStatsHistory partial = new NetworkStatsHistory( - MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS); - - full.recordData(0, MINUTE_IN_MILLIS, - new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L)); - partial.recordEntireHistory(full); - - assertFullValues(partial, UNKNOWN, UNKNOWN, 10L, UNKNOWN, UNKNOWN, 4L); - } - - public void testIgnoreFieldsRecordOut() throws Exception { - final NetworkStatsHistory full = new NetworkStatsHistory(MINUTE_IN_MILLIS, 0, FIELD_ALL); - final NetworkStatsHistory partial = new NetworkStatsHistory( - MINUTE_IN_MILLIS, 0, FIELD_RX_PACKETS | FIELD_OPERATIONS); - - partial.recordData(0, MINUTE_IN_MILLIS, - new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L)); - full.recordEntireHistory(partial); - - assertFullValues(full, MINUTE_IN_MILLIS, 0L, 10L, 0L, 0L, 4L); - } - - public void testSerialize() throws Exception { - final NetworkStatsHistory before = new NetworkStatsHistory(MINUTE_IN_MILLIS, 40, FIELD_ALL); - before.recordData(0, 4 * MINUTE_IN_MILLIS, - new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 4L)); - before.recordData(DAY_IN_MILLIS, DAY_IN_MILLIS + MINUTE_IN_MILLIS, - new NetworkStats.Entry(10L, 20L, 30L, 40L, 50L)); - - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - before.writeToStream(new DataOutputStream(out)); - out.close(); - - final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - final NetworkStatsHistory after = new NetworkStatsHistory(new DataInputStream(in)); - - // must have identical totals before and after - assertFullValues(before, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L); - assertFullValues(after, 5 * MINUTE_IN_MILLIS, 1034L, 30L, 2078L, 60L, 54L); - } - - public void testVarLong() throws Exception { - assertEquals(0L, performVarLong(0L)); - assertEquals(-1L, performVarLong(-1L)); - assertEquals(1024L, performVarLong(1024L)); - assertEquals(-1024L, performVarLong(-1024L)); - assertEquals(40 * MB_IN_BYTES, performVarLong(40 * MB_IN_BYTES)); - assertEquals(512 * GB_IN_BYTES, performVarLong(512 * GB_IN_BYTES)); - assertEquals(Long.MIN_VALUE, performVarLong(Long.MIN_VALUE)); - assertEquals(Long.MAX_VALUE, performVarLong(Long.MAX_VALUE)); - assertEquals(Long.MIN_VALUE + 40, performVarLong(Long.MIN_VALUE + 40)); - assertEquals(Long.MAX_VALUE - 40, performVarLong(Long.MAX_VALUE - 40)); - } - - public void testIndexBeforeAfter() throws Exception { - final long BUCKET_SIZE = HOUR_IN_MILLIS; - stats = new NetworkStatsHistory(BUCKET_SIZE); - - final long FIRST_START = TEST_START; - final long FIRST_END = FIRST_START + (2 * HOUR_IN_MILLIS); - final long SECOND_START = TEST_START + WEEK_IN_MILLIS; - final long SECOND_END = SECOND_START + HOUR_IN_MILLIS; - final long THIRD_START = TEST_START + (2 * WEEK_IN_MILLIS); - final long THIRD_END = THIRD_START + (2 * HOUR_IN_MILLIS); - - stats.recordData(FIRST_START, FIRST_END, - new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L)); - stats.recordData(SECOND_START, SECOND_END, - new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L)); - stats.recordData(THIRD_START, THIRD_END, - new NetworkStats.Entry(1024L, 10L, 2048L, 20L, 2L)); - - // should have buckets: 2+1+2 - assertEquals(5, stats.size()); - - assertIndexBeforeAfter(stats, 0, 0, Long.MIN_VALUE); - assertIndexBeforeAfter(stats, 0, 1, FIRST_START); - assertIndexBeforeAfter(stats, 0, 1, FIRST_START + MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 0, 2, FIRST_START + HOUR_IN_MILLIS); - assertIndexBeforeAfter(stats, 1, 2, FIRST_START + HOUR_IN_MILLIS + MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 1, 2, FIRST_END - MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 1, 2, FIRST_END); - assertIndexBeforeAfter(stats, 1, 2, FIRST_END + MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 1, 2, SECOND_START - MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 1, 3, SECOND_START); - assertIndexBeforeAfter(stats, 2, 3, SECOND_END); - assertIndexBeforeAfter(stats, 2, 3, SECOND_END + MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 2, 3, THIRD_START - MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 2, 4, THIRD_START); - assertIndexBeforeAfter(stats, 3, 4, THIRD_START + MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 3, 4, THIRD_START + HOUR_IN_MILLIS); - assertIndexBeforeAfter(stats, 4, 4, THIRD_END); - assertIndexBeforeAfter(stats, 4, 4, THIRD_END + MINUTE_IN_MILLIS); - assertIndexBeforeAfter(stats, 4, 4, Long.MAX_VALUE); - } - - private static void assertIndexBeforeAfter( - NetworkStatsHistory stats, int before, int after, long time) { - assertEquals("unexpected before", before, stats.getIndexBefore(time)); - assertEquals("unexpected after", after, stats.getIndexAfter(time)); - } - - private static long performVarLong(long before) throws Exception { - final ByteArrayOutputStream out = new ByteArrayOutputStream(); - writeVarLong(new DataOutputStream(out), before); - - final ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); - return readVarLong(new DataInputStream(in)); - } - - private static void assertConsistent(NetworkStatsHistory stats) { - // verify timestamps are monotonic - long lastStart = Long.MIN_VALUE; - NetworkStatsHistory.Entry entry = null; - for (int i = 0; i < stats.size(); i++) { - entry = stats.getValues(i, entry); - assertTrue(lastStart < entry.bucketStart); - lastStart = entry.bucketStart; - } - } - - private static void assertValues( - NetworkStatsHistory stats, int index, long rxBytes, long txBytes) { - final NetworkStatsHistory.Entry entry = stats.getValues(index, null); - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - } - - private static void assertValues( - NetworkStatsHistory stats, long start, long end, long rxBytes, long txBytes) { - final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - } - - private static void assertValues(NetworkStatsHistory stats, int index, long activeTime, - long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - final NetworkStatsHistory.Entry entry = stats.getValues(index, null); - assertEquals("unexpected activeTime", activeTime, entry.activeTime); - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - assertEquals("unexpected txPackets", txPackets, entry.txPackets); - assertEquals("unexpected operations", operations, entry.operations); - } - - private static void assertFullValues(NetworkStatsHistory stats, long activeTime, long rxBytes, - long rxPackets, long txBytes, long txPackets, long operations) { - assertValues(stats, Long.MIN_VALUE, Long.MAX_VALUE, activeTime, rxBytes, rxPackets, txBytes, - txPackets, operations); - } - - private static void assertValues(NetworkStatsHistory stats, long start, long end, - long activeTime, long rxBytes, long rxPackets, long txBytes, long txPackets, - long operations) { - final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); - assertEquals("unexpected activeTime", activeTime, entry.activeTime); - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - assertEquals("unexpected txPackets", txPackets, entry.txPackets); - assertEquals("unexpected operations", operations, entry.operations); - } -} diff --git a/core/tests/coretests/src/android/net/NetworkStatsTest.java b/core/tests/coretests/src/android/net/NetworkStatsTest.java deleted file mode 100644 index 633196433d..0000000000 --- a/core/tests/coretests/src/android/net/NetworkStatsTest.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.SET_FOREGROUND; -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; - -import android.test.suitebuilder.annotation.SmallTest; - -import com.google.android.collect.Sets; - -import junit.framework.TestCase; - -import java.util.HashSet; - -@SmallTest -public class NetworkStatsTest extends TestCase { - - private static final String TEST_IFACE = "test0"; - private static final String TEST_IFACE2 = "test2"; - private static final int TEST_UID = 1001; - private static final long TEST_START = 1194220800000L; - - public void testFindIndex() throws Exception { - final NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 12); - - assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE)); - assertEquals(2, stats.findIndex(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE)); - assertEquals(0, stats.findIndex(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE)); - assertEquals(-1, stats.findIndex(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE)); - } - - public void testFindIndexHinted() { - final NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 12) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 1024L, 8L, 0L, 0L, 10) - .addValues(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, 0L, 0L, 1024L, 8L, 11) - .addValues(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 12); - - // verify that we correctly find across regardless of hinting - for (int hint = 0; hint < stats.size(); hint++) { - assertEquals(0, stats.findIndexHinted(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, hint)); - assertEquals(1, stats.findIndexHinted(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, hint)); - assertEquals(2, stats.findIndexHinted(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, hint)); - assertEquals(3, stats.findIndexHinted(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, hint)); - assertEquals(4, stats.findIndexHinted(TEST_IFACE2, 101, SET_DEFAULT, 0xF00D, hint)); - assertEquals(5, stats.findIndexHinted(TEST_IFACE2, 102, SET_DEFAULT, TAG_NONE, hint)); - assertEquals(-1, stats.findIndexHinted(TEST_IFACE, 6, SET_DEFAULT, TAG_NONE, hint)); - } - } - - public void testAddEntryGrow() throws Exception { - final NetworkStats stats = new NetworkStats(TEST_START, 2); - - assertEquals(0, stats.size()); - assertEquals(2, stats.internalSize()); - - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 1L, 1L, 2L, 2L, 3); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 2L, 2L, 2L, 2L, 4); - - assertEquals(2, stats.size()); - assertEquals(2, stats.internalSize()); - - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 3L, 30L, 4L, 40L, 7); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 4L, 40L, 4L, 40L, 8); - stats.addValues(TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 5L, 50L, 5L, 50L, 10); - - assertEquals(5, stats.size()); - assertTrue(stats.internalSize() >= 5); - - assertValues(stats, 0, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 1L, 1L, 2L, 2L, 3); - assertValues(stats, 1, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 2L, 2L, 2L, 2L, 4); - assertValues(stats, 2, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 3L, 30L, 4L, 40L, 7); - assertValues(stats, 3, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 4L, 40L, 4L, 40L, 8); - assertValues(stats, 4, TEST_IFACE, TEST_UID, SET_DEFAULT, TAG_NONE, 5L, 50L, 5L, 50L, 10); - } - - public void testCombineExisting() throws Exception { - final NetworkStats stats = new NetworkStats(TEST_START, 10); - - stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 10); - stats.addValues(TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2); - stats.combineValues(TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, -128L, -1L, -128L, -1L, -1); - - assertValues(stats, 0, TEST_IFACE, 1001, SET_DEFAULT, TAG_NONE, 384L, 3L, 128L, 1L, 9); - assertValues(stats, 1, TEST_IFACE, 1001, SET_DEFAULT, 0xff, 128L, 1L, 128L, 1L, 2); - - // now try combining that should create row - stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3); - assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3); - stats.combineValues(TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 3); - assertValues(stats, 2, TEST_IFACE, 5005, SET_DEFAULT, TAG_NONE, 256L, 2L, 256L, 2L, 6); - } - - public void testSubtractIdenticalData() throws Exception { - final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); - - final NetworkStats after = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); - - final NetworkStats result = after.subtract(before); - - // identical data should result in zero delta - assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0); - assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0); - } - - public void testSubtractIdenticalRows() throws Exception { - final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); - - final NetworkStats after = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1025L, 9L, 2L, 1L, 15) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 1028L, 9L, 20); - - final NetworkStats result = after.subtract(before); - - // expect delta between measurements - assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1L, 1L, 2L, 1L, 4); - assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 3L, 1L, 4L, 1L, 8); - } - - public void testSubtractNewRows() throws Exception { - final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12); - - final NetworkStats after = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 1024L, 8L, 0L, 0L, 11) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 1024L, 8L, 12) - .addValues(TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); - - final NetworkStats result = after.subtract(before); - - // its okay to have new rows - assertValues(result, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0); - assertValues(result, 1, TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 0L, 0L, 0L, 0L, 0); - assertValues(result, 2, TEST_IFACE, 102, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 20); - } - - public void testSubtractMissingRows() throws Exception { - final NetworkStats before = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 1024L, 0L, 0L, 0L, 0) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2048L, 0L, 0L, 0L, 0); - - final NetworkStats after = new NetworkStats(TEST_START, 1) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 2049L, 2L, 3L, 4L, 0); - - final NetworkStats result = after.subtract(before); - - // should silently drop omitted rows - assertEquals(1, result.size()); - assertValues(result, 0, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 1L, 2L, 3L, 4L, 0); - assertEquals(4L, result.getTotalBytes()); - } - - public void testTotalBytes() throws Exception { - final NetworkStats iface = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, UID_ALL, SET_DEFAULT, TAG_NONE, 128L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 256L, 0L, 0L, 0L, 0L); - assertEquals(384L, iface.getTotalBytes()); - - final NetworkStats uidSet = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); - assertEquals(96L, uidSet.getTotalBytes()); - - final NetworkStats uidTag = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 16L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 8L, 0L, 0L, 0L, 0L); - assertEquals(64L, uidTag.getTotalBytes()); - } - - public void testGroupedByIfaceEmpty() throws Exception { - final NetworkStats uidStats = new NetworkStats(TEST_START, 3); - final NetworkStats grouped = uidStats.groupedByIface(); - - assertEquals(0, uidStats.size()); - assertEquals(0, grouped.size()); - } - - public void testGroupedByIfaceAll() throws Exception { - final NetworkStats uidStats = new NetworkStats(TEST_START, 3) - .addValues(IFACE_ALL, 100, SET_ALL, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(IFACE_ALL, 101, SET_FOREGROUND, TAG_NONE, 128L, 8L, 0L, 2L, 20L); - final NetworkStats grouped = uidStats.groupedByIface(); - - assertEquals(2, uidStats.size()); - assertEquals(1, grouped.size()); - - assertValues(grouped, 0, IFACE_ALL, UID_ALL, SET_ALL, TAG_NONE, 256L, 16L, 0L, 4L, 0L); - } - - public void testGroupedByIface() throws Exception { - final NetworkStats uidStats = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 512L, 32L, 0L, 0L, 0L) - .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 grouped = uidStats.groupedByIface(); - - assertEquals(6, uidStats.size()); - - assertEquals(2, grouped.size()); - assertValues(grouped, 0, TEST_IFACE, UID_ALL, SET_ALL, TAG_NONE, 256L, 16L, 0L, 2L, 0L); - assertValues(grouped, 1, TEST_IFACE2, UID_ALL, SET_ALL, TAG_NONE, 1024L, 64L, 0L, 0L, 0L); - } - - public void testAddAllValues() { - final NetworkStats first = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); - - final NetworkStats second = new NetworkStats(TEST_START, 2) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L); - - first.combineAllValues(second); - - assertEquals(3, first.size()); - assertValues(first, 0, TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 64L, 0L, 0L, 0L, 0L); - assertValues(first, 1, TEST_IFACE, 100, SET_FOREGROUND, TAG_NONE, 32L, 0L, 0L, 0L, 0L); - assertValues(first, 2, TEST_IFACE2, UID_ALL, SET_DEFAULT, TAG_NONE, 32L, 0L, 0L, 0L, 0L); - } - - public void testGetTotal() { - final NetworkStats stats = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 512L, 32L, 0L, 0L, 0L) - .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); - - assertValues(stats.getTotal(null), 1280L, 80L, 0L, 2L, 20L); - assertValues(stats.getTotal(null, 100), 1152L, 72L, 0L, 2L, 20L); - assertValues(stats.getTotal(null, 101), 128L, 8L, 0L, 0L, 0L); - - final HashSet ifaces = Sets.newHashSet(); - assertValues(stats.getTotal(null, ifaces), 0L, 0L, 0L, 0L, 0L); - - ifaces.add(TEST_IFACE2); - assertValues(stats.getTotal(null, ifaces), 1024L, 64L, 0L, 0L, 0L); - } - - public void testWithoutUid() throws Exception { - final NetworkStats before = new NetworkStats(TEST_START, 3) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, 0xF00D, 64L, 4L, 0L, 0L, 0L) - .addValues(TEST_IFACE2, 100, SET_FOREGROUND, TAG_NONE, 512L, 32L, 0L, 0L, 0L) - .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.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); - assertValues(after, 1, TEST_IFACE, 101, SET_DEFAULT, 0xF00D, 128L, 8L, 0L, 0L, 0L); - } - - public void testClone() throws Exception { - final NetworkStats original = new NetworkStats(TEST_START, 5) - .addValues(TEST_IFACE, 100, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 2L, 20L) - .addValues(TEST_IFACE2, 100, SET_DEFAULT, TAG_NONE, 512L, 32L, 0L, 0L, 0L); - - // make clone and mutate original - final NetworkStats clone = original.clone(); - original.addValues(TEST_IFACE, 101, SET_DEFAULT, TAG_NONE, 128L, 8L, 0L, 0L, 0L); - - assertEquals(3, original.size()); - assertEquals(2, clone.size()); - - assertEquals(128L + 512L + 128L, original.getTotalBytes()); - assertEquals(128L + 512L, clone.getTotalBytes()); - } - - private static void assertValues(NetworkStats stats, int index, String iface, int uid, int set, - int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, long operations) { - final NetworkStats.Entry entry = stats.getValues(index, null); - assertValues(entry, iface, uid, set, tag); - assertValues(entry, rxBytes, rxPackets, txBytes, txPackets, operations); - } - - private static void assertValues( - NetworkStats.Entry entry, String iface, int uid, int set, int tag) { - assertEquals(iface, entry.iface); - assertEquals(uid, entry.uid); - assertEquals(set, entry.set); - assertEquals(tag, entry.tag); - } - - private static void assertValues(NetworkStats.Entry entry, long rxBytes, long rxPackets, - long txBytes, long txPackets, long operations) { - assertEquals(rxBytes, entry.rxBytes); - assertEquals(rxPackets, entry.rxPackets); - assertEquals(txBytes, entry.txBytes); - assertEquals(txPackets, entry.txPackets); - assertEquals(operations, entry.operations); - } - -} diff --git a/core/tests/coretests/src/android/net/RouteInfoTest.java b/core/tests/coretests/src/android/net/RouteInfoTest.java deleted file mode 100644 index 01283a65ba..0000000000 --- a/core/tests/coretests/src/android/net/RouteInfoTest.java +++ /dev/null @@ -1,214 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package 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((LinkAddress) null, null, "rmnet0"); - fail("Expected RuntimeException: destination and gateway null"); - } catch(RuntimeException e) {} - - // Null destination is default route. - 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((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()); - - // 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 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; - 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); - } -} diff --git a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java b/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java deleted file mode 100644 index d3dd01a240..0000000000 --- a/core/tests/coretests/src/com/android/internal/net/NetworkStatsFactoryTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.net; - -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.SET_FOREGROUND; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static com.android.server.NetworkManagementSocketTagger.kernelToTag; - -import android.content.res.Resources; -import android.net.NetworkStats; -import android.net.TrafficStats; -import android.test.AndroidTestCase; - -import com.android.frameworks.coretests.R; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.FileWriter; -import java.io.InputStream; -import java.io.OutputStream; - -import libcore.io.IoUtils; -import libcore.io.Streams; - -/** - * Tests for {@link NetworkStatsFactory}. - */ -public class NetworkStatsFactoryTest extends AndroidTestCase { - private File mTestProc; - private NetworkStatsFactory mFactory; - - @Override - public void setUp() throws Exception { - super.setUp(); - - mTestProc = new File(getContext().getFilesDir(), "proc"); - if (mTestProc.exists()) { - IoUtils.deleteContents(mTestProc); - } - - mFactory = new NetworkStatsFactory(mTestProc); - } - - @Override - public void tearDown() throws Exception { - mFactory = null; - - if (mTestProc.exists()) { - IoUtils.deleteContents(mTestProc); - } - - super.tearDown(); - } - - public void testNetworkStatsDetail() throws Exception { - stageFile(R.raw.xt_qtaguid_typical, new File(mTestProc, "net/xt_qtaguid/stats")); - - final NetworkStats stats = mFactory.readNetworkStatsDetail(); - assertEquals(70, stats.size()); - assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 18621L, 2898L); - assertStatsEntry(stats, "wlan0", 10011, SET_DEFAULT, 0x0, 35777L, 5718L); - assertStatsEntry(stats, "wlan0", 10021, SET_DEFAULT, 0x7fffff01, 562386L, 49228L); - assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 227423L); - assertStatsEntry(stats, "rmnet2", 10001, SET_DEFAULT, 0x0, 1125899906842624L, 984L); - } - - public void testKernelTags() throws Exception { - assertEquals(0, kernelToTag("0x0000000000000000")); - assertEquals(0x32, kernelToTag("0x0000003200000000")); - assertEquals(2147483647, kernelToTag("0x7fffffff00000000")); - assertEquals(0, kernelToTag("0x0000000000000000")); - assertEquals(2147483136, kernelToTag("0x7FFFFE0000000000")); - - assertEquals(0, kernelToTag("0x0")); - assertEquals(0, kernelToTag("0xf00d")); - assertEquals(1, kernelToTag("0x100000000")); - assertEquals(14438007, kernelToTag("0xdc4e7700000000")); - assertEquals(TrafficStats.TAG_SYSTEM_DOWNLOAD, kernelToTag("0xffffff0100000000")); - } - - public void testNetworkStatsWithSet() throws Exception { - stageFile(R.raw.xt_qtaguid_typical, new File(mTestProc, "net/xt_qtaguid/stats")); - - final NetworkStats stats = mFactory.readNetworkStatsDetail(); - assertEquals(70, stats.size()); - assertStatsEntry(stats, "rmnet1", 10021, SET_DEFAULT, 0x30100000, 219110L, 578L, 227423L, 676L); - assertStatsEntry(stats, "rmnet1", 10021, SET_FOREGROUND, 0x30100000, 742L, 3L, 1265L, 3L); - } - - public void testNetworkStatsSingle() throws Exception { - stageFile(R.raw.xt_qtaguid_iface_typical, new File(mTestProc, "net/xt_qtaguid/iface_stat_all")); - - final NetworkStats stats = mFactory.readNetworkStatsSummaryDev(); - assertEquals(6, stats.size()); - assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 2112L, 24L, 700L, 10L); - assertStatsEntry(stats, "test1", UID_ALL, SET_ALL, TAG_NONE, 6L, 8L, 10L, 12L); - assertStatsEntry(stats, "test2", UID_ALL, SET_ALL, TAG_NONE, 1L, 2L, 3L, 4L); - } - - public void testNetworkStatsXt() throws Exception { - stageFile(R.raw.xt_qtaguid_iface_fmt_typical, - new File(mTestProc, "net/xt_qtaguid/iface_stat_fmt")); - - final NetworkStats stats = mFactory.readNetworkStatsSummaryXt(); - assertEquals(3, stats.size()); - assertStatsEntry(stats, "rmnet0", UID_ALL, SET_ALL, TAG_NONE, 6824L, 16L, 5692L, 10L); - assertStatsEntry(stats, "rmnet1", UID_ALL, SET_ALL, TAG_NONE, 11153922L, 8051L, 190226L, 2468L); - assertStatsEntry(stats, "rmnet2", UID_ALL, SET_ALL, TAG_NONE, 4968L, 35L, 3081L, 39L); - } - - /** - * Copy a {@link Resources#openRawResource(int)} into {@link File} for - * testing purposes. - */ - private void stageFile(int rawId, File file) throws Exception { - new File(file.getParent()).mkdirs(); - InputStream in = null; - OutputStream out = null; - try { - in = getContext().getResources().openRawResource(rawId); - out = new FileOutputStream(file); - Streams.copy(in, out); - } finally { - IoUtils.closeQuietly(in); - IoUtils.closeQuietly(out); - } - } - - private void stageLong(long value, File file) throws Exception { - new File(file.getParent()).mkdirs(); - FileWriter out = null; - try { - out = new FileWriter(file); - out.write(Long.toString(value)); - } finally { - IoUtils.closeQuietly(out); - } - } - - private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set, - int tag, long rxBytes, long txBytes) { - final int i = stats.findIndex(iface, uid, set, tag); - final NetworkStats.Entry entry = stats.getValues(i, null); - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - } - - private static void assertStatsEntry(NetworkStats stats, String iface, int uid, int set, - int tag, long rxBytes, long rxPackets, long txBytes, long txPackets) { - final int i = stats.findIndex(iface, uid, set, tag); - final NetworkStats.Entry entry = stats.getValues(i, null); - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - assertEquals("unexpected txPackets", txPackets, entry.txPackets); - } - -} diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java deleted file mode 100644 index 657d5eca5a..0000000000 --- a/services/core/java/com/android/server/ConnectivityService.java +++ /dev/null @@ -1,6047 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -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.NetworkCallbackListener; -import static android.net.ConnectivityManager.TYPE_BLUETOOTH; -import static android.net.ConnectivityManager.TYPE_DUMMY; -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; -import static android.net.ConnectivityManager.getNetworkTypeName; -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.AppOpsManager; -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; -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; -import android.net.CaptivePortalTracker; -import android.net.ConnectivityManager; -import android.net.DummyDataStateTracker; -import android.net.IConnectivityManager; -import android.net.INetworkManagementEventObserver; -import android.net.INetworkPolicyListener; -import android.net.INetworkPolicyManager; -import android.net.INetworkStatsService; -import android.net.LinkAddress; -import android.net.LinkProperties; -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; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkFactory; -import android.net.NetworkQuotaInfo; -import android.net.NetworkRequest; -import android.net.NetworkState; -import android.net.NetworkStateTracker; -import android.net.NetworkUtils; -import android.net.Proxy; -import android.net.ProxyDataTracker; -import android.net.ProxyInfo; -import android.net.RouteInfo; -import android.net.SamplingDataTracker; -import android.net.Uri; -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; -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; -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; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Slog; -import android.util.SparseArray; -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; -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; -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; -import com.android.server.net.BaseNetworkObserver; -import com.android.server.net.LockdownVpnTracker; -import com.google.android.collect.Lists; -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; -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; -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.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.net.ssl.HostnameVerifier; -import javax.net.ssl.HttpsURLConnection; -import javax.net.ssl.SSLSession; - -import static android.net.ConnectivityManager.INVALID_NET_ID; - -/** - * @hide - */ -public class ConnectivityService extends IConnectivityManager.Stub { - private static final String TAG = "ConnectivityService"; - - 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 - - // 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 - 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"; - - 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_REQUEST_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 = (SAMPLE_DBG ? 30 : 12 * 60); - - // start network sampling a minute after booting ... - private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 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; - - private Tethering mTethering; - - private KeyStore mKeyStore; - - @GuardedBy("mVpns") - private final SparseArray mVpns = new SparseArray(); - private VpnCallback mVpnCallback = new VpnCallback(); - - 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. */ - private SparseIntArray mUidRules = new SparseIntArray(); - /** Set of ifaces that are costly. */ - private HashSet mMeteredIfaces = Sets.newHashSet(); - - /** - * Sometimes we want to refer to the individual network state - * trackers separately, and sometimes we just want to treat them - * abstractly. - */ - private NetworkStateTracker mNetTrackers[]; - - /* Handles captive portal check on a network */ - private CaptivePortalTracker mCaptivePortalTracker; - - /** - * The link properties that define the current links - */ - private LinkProperties mCurrentLinkProperties[]; - - /** - * 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[]; - - // priority order of the nettrackers - // (excluding dynamically set mNetworkPreference) - // TODO - move mNetworkTypePreference into this - private int[] mPriorityList; - - private Context mContext; - 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; - - private Object mDnsLock = new Object(); - private int mNumDnsEntries; - - private boolean mTestMode; - private static ConnectivityService sServiceInstance; - - private INetworkManagementService mNetd; - private INetworkPolicyManager mPolicyManager; - - private static final int ENABLED = 1; - private static final int DISABLED = 0; - - private static final boolean ADD = true; - private static final boolean REMOVE = false; - - 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 - */ - private static final int EVENT_RESTORE_DEFAULT_NETWORK = 1; - - /** - * used internally to change our mobile data enabled flag - */ - private static final int EVENT_CHANGE_MOBILE_DATA_ENABLED = 2; - - /** - * used internally to synchronize inet condition reports - * arg1 = networkType - * arg2 = condition (0 bad, 100 good) - */ - private static final int EVENT_INET_CONDITION_CHANGE = 4; - - /** - * used internally to mark the end of inet condition hold periods - * arg1 = networkType - */ - private static final int EVENT_INET_CONDITION_HOLD_END = 5; - - /** - * used internally to clear a wakelock when transitioning - * from one net to another - */ - private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK = 8; - - /** - * used internally to reload global proxy settings - */ - private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9; - - /** - * used internally to set external dependency met/unmet - * arg1 = ENABLED (met) or DISABLED (unmet) - * arg2 = NetworkType - */ - private static final int EVENT_SET_DEPENDENCY_MET = 10; - - /** - * used internally to send a sticky broadcast delayed. - */ - 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 = 12; - - 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 = 14; - - /** - * used internally to indicate that data sampling interval is up - */ - private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15; - - /** - * PAC manager has received new port. - */ - private static final int EVENT_PROXY_HAS_CHANGED = 16; - - /** - * used internally when registering NetworkFactories - * obj = NetworkFactoryInfo - */ - 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; - - /** - * 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; - - /** - * 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. */ - final private NetworkStateTrackerHandler mTrackerHandler; - - // list of DeathRecipients used to make sure features are turned off when - // a process dies - private List mFeatureUsers; - - private boolean mSystemReady; - private Intent mInitialBroadcast; - - private PowerManager.WakeLock mNetTransitionWakeLock; - private String mNetTransitionWakeLockCausedBy = ""; - private int mNetTransitionWakeLockSerialNumber; - private int mNetTransitionWakeLockTimeout; - - 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; - - // track the current default http proxy - tell the world if we get a new one (real change) - private ProxyInfo mDefaultProxy = null; - private Object mProxyLock = new Object(); - private boolean mDefaultProxyDisabled = false; - - // track the global proxy. - private ProxyInfo mGlobalProxy = null; - - private PacManager mPacManager = null; - - private SettingsObserver mSettingsObserver; - - private AppOpsManager mAppOpsManager; - - NetworkConfig[] mNetConfigs; - int mNetworksDefined; - - private static class RadioAttributes { - public int mSimultaneity; - public int mType; - public RadioAttributes(String init) { - String fragments[] = init.split(","); - mType = Integer.parseInt(fragments[0]); - mSimultaneity = Integer.parseInt(fragments[1]); - } - } - RadioAttributes[] mRadioAttributes; - - // the set of network types that can only be enabled by system/sig apps - List mProtectedNetworks; - - private DataConnectionStats mDataConnectionStats; - - private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0); - - 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; - - 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 - // TODO: create here when we have cleaner WiMAX support - this(context, netd, statsService, policyManager, null); - } - - public ConnectivityService(Context context, INetworkManagementService netManager, - INetworkStatsService statsService, INetworkPolicyManager policyManager, - NetworkFactory netFactory) { - if (DBG) log("ConnectivityService starting up"); - - NetworkCapabilities netCap = new NetworkCapabilities(); - 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); - mNetworkRequests.put(mDefaultRequest, nri); - - HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread"); - handlerThread.start(); - mHandler = new InternalHandler(handlerThread.getLooper()); - mTrackerHandler = new NetworkStateTrackerHandler(handlerThread.getLooper()); - - if (netFactory == null) { - netFactory = new DefaultNetworkFactory(context, mTrackerHandler); - } - - // setup our unique device name - if (TextUtils.isEmpty(SystemProperties.get("net.hostname"))) { - String id = Settings.Secure.getString(context.getContentResolver(), - Settings.Secure.ANDROID_ID); - if (id != null && id.length() > 0) { - String name = new String("android-").concat(id); - SystemProperties.set("net.hostname", name); - } - } - - // read our default dns server ip - 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); - } - try { - mDefaultDns = NetworkUtils.numericToInetAddress(dns); - } catch (IllegalArgumentException e) { - loge("Error setting defaultDns using " + dns); - } - - mContext = checkNotNull(context, "missing Context"); - mNetd = checkNotNull(netManager, "missing INetworkManagementService"); - mPolicyManager = checkNotNull(policyManager, "missing INetworkPolicyManager"); - mKeyStore = KeyStore.getInstance(); - mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); - - try { - mPolicyManager.registerListener(mPolicyListener); - } catch (RemoteException e) { - // ouch, no rules updates means some processes may never get network - loge("unable to register INetworkPolicyListener" + e.toString()); - } - - final PowerManager powerManager = (PowerManager) context.getSystemService( - Context.POWER_SERVICE); - mNetTransitionWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mNetTransitionWakeLockTimeout = mContext.getResources().getInteger( - com.android.internal.R.integer.config_networkTransitionTimeout); - - mNetTrackers = new NetworkStateTracker[ - ConnectivityManager.MAX_NETWORK_TYPE+1]; - mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1]; - - mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1]; - mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; - - // Load device network attributes from resources - String[] raStrings = context.getResources().getStringArray( - 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; - } - if (mRadioAttributes[r.mType] != null) { - loge("Error in radioAttributes - ignoring attempt to redefine type " + - r.mType); - continue; - } - 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) { - 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); - 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); - continue; - } - if (mRadioAttributes[n.radio] == null) { - loge("Error in networkAttributes - ignoring attempt to use undefined " + - "radio " + n.radio + " in network type " + n.type); - continue; - } - mLegacyTypeTracker.addSupportedType(n.type); - - mNetConfigs[n.type] = n; - mNetworksDefined++; - } catch(Exception e) { - // ignore it - leave the entry null - } - } - if (VDBG) log("mNetworksDefined=" + mNetworksDefined); - - mProtectedNetworks = new ArrayList(); - int[] protectedNetworks = context.getResources().getIntArray( - com.android.internal.R.array.config_protectedNetworks); - for (int p : protectedNetworks) { - if ((mNetConfigs[p] != null) && (mProtectedNetworks.contains(p) == false)) { - mProtectedNetworks.add(p); - } else { - if (DBG) loge("Ignoring protectedNetwork " + p); - } - } - - // high priority first - mPriorityList = new int[mNetworksDefined]; - { - int insertionPoint = mNetworksDefined-1; - int currentLowest = 0; - int nextLowest = 0; - while (insertionPoint > -1) { - for (NetworkConfig na : mNetConfigs) { - if (na == null) continue; - if (na.priority < currentLowest) continue; - if (na.priority > currentLowest) { - if (na.priority < nextLowest || nextLowest == 0) { - nextLowest = na.priority; - } - continue; - } - mPriorityList[insertionPoint--] = na.type; - } - currentLowest = nextLowest; - nextLowest = 0; - } - } - - mNetRequestersPids = - (List [])new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; - for (int i : mPriorityList) { - mNetRequestersPids[i] = new ArrayList(); - } - - mFeatureUsers = new ArrayList(); - - mTestMode = SystemProperties.get("cm.test.mode").equals("true") - && SystemProperties.get("ro.build.type").equals("eng"); - - // Create and start trackers for hard-coded networks - for (int targetNetworkType : mPriorityList) { - final NetworkConfig config = mNetConfigs[targetNetworkType]; - final NetworkStateTracker tracker; - try { - tracker = netFactory.createTracker(targetNetworkType, config); - mNetTrackers[targetNetworkType] = tracker; - } catch (IllegalArgumentException e) { - Slog.e(TAG, "Problem creating " + getNetworkTypeName(targetNetworkType) - + " tracker: " + e); - continue; - } - - tracker.startMonitoring(context, mTrackerHandler); - if (config.isDefault()) { - tracker.reconnect(); - } - } - - mTethering = new Tethering(mContext, mNetd, statsService, this, mHandler.getLooper()); - - //set up the listener for user state for creating user VPNs - 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 { - mNetd.registerObserver(mTethering); - mNetd.registerObserver(mDataActivityObserver); - mNetd.registerObserver(mClat); - } catch (RemoteException e) { - loge("Error registering observer :" + e); - } - - if (DBG) { - mInetLog = new ArrayList(); - } - - mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY); - mSettingsObserver.observe(mContext); - - 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_REQUEST_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, mHandler, EVENT_PROXY_HAS_CHANGED); - - filter = new IntentFilter(); - filter.addAction(CONNECTED_TO_PROVISIONING_NETWORK_ACTION); - mContext.registerReceiver(mProvisioningReceiver, filter); - - 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; - return netId; - } - - /** - * 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); - } - - private static class DefaultNetworkFactory implements NetworkFactory { - private final Context mContext; - private final Handler mTrackerHandler; - - public DefaultNetworkFactory(Context context, Handler trackerHandler) { - mContext = context; - mTrackerHandler = trackerHandler; - } - - @Override - public NetworkStateTracker createTracker(int targetNetworkType, NetworkConfig config) { - switch (config.radio) { - case TYPE_DUMMY: - return new DummyDataStateTracker(targetNetworkType, config.name); - case TYPE_BLUETOOTH: - return BluetoothTetheringDataTracker.getInstance(); - case TYPE_WIMAX: - return makeWimaxStateTracker(mContext, mTrackerHandler); - case TYPE_PROXY: - return new ProxyDataTracker(); - default: - throw new IllegalArgumentException( - "Trying to create a NetworkStateTracker for an unknown radio type: " - + config.radio); - } - } - } - - /** - * Loads external WiMAX library and registers as system service, returning a - * {@link NetworkStateTracker} for WiMAX. Caller is still responsible for - * invoking {@link NetworkStateTracker#startMonitoring(Context, Handler)}. - */ - private static NetworkStateTracker makeWimaxStateTracker( - Context context, Handler trackerHandler) { - // Initialize Wimax - DexClassLoader wimaxClassLoader; - Class wimaxStateTrackerClass = null; - Class wimaxServiceClass = null; - Class wimaxManagerClass; - String wimaxJarLocation; - String wimaxLibLocation; - String wimaxManagerClassName; - String wimaxServiceClassName; - String wimaxStateTrackerClassName; - - NetworkStateTracker wimaxStateTracker = null; - - boolean isWimaxEnabled = context.getResources().getBoolean( - com.android.internal.R.bool.config_wimaxEnabled); - - if (isWimaxEnabled) { - try { - wimaxJarLocation = context.getResources().getString( - com.android.internal.R.string.config_wimaxServiceJarLocation); - wimaxLibLocation = context.getResources().getString( - com.android.internal.R.string.config_wimaxNativeLibLocation); - wimaxManagerClassName = context.getResources().getString( - com.android.internal.R.string.config_wimaxManagerClassname); - wimaxServiceClassName = context.getResources().getString( - com.android.internal.R.string.config_wimaxServiceClassname); - wimaxStateTrackerClassName = context.getResources().getString( - com.android.internal.R.string.config_wimaxStateTrackerClassname); - - if (DBG) log("wimaxJarLocation: " + wimaxJarLocation); - wimaxClassLoader = new DexClassLoader(wimaxJarLocation, - new ContextWrapper(context).getCacheDir().getAbsolutePath(), - wimaxLibLocation, ClassLoader.getSystemClassLoader()); - - try { - wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName); - wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName); - wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName); - } catch (ClassNotFoundException ex) { - loge("Exception finding Wimax classes: " + ex.toString()); - return null; - } - } catch(Resources.NotFoundException ex) { - loge("Wimax Resources does not exist!!! "); - return null; - } - - try { - if (DBG) log("Starting Wimax Service... "); - - Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor - (new Class[] {Context.class, Handler.class}); - wimaxStateTracker = (NetworkStateTracker) wmxStTrkrConst.newInstance( - context, trackerHandler); - - Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor - (new Class[] {Context.class, wimaxStateTrackerClass}); - wmxSrvConst.setAccessible(true); - IBinder svcInvoker = (IBinder)wmxSrvConst.newInstance(context, wimaxStateTracker); - wmxSrvConst.setAccessible(false); - - ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker); - - } catch(Exception ex) { - loge("Exception creating Wimax classes: " + ex.toString()); - return null; - } - } else { - loge("Wimax is not enabled or not added to the network attributes!!! "); - return null; - } - - return wimaxStateTracker; - } - - private int getConnectivityChangeDelay() { - final ContentResolver cr = mContext.getContentResolver(); - - /** Check system properties for the default value then use secure settings value, if any. */ - int defaultDelay = SystemProperties.getInt( - "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY, - ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT); - return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY, - defaultDelay); - } - - private boolean teardown(NetworkStateTracker netTracker) { - if (netTracker.teardown()) { - netTracker.setTeardownRequested(true); - return true; - } else { - return false; - } - } - - /** - * Check if UID should be blocked from using the network represented by the - * given {@link NetworkStateTracker}. - */ - 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); - } - - if (networkCostly && (uidRules & RULE_REJECT_METERED) != 0) { - return true; - } - - // no restrictive rules; network is visible - return false; - } - - /** - * Return a filtered {@link NetworkInfo}, potentially marked - * {@link DetailedState#BLOCKED} based on - * {@link #isNetworkBlocked}. - */ - 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); - } - if (mLockdownTracker != null) { - info = mLockdownTracker.augmentNetworkInfo(info); - } - return info; - } - - /** - * Return NetworkInfo for the active (i.e., connected) network interface. - * It is assumed that at most one network is active at a time. If more - * than one is active, it is indeterminate which will be returned. - * @return the info for the active network, or {@code null} if none is - * active - */ - @Override - public NetworkInfo getActiveNetworkInfo() { - enforceAccessPermission(); - final int uid = Binder.getCallingUid(); - 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. - * - * @return NetworkInfo or null if none. - */ - private NetworkInfo getProvisioningNetworkInfo() { - enforceAccessPermission(); - - // Find the first Provisioning Network - NetworkInfo provNi = null; - for (NetworkInfo ni : getAllNetworkInfo()) { - if (ni.isConnectedToProvisioningNetwork()) { - 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)) { - return getNetworkInfoForType(mActiveDefaultNetwork); - } - return null; - } - - @Override - public NetworkInfo getActiveNetworkInfoForUid(int uid) { - enforceConnectivityInternalPermission(); - return getNetworkInfo(mActiveDefaultNetwork, uid); - } - - @Override - public NetworkInfo getNetworkInfo(int networkType) { - enforceAccessPermission(); - final int uid = Binder.getCallingUid(); - return getNetworkInfo(networkType, uid); - } - - private NetworkInfo getNetworkInfo(int networkType, int uid) { - NetworkInfo info = null; - if (isNetworkTypeValid(networkType)) { - if (getNetworkInfoForType(networkType) != null) { - info = getFilteredNetworkInfo(networkType, uid); - } - } - return info; - } - - @Override - public NetworkInfo[] getAllNetworkInfo() { - enforceAccessPermission(); - final int uid = Binder.getCallingUid(); - final ArrayList result = Lists.newArrayList(); - synchronized (mRulesLock) { - for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE; - networkType++) { - if (getNetworkInfoForType(networkType) != null) { - result.add(getFilteredNetworkInfo(networkType, uid)); - } - } - } - return result.toArray(new NetworkInfo[result.size()]); - } - - @Override - public boolean isNetworkSupported(int networkType) { - enforceAccessPermission(); - return (isNetworkTypeValid(networkType) && (getNetworkInfoForType(networkType) != null)); - } - - /** - * Return LinkProperties for the active (i.e., connected) default - * network interface. It is assumed that at most one default network - * is active at a time. If more than one is active, it is indeterminate - * which will be returned. - * @return the ip properties for the active network, or {@code null} if - * none is active - */ - @Override - public LinkProperties getActiveLinkProperties() { - return getLinkPropertiesForType(mActiveDefaultNetwork); - } - - @Override - public LinkProperties getLinkPropertiesForType(int networkType) { - enforceAccessPermission(); - if (isNetworkTypeValid(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(); - final int uid = Binder.getCallingUid(); - final ArrayList result = Lists.newArrayList(); - synchronized (mRulesLock) { - for (int networkType = 0; networkType <= ConnectivityManager.MAX_NETWORK_TYPE; - networkType++) { - if (getNetworkInfoForType(networkType) != null) { - final NetworkInfo info = getFilteredNetworkInfo(networkType, uid); - final LinkProperties lp = getLinkPropertiesForTypeInternal(networkType); - final NetworkCapabilities netcap = getNetworkCapabilitiesForType(networkType); - result.add(new NetworkState(info, lp, netcap)); - } - } - } - return result.toArray(new NetworkState[result.size()]); - } - - private NetworkState getNetworkStateUnchecked(int networkType) { - if (isNetworkTypeValid(networkType)) { - NetworkInfo info = getNetworkInfoForType(networkType); - if (info != null) { - return new NetworkState(info, - getLinkPropertiesForTypeInternal(networkType), - getNetworkCapabilitiesForType(networkType)); - } - } - return null; - } - - @Override - public NetworkQuotaInfo getActiveNetworkQuotaInfo() { - enforceAccessPermission(); - - final long token = Binder.clearCallingIdentity(); - try { - final NetworkState state = getNetworkStateUnchecked(mActiveDefaultNetwork); - if (state != null) { - try { - return mPolicyManager.getNetworkQuotaInfo(state); - } catch (RemoteException e) { - } - } - return null; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - @Override - public boolean isActiveNetworkMetered() { - enforceAccessPermission(); - final long token = Binder.clearCallingIdentity(); - try { - return isNetworkMeteredUnchecked(mActiveDefaultNetwork); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private boolean isNetworkMeteredUnchecked(int networkType) { - final NetworkState state = getNetworkStateUnchecked(networkType); - if (state != null) { - try { - return mPolicyManager.isNetworkMetered(state); - } catch (RemoteException e) { - } - } - return false; - } - - private INetworkManagementEventObserver mDataActivityObserver = new BaseNetworkObserver() { - @Override - public void interfaceClassDataActivityChanged(String label, boolean active, long tsNanos) { - int deviceType = Integer.parseInt(label); - sendDataActivityBroadcast(deviceType, active, tsNanos); - } - }; - - /** - * Used to notice when the calling process dies so we can self-expire - * - * Also used to know if the process has cleaned up after itself when - * our auto-expire timer goes off. The timer has a link to an object. - * - */ - private class FeatureUser implements IBinder.DeathRecipient { - int mNetworkType; - String mFeature; - IBinder mBinder; - int mPid; - int mUid; - long mCreateTime; - - FeatureUser(int type, String feature, IBinder binder) { - super(); - mNetworkType = type; - mFeature = feature; - mBinder = binder; - mPid = getCallingPid(); - mUid = getCallingUid(); - mCreateTime = System.currentTimeMillis(); - - try { - mBinder.linkToDeath(this, 0); - } catch (RemoteException e) { - binderDied(); - } - } - - void unlinkDeathRecipient() { - mBinder.unlinkToDeath(this, 0); - } - - public void binderDied() { - log("ConnectivityService FeatureUser binderDied(" + - mNetworkType + ", " + mFeature + ", " + mBinder + "), created " + - (System.currentTimeMillis() - mCreateTime) + " mSec ago"); - stopUsingNetworkFeature(this, false); - } - - public void expire() { - if (VDBG) { - log("ConnectivityService FeatureUser expire(" + - mNetworkType + ", " + mFeature + ", " + mBinder +"), created " + - (System.currentTimeMillis() - mCreateTime) + " mSec ago"); - } - stopUsingNetworkFeature(this, false); - } - - public boolean isSameUser(FeatureUser u) { - if (u == null) return false; - - return isSameUser(u.mPid, u.mUid, u.mNetworkType, u.mFeature); - } - - public boolean isSameUser(int pid, int uid, int networkType, String feature) { - if ((mPid == pid) && (mUid == uid) && (mNetworkType == networkType) && - TextUtils.equals(mFeature, feature)) { - return true; - } - return false; - } - - public String toString() { - return "FeatureUser("+mNetworkType+","+mFeature+","+mPid+","+mUid+"), created " + - (System.currentTimeMillis() - mCreateTime) + " mSec ago"; - } - } - - // javadoc from interface - public int startUsingNetworkFeature(int networkType, String feature, - IBinder binder) { - long startTime = 0; - if (DBG) { - startTime = SystemClock.elapsedRealtime(); - } - if (VDBG) { - log("startUsingNetworkFeature for net " + networkType + ": " + feature + ", uid=" - + Binder.getCallingUid()); - } - enforceChangePermission(); - try { - if (!ConnectivityManager.isNetworkTypeValid(networkType) || - mNetConfigs[networkType] == null) { - return PhoneConstants.APN_REQUEST_FAILED; - } - - FeatureUser f = new FeatureUser(networkType, feature, binder); - - // 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(); - } - - // if UID is restricted, don't allow them to bring up metered APNs - final boolean networkMetered = isNetworkMeteredUnchecked(usedNetworkType); - final int uidRules; - synchronized (mRulesLock) { - uidRules = mUidRules.get(Binder.getCallingUid(), RULE_ALLOW_ALL); - } - if (networkMetered && (uidRules & RULE_REJECT_METERED) != 0) { - return PhoneConstants.APN_REQUEST_FAILED; - } - - NetworkStateTracker network = mNetTrackers[usedNetworkType]; - if (network != null) { - Integer currentPid = new Integer(getCallingPid()); - if (usedNetworkType != networkType) { - NetworkInfo ni = network.getNetworkInfo(); - - if (ni.isAvailable() == false) { - if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) { - if (DBG) log("special network not available ni=" + ni.getTypeName()); - return PhoneConstants.APN_TYPE_NOT_AVAILABLE; - } else { - // else make the attempt anyway - probably giving REQUEST_STARTED below - if (DBG) { - log("special network not available, but try anyway ni=" + - ni.getTypeName()); - } - } - } - - int restoreTimer = getRestoreDefaultNetworkDelay(usedNetworkType); - - synchronized(this) { - boolean addToList = true; - if (restoreTimer < 0) { - // In case there is no timer is specified for the feature, - // make sure we don't add duplicate entry with the same request. - for (FeatureUser u : mFeatureUsers) { - if (u.isSameUser(f)) { - // Duplicate user is found. Do not add. - addToList = false; - break; - } - } - } - - if (addToList) mFeatureUsers.add(f); - if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { - // this gets used for per-pid dns when connected - mNetRequestersPids[usedNetworkType].add(currentPid); - } - } - - if (restoreTimer >= 0) { - mHandler.sendMessageDelayed(mHandler.obtainMessage( - EVENT_RESTORE_DEFAULT_NETWORK, f), restoreTimer); - } - - if ((ni.isConnectedOrConnecting() == true) && - !network.isTeardownRequested()) { - if (ni.isConnected() == true) { - final long token = Binder.clearCallingIdentity(); - try { - // add the pid-specific dns - handleDnsConfigurationChange(usedNetworkType); - if (VDBG) log("special network already active"); - } finally { - Binder.restoreCallingIdentity(token); - } - return PhoneConstants.APN_ALREADY_ACTIVE; - } - if (VDBG) log("special network already connecting"); - return PhoneConstants.APN_REQUEST_STARTED; - } - - // check if the radio in play can make another contact - // assume if cannot for now - - if (DBG) { - log("startUsingNetworkFeature reconnecting to " + networkType + ": " + - 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 { - // need to remember this unsupported request so we respond appropriately on stop - synchronized(this) { - mFeatureUsers.add(f); - if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { - // this gets used for per-pid dns when connected - 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) { - final long execTime = SystemClock.elapsedRealtime() - startTime; - if (execTime > 250) { - loge("startUsingNetworkFeature took too long: " + execTime + "ms"); - } else { - if (VDBG) log("startUsingNetworkFeature took " + execTime + "ms"); - } - } - } - } - - // javadoc from interface - public int stopUsingNetworkFeature(int networkType, String feature) { - enforceChangePermission(); - - int pid = getCallingPid(); - int uid = getCallingUid(); - - FeatureUser u = null; - boolean found = false; - - synchronized(this) { - for (FeatureUser x : mFeatureUsers) { - if (x.isSameUser(pid, uid, networkType, feature)) { - u = x; - found = true; - break; - } - } - } - 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: X not a live request, ignoring"); - return 1; - } - } - - private int stopUsingNetworkFeature(FeatureUser u, boolean ignoreDups) { - int networkType = u.mNetworkType; - String feature = u.mFeature; - int pid = u.mPid; - int uid = u.mUid; - - NetworkStateTracker tracker = null; - boolean callTeardown = false; // used to carry our decision outside of sync block - - if (VDBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature); - } - - if (!ConnectivityManager.isNetworkTypeValid(networkType)) { - if (DBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature + - ", net is invalid"); - } - return -1; - } - - // need to link the mFeatureUsers list with the mNetRequestersPids state in this - // sync block - synchronized(this) { - // check if this process still has an outstanding start request - if (!mFeatureUsers.contains(u)) { - if (VDBG) { - log("stopUsingNetworkFeature: this process has no outstanding requests" + - ", ignoring"); - } - return 1; - } - u.unlinkDeathRecipient(); - mFeatureUsers.remove(mFeatureUsers.indexOf(u)); - // If we care about duplicate requests, check for that here. - // - // This is done to support the extension of a request - the app - // can request we start the network feature again and renew the - // auto-shutoff delay. Normal "stop" calls from the app though - // do not pay attention to duplicate requests - in effect the - // API does not refcount and a single stop will counter multiple starts. - if (ignoreDups == false) { - for (FeatureUser x : mFeatureUsers) { - if (x.isSameUser(u)) { - if (VDBG) log("stopUsingNetworkFeature: dup is found, ignoring"); - return 1; - } - } - } - - // TODO - move to individual network trackers - int usedNetworkType = convertFeatureToNetworkType(networkType, feature); - - tracker = mNetTrackers[usedNetworkType]; - if (tracker == null) { - if (DBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature + - " no known tracker for used net type " + usedNetworkType); - } - return -1; - } - if (usedNetworkType != networkType) { - Integer currentPid = new Integer(pid); - mNetRequestersPids[usedNetworkType].remove(currentPid); - - final long token = Binder.clearCallingIdentity(); - try { - reassessPidDns(pid, true); - } finally { - Binder.restoreCallingIdentity(token); - } - flushVmDnsCache(); - if (mNetRequestersPids[usedNetworkType].size() != 0) { - if (VDBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature + - " others still using it"); - } - return 1; - } - callTeardown = true; - } else { - if (DBG) { - log("stopUsingNetworkFeature: net " + networkType + ": " + feature + - " not a known feature - dropping"); - } - } - } - - if (callTeardown) { - if (DBG) { - log("stopUsingNetworkFeature: teardown net " + networkType + ": " + feature); - } - tracker.teardown(); - return 1; - } else { - return -1; - } - } - - /** - * 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.getPrefixLength(); - 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 - * - * Ensure that a network route exists to deliver traffic to the specified - * host via the specified network interface. - * @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 - * @return {@code true} on success, {@code false} on failure - */ - public boolean requestRouteToHost(int networkType, int hostAddress, String packageName) { - InetAddress inetAddress = NetworkUtils.intToInetAddress(hostAddress); - - if (inetAddress == null) { - return false; - } - - return requestRouteToHostAddress(networkType, inetAddress.getAddress(), packageName); - } - - /** - * Ensure that a network route exists to deliver traffic to the specified - * host via the specified network interface. - * @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 - * @return {@code true} on success, {@code false} on failure - */ - public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress, - String packageName) { - enforceChangePermission(); - 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); - return false; - } - - 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)) { - if (VDBG) { - log("requestRouteToHostAddress on down network " - + "(" + networkType + ") - dropped" - + " netState=" + netState); - } - return false; - } - final int uid = Binder.getCallingUid(); - final long token = Binder.clearCallingIdentity(); - try { - LinkProperties lp = nai.linkProperties; - boolean ok = modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE, exempt, - nai.network.netId, uid); - if (DBG) log("requestRouteToHostAddress ok=" + ok); - return ok; - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable, - boolean exempt, int 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, false, UID_UNUSED); - } - - private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd, - boolean toDefaultTable, boolean exempt, int netId, int uid) { - RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getAllRoutes(), addr); - if (bestRoute == null) { - 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); - } else { - // if we will connect to this through another route, add a direct route - // to it's gateway - bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway(), iface); - } - } - 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 legacy, int uid) { - if ((lp == null) || (r == null)) { - if (DBG) log("modifyRoute got unexpected null: " + lp + ", " + r); - return false; - } - - if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) { - loge("Error modifying route - too much recursion"); - return false; - } - - String ifaceName = r.getInterface(); - if(ifaceName == null) { - loge("Error modifying route - no interface name"); - return false; - } - if (r.hasGateway()) { - 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 - 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(), - ifaceName); - } - modifyRoute(lp, bestRoute, cycleCount+1, doAdd, toDefaultTable, exempt, netId, - legacy, uid); - } - } - if (doAdd) { - if (VDBG) log("Adding " + r + " for interface " + ifaceName); - try { - if (toDefaultTable) { - synchronized (mRoutesLock) { - // only track default table - only one apps can effect - mAddedRoutes.add(r); - if (legacy) { - mNetd.addLegacyRouteForNetId(netId, r, uid); - } else { - mNetd.addRoute(netId, r); - } - if (exempt) { - LinkAddress dest = r.getDestinationLinkAddress(); - if (!mExemptAddresses.contains(dest)) { - mNetd.setHostExemption(dest); - mExemptAddresses.add(dest); - } - } - } - } else { - if (legacy) { - mNetd.addLegacyRouteForNetId(netId, r, uid); - } else { - mNetd.addRoute(netId, r); - } - } - } catch (Exception e) { - // never crash - catch them all - if (DBG) loge("Exception trying to add a route: " + e); - return false; - } - } else { - // 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) { - synchronized (mRoutesLock) { - mAddedRoutes.remove(r); - if (mAddedRoutes.contains(r) == false) { - if (VDBG) log("Removing " + r + " for interface " + ifaceName); - try { - if (legacy) { - mNetd.removeLegacyRouteForNetId(netId, r, uid); - } else { - mNetd.removeRoute(netId, r); - } - LinkAddress dest = r.getDestinationLinkAddress(); - 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("Removing " + r + " for interface " + ifaceName); - try { - 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); - return false; - } - } - } - return true; - } - - public void setDataDependency(int networkType, boolean met) { - enforceConnectivityInternalPermission(); - - mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET, - (met ? ENABLED : DISABLED), networkType)); - } - - private void handleSetDependencyMet(int networkType, boolean met) { - if (mNetTrackers[networkType] != null) { - if (DBG) { - log("handleSetDependencyMet(" + networkType + ", " + met + ")"); - } - mNetTrackers[networkType].setDependencyMet(met); - } - } - - private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { - @Override - public void onUidRulesChanged(int uid, int uidRules) { - // caller is NPMS, since we only register with them - if (LOGD_RULES) { - log("onUidRulesChanged(uid=" + uid + ", uidRules=" + uidRules + ")"); - } - - synchronized (mRulesLock) { - // skip update when we've already applied rules - final int oldRules = mUidRules.get(uid, RULE_ALLOW_ALL); - if (oldRules == uidRules) return; - - mUidRules.put(uid, uidRules); - } - - // TODO: notify UID when it has requested targeted updates - } - - @Override - public void onMeteredIfacesChanged(String[] meteredIfaces) { - // caller is NPMS, since we only register with them - if (LOGD_RULES) { - log("onMeteredIfacesChanged(ifaces=" + Arrays.toString(meteredIfaces) + ")"); - } - - synchronized (mRulesLock) { - mMeteredIfaces.clear(); - for (String iface : meteredIfaces) { - mMeteredIfaces.add(iface); - } - } - } - - @Override - public void onRestrictBackgroundChanged(boolean restrictBackground) { - // caller is NPMS, since we only register with them - if (LOGD_RULES) { - log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); - } - - // kick off connectivity change broadcast for active network, since - // global background policy change is radical. - final int networkType = mActiveDefaultNetwork; - if (isNetworkTypeValid(networkType)) { - final NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - final NetworkInfo info = tracker.getNetworkInfo(); - if (info != null && info.isConnected()) { - sendConnectedBroadcast(info); - } - } - } - } - }; - - @Override - public void setPolicyDataEnable(int networkType, boolean enabled) { - // only someone like NPMS should only be calling us - mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - - mHandler.sendMessage(mHandler.obtainMessage( - EVENT_SET_POLICY_DATA_ENABLE, networkType, (enabled ? ENABLED : DISABLED))); - } - - private void handleSetPolicyDataEnable(int networkType, boolean enabled) { - // TODO - handle this passing to factories -// if (isNetworkTypeValid(networkType)) { -// final NetworkStateTracker tracker = mNetTrackers[networkType]; -// if (tracker != null) { -// tracker.setPolicyDataEnable(enabled); -// } -// } - } - - private void enforceAccessPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ACCESS_NETWORK_STATE, - "ConnectivityService"); - } - - private void enforceChangePermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CHANGE_NETWORK_STATE, - "ConnectivityService"); - } - - // TODO Make this a special check when it goes public - private void enforceTetherChangePermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CHANGE_NETWORK_STATE, - "ConnectivityService"); - } - - private void enforceTetherAccessPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.ACCESS_NETWORK_STATE, - "ConnectivityService"); - } - - private void enforceConnectivityInternalPermission() { - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.CONNECTIVITY_INTERNAL, - "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 - * broadcast. But first, we check whether it might be possible to connect - * to a different network. - * @param info the {@code NetworkInfo} for the network - */ - private void handleDisconnect(NetworkInfo info) { - - int prevNetType = info.getType(); - - mNetTrackers[prevNetType].setTeardownRequested(false); - int thisNetId = mNetTrackers[prevNetType].getNetwork().netId; - - // Remove idletimer previously setup in {@code handleConnect} -// 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 - * this as a loss of connectivity. What probably happened is that we're - * getting the disconnect for a network that we explicitly disabled - * in accordance with network preference policies. - */ - if (!mNetConfigs[prevNetType].isDefault()) { - List 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. - reassessPidDns(pid.intValue(), false); - } - } - - 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 (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - info.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()); - } - - if (mNetConfigs[prevNetType].isDefault()) { - tryFailover(prevNetType); - if (mActiveDefaultNetwork != -1) { - NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo(); - intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo); - } else { - mDefaultInetConditionPublished = 0; // we're not connected anymore - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - } - } - intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); - - // Reset interface if no other connections are using the same interface - boolean doReset = true; - LinkProperties linkProperties = mNetTrackers[prevNetType].getLinkProperties(); - if (linkProperties != null) { - String oldIface = linkProperties.getInterfaceName(); - if (TextUtils.isEmpty(oldIface) == false) { - for (NetworkStateTracker networkStateTracker : mNetTrackers) { - if (networkStateTracker == null) continue; - NetworkInfo networkInfo = networkStateTracker.getNetworkInfo(); - if (networkInfo.isConnected() && networkInfo.getType() != prevNetType) { - LinkProperties l = networkStateTracker.getLinkProperties(); - if (l == null) continue; - if (oldIface.equals(l.getInterfaceName())) { - doReset = false; - break; - } - } - } - } - } - - // do this before we broadcast the change -// Already done in new function. This is dead code. -// handleConnectivityChange(prevNetType, doReset); - - final Intent immediateIntent = new Intent(intent); - immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); - sendStickyBroadcast(immediateIntent); - sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); - /* - * If the failover network is already connected, then immediately send - * out a followup broadcast indicating successful failover - */ - if (mActiveDefaultNetwork != -1) { - 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) { - /* - * If this is a default network, check if other defaults are available. - * Try to reconnect on all available and let them hash it out when - * more than one connects. - */ - if (mNetConfigs[prevNetType].isDefault()) { - if (mActiveDefaultNetwork == prevNetType) { - if (DBG) { - 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 - // current connected default - // TODO - don't filter by priority now - nice optimization but risky -// int currentPriority = -1; -// 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; - if (!mNetConfigs[checkType].isDefault()) continue; - if (mNetTrackers[checkType] == null) continue; - -// Enabling the isAvailable() optimization caused mobile to not get -// selected if it was in the middle of error handling. Specifically -// a moble connection that took 30 seconds to complete the DEACTIVATE_DATA_CALL -// would not be available and we wouldn't get connected to anything. -// So removing the isAvailable() optimization below for now. TODO: This -// 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; - - NetworkStateTracker checkTracker = mNetTrackers[checkType]; - NetworkInfo checkInfo = checkTracker.getNetworkInfo(); - if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) { - checkInfo.setFailover(true); - checkTracker.reconnect(); - } - if (DBG) log("Attempting to switch to " + checkInfo.getTypeName()); - } - } - } - - public void sendConnectedBroadcast(NetworkInfo info) { - enforceConnectivityInternalPermission(); - sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); - sendGeneralBroadcast(info, CONNECTIVITY_ACTION); - } - - private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) { - sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); - sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs); - } - - private void sendInetConditionBroadcast(NetworkInfo info) { - sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION); - } - - 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, new NetworkInfo(info)); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_TYPE, info.getType()); - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - info.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()); - } - intent.putExtra(ConnectivityManager.EXTRA_INET_CONDITION, mDefaultInetConditionPublished); - return intent; - } - - private void sendGeneralBroadcast(NetworkInfo info, String bcastType) { - sendStickyBroadcast(makeGeneralIntent(info, bcastType)); - } - - private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) { - sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs); - } - - 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, - RECEIVE_DATA_ACTIVITY_CHANGE, null, null, 0, null, null); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - private void sendStickyBroadcast(Intent intent) { - synchronized(this) { - if (!mSystemReady) { - mInitialBroadcast = new Intent(intent); - } - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - if (VDBG) { - log("sendStickyBroadcast: action=" + intent.getAction()); - } - - final long ident = Binder.clearCallingIdentity(); - try { - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - } - - private void sendStickyBroadcastDelayed(Intent intent, int delayMs) { - if (delayMs <= 0) { - sendStickyBroadcast(intent); - } else { - if (VDBG) { - log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action=" - + intent.getAction()); - } - mHandler.sendMessageDelayed(mHandler.obtainMessage( - EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs); - } - } - - void systemReady() { - mCaptivePortalTracker = CaptivePortalTracker.makeCaptivePortalTracker(mContext, this); - loadGlobalProxy(); - - synchronized(this) { - mSystemReady = true; - if (mInitialBroadcast != null) { - mContext.sendStickyBroadcastAsUser(mInitialBroadcast, UserHandle.ALL); - mInitialBroadcast = null; - } - } - // 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 boolean isNewNetTypePreferredOverCurrentNetType(int type) { - if (((type != mNetworkPreference) - && (mNetConfigs[mActiveDefaultNetwork].priority > mNetConfigs[type].priority)) - || (mNetworkPreference == mActiveDefaultNetwork)) { - return false; - } - return true; - } - - private void handleConnect(NetworkInfo info) { - final int newNetType = info.getType(); - - // snapshot isFailover, because sendConnectedBroadcast() resets it - boolean isFailover = info.isFailover(); - 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()) { - if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != newNetType) { - if (isNewNetTypePreferredOverCurrentNetType(newNetType)) { - 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 - if (VDBG) { - log("Not broadcasting CONNECT_ACTION " + - "to torn down network " + info.getTypeName()); - } - teardown(thisNet); - return; - } - } - int thisNetId = nextNetId(); - thisNet.setNetId(thisNetId); - try { -// mNetd.createNetwork(thisNetId, thisIface); - } catch (Exception e) { - loge("Exception creating network :" + e); - teardown(thisNet); - return; - } -// 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 - // new network - if (mNetTransitionWakeLock.isHeld()) { - mHandler.sendMessageDelayed(mHandler.obtainMessage( - EVENT_CLEAR_NET_TRANSITION_WAKELOCK, - mNetTransitionWakeLockSerialNumber, 0), - 1000); - } - } - 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 - mDefaultInetConditionPublished = 0; - mDefaultConnectionSequence++; - mInetConditionChangeInFlight = false; - // 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); -// 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 - if (thisIface != null) { - try { - BatteryStatsService.getService().noteNetworkInterfaceType(thisIface, newNetType); - } catch (RemoteException e) { - // ignored; service lives in system_server - } - } - } - - /** @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. - * - * Every {@code setupDataActivityTracking} should be paired with a - * {@link #removeDataActivityTracking} for cleanup. - */ - private void setupDataActivityTracking(NetworkAgentInfo networkAgent) { - final String iface = networkAgent.linkProperties.getInterfaceName(); - - final int timeout; - int type = ConnectivityManager.TYPE_NONE; - - if (networkAgent.networkCapabilities.hasTransport( - NetworkCapabilities.TRANSPORT_CELLULAR)) { - timeout = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.DATA_ACTIVITY_TIMEOUT_MOBILE, - 5); - type = ConnectivityManager.TYPE_MOBILE; - } 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 && type != ConnectivityManager.TYPE_NONE) { - try { - mNetd.addIdleTimer(iface, timeout, type); - } catch (Exception e) { - // You shall not crash! - loge("Exception in setupDataActivityTracking " + e); - } - } - } - - /** - * Remove data activity tracking when network disconnects. - */ - private void removeDataActivityTracking(NetworkAgentInfo networkAgent) { - final String iface = networkAgent.linkProperties.getInterfaceName(); - final NetworkCapabilities caps = networkAgent.networkCapabilities; - - 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); - } catch (Exception e) { - loge("Exception in removeDataActivityTracking " + 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 - * 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, LinkProperties curLp, 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 - * will allow it's DNS servers to be accessed. - */ - handleDnsConfigurationChange(netType); - - LinkProperties newLp = null; - - if (mNetTrackers[netType].getNetworkInfo().isConnected()) { - newLp = mNetTrackers[netType].getLinkProperties(); - if (VDBG) { - log("handleConnectivityChange: changed linkProperty[" + netType + "]:" + - " doReset=" + doReset + " resetMask=" + resetMask + - "\n curLp=" + curLp + - "\n newLp=" + newLp); - } - - if (curLp != null) { - if (curLp.isIdenticalInterfaceName(newLp)) { - CompareResult car = curLp.compareAddresses(newLp); - if ((car.removed.size() != 0) || (car.added.size() != 0)) { - for (LinkAddress linkAddr : car.removed) { - if (linkAddr.getAddress() instanceof Inet4Address) { - resetMask |= NetworkUtils.RESET_IPV4_ADDRESSES; - } - if (linkAddr.getAddress() instanceof Inet6Address) { - resetMask |= NetworkUtils.RESET_IPV6_ADDRESSES; - } - } - if (DBG) { - log("handleConnectivityChange: addresses changed" + - " linkProperty[" + netType + "]:" + " resetMask=" + resetMask + - "\n car=" + car); - } - } else { - if (VDBG) { - log("handleConnectivityChange: addresses are the same reset per" + - " doReset linkProperty[" + netType + "]:" + - " resetMask=" + resetMask); - } - } - } else { - resetMask = NetworkUtils.RESET_ALL_ADDRESSES; - if (DBG) { - log("handleConnectivityChange: interface not not equivalent reset both" + - " linkProperty[" + netType + "]:" + - " resetMask=" + resetMask); - } - } - } - if (mNetConfigs[netType].isDefault()) { - handleApplyDefaultProxy(newLp.getHttpProxy()); - } - } else { - if (VDBG) { - log("handleConnectivityChange: changed linkProperty[" + netType + "]:" + - " doReset=" + doReset + " resetMask=" + resetMask + - "\n curLp=" + curLp + - "\n newLp= null"); - } - } - mCurrentLinkProperties[netType] = newLp; - boolean resetDns = updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault(), exempt, - mNetTrackers[netType].getNetwork().netId); - - 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) { - 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) { - synchronized(mVpns) { - for (int i = 0; i < mVpns.size(); i++) { - mVpns.valueAt(i).interfaceStatusChanged(iface, false); - } - } - } - } - } 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); - } - } - } - } - - // TODO: Temporary notifying upstread change to Tethering. - // @see bug/4455071 - /** Notify TetheringService if interface name has been changed. */ - if (TextUtils.equals(mNetTrackers[netType].getNetworkInfo().getReason(), - PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) { - if (isTetheringSupported()) { - mTethering.handleTetherIfaceChange(); - } - } - } - - /** - * Add and remove routes using the old properties (null if not previously connected), - * new properties (null if becoming disconnected). May even be double null, which - * is a noop. - * Uses isLinkDefault to determine if default routes should be set or conversely if - * host routes should be set to the dns servers - * returns a boolean indicating the routes changed - */ - private boolean updateRoutes(LinkProperties newLp, LinkProperties curLp, - boolean isLinkDefault, boolean exempt, int netId) { - Collection routesToAdd = null; - CompareResult dnsDiff = new CompareResult(); - CompareResult routeDiff = new CompareResult(); - if (curLp != null) { - // check for the delta between the current set and the new - routeDiff = curLp.compareAllRoutes(newLp); - dnsDiff = curLp.compareDnses(newLp); - } else if (newLp != null) { - routeDiff.added = newLp.getAllRoutes(); - dnsDiff.added = newLp.getDnsServers(); - } - - boolean routesChanged = (routeDiff.removed.size() != 0 || routeDiff.added.size() != 0); - - for (RouteInfo r : routeDiff.removed) { - if (isLinkDefault || ! r.isDefaultRoute()) { - if (VDBG) log("updateRoutes: default remove route r=" + r); - removeRoute(curLp, r, TO_DEFAULT_TABLE, netId); - } - if (isLinkDefault == false) { - // remove from a secondary route table - removeRoute(curLp, r, TO_SECONDARY_TABLE, netId); - } - } - - for (RouteInfo r : routeDiff.added) { - if (isLinkDefault || ! r.isDefaultRoute()) { - addRoute(newLp, r, TO_DEFAULT_TABLE, exempt, netId); - } else { - // add to a secondary route table - 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 - String ifaceName = newLp.getInterfaceName(); - synchronized (mRoutesLock) { - if (!TextUtils.isEmpty(ifaceName) && !mAddedRoutes.contains(r)) { - if (VDBG) log("Removing " + r + " for interface " + ifaceName); - try { - mNetd.removeRoute(netId, r); - } catch (Exception e) { - // never crash - catch them all - if (DBG) loge("Exception trying to remove a route: " + e); - } - } - } - } - } - - return routesChanged; - } - - /** - * Reads the network specific MTU size from reources. - * and set it on it's iface. - */ - 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 + ", " + 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); - } - } - - /** - * 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) { - String key = nt.getTcpBufferSizesPropName(); - String bufferSizes = key == null ? null : SystemProperties.get(key); - - 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 - key = "net.tcp.buffersize.default"; - bufferSizes = SystemProperties.get(key); - } - - // Set values in kernel - if (bufferSizes.length() != 0) { - if (VDBG) { - log("Setting TCP values: [" + bufferSizes - + "] which comes from [" + key + "]"); - } - 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()); - } - } - - /** - * 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 - * - * @param bufferSizes in the format of "readMin, readInitial, readMax, - * writeMin, writeInitial, writeMax" - */ - private void setBufferSize(String bufferSizes) { - try { - String[] values = bufferSizes.split(","); - - if (values.length == 6) { - final String prefix = "/sys/kernel/ipv4/tcp_"; - FileUtils.stringToFile(prefix + "rmem_min", values[0]); - FileUtils.stringToFile(prefix + "rmem_def", values[1]); - FileUtils.stringToFile(prefix + "rmem_max", values[2]); - FileUtils.stringToFile(prefix + "wmem_min", values[3]); - FileUtils.stringToFile(prefix + "wmem_def", values[4]); - FileUtils.stringToFile(prefix + "wmem_max", values[5]); - } else { - loge("Invalid buffersize string: " + bufferSizes); - } - } catch (IOException e) { - loge("Can't set tcp buffer sizes:" + e); - } - } - - /** - * Adjust the per-process dns entries (net.dns.) based - * on the highest priority active net which this process requested. - * If there aren't any, clear it out - */ - private void reassessPidDns(int pid, boolean doBump) - { - if (VDBG) log("reassessPidDns for pid " + pid); - Integer myPid = new Integer(pid); - for(int i : mPriorityList) { - if (mNetConfigs[i].isDefault()) { - continue; - } - NetworkStateTracker nt = mNetTrackers[i]; - if (nt.getNetworkInfo().isConnected() && - !nt.isTeardownRequested()) { - LinkProperties p = nt.getLinkProperties(); - if (p == null) continue; - if (mNetRequestersPids[i].contains(myPid)) { - try { - // 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); - } - return; - } - } - } - // nothing found - delete - try { - // TODO: Reimplement this via local variable in bionic. - // mNetd.clearDnsNetworkForPid(pid); - } catch (Exception e) { - Slog.e(TAG, "exception clear interface from pid: " + e); - } - } - - private void flushVmDnsCache() { - /* - * Tell the VMs to toss their DNS caches - */ - Intent intent = new Intent(Intent.ACTION_CLEAR_DNS_CACHE); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); - /* - * Connectivity events can happen before boot has completed ... - */ - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - final long ident = Binder.clearCallingIdentity(); - try { - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - // Caller must grab mDnsLock. - private void updateDnsLocked(String network, int netId, - Collection dnses, String domains) { - 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()); - } - } - - try { - mNetd.setDnsServersForNetwork(netId, NetworkUtils.makeStrings(dnses), domains); - - 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) { - loge("exception setting default dns interface: " + e); - } - } - - private void handleDnsConfigurationChange(int netType) { - // add default net's dns entries - NetworkStateTracker nt = mNetTrackers[netType]; - if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { - LinkProperties p = nt.getLinkProperties(); - if (p == null) return; - Collection dnses = p.getDnsServers(); - int netId = nt.getNetwork().netId; - if (mNetConfigs[netType].isDefault()) { - String network = nt.getNetworkInfo().getTypeName(); - synchronized (mDnsLock) { - updateDnsLocked(network, netId, dnses, p.getDomains()); - } - } else { - try { - mNetd.setDnsServersForNetwork(netId, - NetworkUtils.makeStrings(dnses), p.getDomains()); - } catch (Exception e) { - 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 { - // TODO: Reimplement this via local variable in bionic. - // mNetd.setDnsNetworkForPid(netId, pid); - } catch (Exception e) { - Slog.e(TAG, "exception setting interface for pid: " + e); - } - } - } - flushVmDnsCache(); - } - } - - @Override - public int getRestoreDefaultNetworkDelay(int networkType) { - String restoreDefaultNetworkDelayStr = SystemProperties.get( - NETWORK_RESTORE_DELAY_PROP_NAME); - if(restoreDefaultNetworkDelayStr != null && - restoreDefaultNetworkDelayStr.length() != 0) { - try { - return Integer.valueOf(restoreDefaultNetworkDelayStr); - } catch (NumberFormatException e) { - } - } - // if the system property isn't set, use the value for the apn type - int ret = RESTORE_DEFAULT_NETWORK_DELAY; - - if ((networkType <= ConnectivityManager.MAX_NETWORK_TYPE) && - (mNetConfigs[networkType] != null)) { - ret = mNetConfigs[networkType].restoreTime; - } - return ret; - } - - @Override - 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) { - pw.println("Permission Denial: can't dump ConnectivityService " + - "from from pid=" + Binder.getCallingPid() + ", uid=" + - Binder.getCallingUid()); - 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) { - pw.println("none"); - } else { - pw.println(defaultNai.network.netId); - } - pw.println(); - - pw.println("Current Networks:"); - pw.increaseIndent(); - 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.decreaseIndent(); - pw.println("Lingered:"); - pw.increaseIndent(); - for (NetworkRequest nr : nai.networkLingered) pw.println(nr.toString()); - pw.decreaseIndent(); - pw.decreaseIndent(); - } - pw.decreaseIndent(); - pw.println(); - - pw.println("Network Requests:"); - pw.increaseIndent(); - for (NetworkRequestInfo nri : mNetworkRequests.values()) { - pw.println(nri.toString()); - } - pw.println(); - pw.decreaseIndent(); - - synchronized (this) { - pw.println("NetworkTranstionWakeLock is currently " + - (mNetTransitionWakeLock.isHeld() ? "" : "not ") + "held."); - pw.println("It was last requested for "+mNetTransitionWakeLockCausedBy); - } - pw.println(); - - mTethering.dump(fd, pw, args); - - 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(); - } - } - - // must be stateless - things change under us. - private class NetworkStateTrackerHandler extends Handler { - public NetworkStateTrackerHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - NetworkInfo info; - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: { - 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 { - if (VDBG) log("Update of Linkproperties for " + nai.name()); - 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 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; - if (score != null) updateNetworkScore(nai, score.intValue()); - break; - } - case NetworkMonitor.EVENT_NETWORK_VALIDATED: { - NetworkAgentInfo nai = (NetworkAgentInfo)msg.obj; - handleConnectionValidated(nai); - break; - } - case NetworkMonitor.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(); - - if (VDBG || (state == NetworkInfo.State.CONNECTED) || - (state == NetworkInfo.State.DISCONNECTED) || - (state == NetworkInfo.State.SUSPENDED)) { - log("ConnectivityChange for " + - info.getTypeName() + ": " + - state + "/" + info.getDetailedState()); - } - - // 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) - && (info.getType() == ConnectivityManager.TYPE_MOBILE)) - || info.isConnectedToProvisioningNetwork())) { - log("ConnectivityChange checkMobileProvisioning for" - + " TYPE_MOBILE or ProvisioningNetwork"); - checkMobileProvisioning(CheckMp.MAX_TIMEOUT_MS); - } - - EventLogTags.writeConnectivityStateChanged( - info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); - - if (info.isConnectedToProvisioningNetwork()) { - /** - * 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 = getLinkPropertiesForTypeInternal(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, - mNetTrackers[info.getType()].getNetwork().netId); - } - } else if (state == NetworkInfo.State.DISCONNECTED) { - } else if (state == NetworkInfo.State.SUSPENDED) { - } else if (state == NetworkInfo.State.CONNECTED) { - // handleConnect(info); - } - if (mLockdownTracker != null) { - mLockdownTracker.onNetworkInfoChanged(info); - } - break; - } - case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: { - info = (NetworkInfo) msg.obj; - // TODO: Temporary allowing network configuration - // change not resetting sockets. - // @see bug/4455071 - handleConnectivityChange(info.getType(), mCurrentLinkProperties[info.getType()], - false); - break; - } - case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: { - info = (NetworkInfo) msg.obj; - int type = info.getType(); - if (mNetConfigs[type].isDefault()) updateNetworkSettings(mNetTrackers[type]); - break; - } - } - } - } - - private void handleAsyncChannelHalfConnect(Message msg) { - AsyncChannel ac = (AsyncChannel) msg.obj; - 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(android.net.NetworkFactory.CMD_REQUEST_NETWORK, - (nai != null ? nai.currentScore : 0), 0, nri.request); - } - } else { - loge("Error connecting NetworkFactory"); - mNetworkFactoryInfos.remove(msg.obj); - } - } 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"); - NetworkAgentInfo nai = mNetworkAgentInfos.remove(msg.replyTo); - if (nai != null) { - mNetworkForNetId.remove(nai.network.netId); - mLegacyTypeTracker.remove(nai); - } - } - } - } - private void handleAsyncChannelDisconnected(Message msg) { - NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo); - if (nai != null) { - 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). - try { - mNetd.removeNetwork(nai.network.netId); - } 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); - updateClat(null, nai.linkProperties, nai); - 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. - 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); - 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); - mActiveDefaultNetwork = ConnectivityManager.TYPE_NONE; - } - for (NetworkAgentInfo networkToActivate : toActivate) { - networkToActivate.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); - } - } - } - - 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.addRequest(nri.request); - mNetworkForRequestId.put(nri.request.requestId, bestNetwork); - int legacyType = nri.request.legacyType; - if (legacyType != TYPE_NONE) { - mLegacyTypeTracker.add(legacyType, bestNetwork); - } - 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 (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(android.net.NetworkFactory.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) { - mNetworkForRequestId.remove(nri.request.requestId); - affectedNetwork.networkRequests.remove(nri.request.requestId); - if (VDBG) { - log(" Removing from current network " + affectedNetwork.name() + ", leaving " + - affectedNetwork.networkRequests.size() + " requests."); - } - } - - if (nri.isRequest) { - for (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(android.net.NetworkFactory.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) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - NetworkInfo info; - switch (msg.what) { - case EVENT_CLEAR_NET_TRANSITION_WAKELOCK: { - String causedBy = null; - synchronized (ConnectivityService.this) { - if (msg.arg1 == mNetTransitionWakeLockSerialNumber && - mNetTransitionWakeLock.isHeld()) { - mNetTransitionWakeLock.release(); - causedBy = mNetTransitionWakeLockCausedBy; - } - } - if (causedBy != null) { - log("NetTransition Wakelock for " + causedBy + " released by timeout"); - } - break; - } - case EVENT_RESTORE_DEFAULT_NETWORK: { - FeatureUser u = (FeatureUser)msg.obj; - u.expire(); - break; - } - case EVENT_INET_CONDITION_CHANGE: { - int netType = msg.arg1; - int condition = msg.arg2; - handleInetConditionChange(netType, condition); - break; - } - case EVENT_INET_CONDITION_HOLD_END: { - int netType = msg.arg1; - int sequence = msg.arg2; - handleInetConditionHoldEnd(netType, sequence); - break; - } - case EVENT_APPLY_GLOBAL_HTTP_PROXY: { - handleDeprecatedGlobalHttpProxy(); - break; - } - case EVENT_SET_DEPENDENCY_MET: { - boolean met = (msg.arg1 == ENABLED); - handleSetDependencyMet(msg.arg2, met); - break; - } - case EVENT_SEND_STICKY_BROADCAST_INTENT: { - Intent intent = (Intent)msg.obj; - sendStickyBroadcast(intent); - break; - } - case EVENT_SET_POLICY_DATA_ENABLE: { - 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; - } - 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); - } - break; - } - case EVENT_SAMPLE_INTERVAL_ELAPSED: { - handleNetworkSamplingTimeout(); - break; - } - case EVENT_PROXY_HAS_CHANGED: { - handleApplyDefaultProxy((ProxyInfo)msg.obj); - break; - } - case EVENT_REGISTER_NETWORK_FACTORY: { - handleRegisterNetworkFactory((NetworkFactoryInfo)msg.obj); - break; - } - case EVENT_UNREGISTER_NETWORK_FACTORY: { - handleUnregisterNetworkFactory((Messenger)msg.obj); - break; - } - case EVENT_REGISTER_NETWORK_AGENT: { - 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; - } - } - } - } - - // javadoc from interface - public int tether(String iface) { - enforceTetherChangePermission(); - - if (isTetheringSupported()) { - return mTethering.tether(iface); - } else { - return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; - } - } - - // javadoc from interface - public int untether(String iface) { - enforceTetherChangePermission(); - - if (isTetheringSupported()) { - return mTethering.untether(iface); - } else { - return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; - } - } - - // javadoc from interface - public int getLastTetherError(String iface) { - enforceTetherAccessPermission(); - - if (isTetheringSupported()) { - return mTethering.getLastTetherError(iface); - } else { - return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; - } - } - - // TODO - proper iface API for selection by property, inspection, etc - public String[] getTetherableUsbRegexs() { - enforceTetherAccessPermission(); - if (isTetheringSupported()) { - return mTethering.getTetherableUsbRegexs(); - } else { - return new String[0]; - } - } - - public String[] getTetherableWifiRegexs() { - enforceTetherAccessPermission(); - if (isTetheringSupported()) { - return mTethering.getTetherableWifiRegexs(); - } else { - return new String[0]; - } - } - - public String[] getTetherableBluetoothRegexs() { - enforceTetherAccessPermission(); - if (isTetheringSupported()) { - return mTethering.getTetherableBluetoothRegexs(); - } else { - return new String[0]; - } - } - - public int setUsbTethering(boolean enable) { - enforceTetherChangePermission(); - if (isTetheringSupported()) { - return mTethering.setUsbTethering(enable); - } else { - return ConnectivityManager.TETHER_ERROR_UNSUPPORTED; - } - } - - // TODO - move iface listing, queries, etc to new module - // javadoc from interface - public String[] getTetherableIfaces() { - enforceTetherAccessPermission(); - return mTethering.getTetherableIfaces(); - } - - public String[] getTetheredIfaces() { - enforceTetherAccessPermission(); - return mTethering.getTetheredIfaces(); - } - - public String[] getTetheringErroredIfaces() { - enforceTetherAccessPermission(); - return mTethering.getErroredIfaces(); - } - - // if ro.tether.denied = true we default to no tethering - // gservices could set the secure setting to 1 though to enable it on a build where it - // had previously been turned off. - public boolean isTetheringSupported() { - enforceTetherAccessPermission(); - 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 && ((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. - // This will automatically be cleared after X seconds or a network becomes CONNECTED, - // whichever happens first. The timer is started by the first caller and not - // restarted by subsequent callers. - public void requestNetworkTransitionWakelock(String forWhom) { - enforceConnectivityInternalPermission(); - synchronized (this) { - if (mNetTransitionWakeLock.isHeld()) return; - mNetTransitionWakeLockSerialNumber++; - mNetTransitionWakeLock.acquire(); - mNetTransitionWakeLockCausedBy = forWhom; - } - mHandler.sendMessageDelayed(mHandler.obtainMessage( - EVENT_CLEAR_NET_TRANSITION_WAKELOCK, - mNetTransitionWakeLockSerialNumber, 0), - mNetTransitionWakeLockTimeout); - return; - } - - // 100 percent is full good, 0 is full bad. - public void reportInetCondition(int networkType, int percentage) { - if (VDBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")"); - mContext.enforceCallingOrSelfPermission( - android.Manifest.permission.STATUS_BAR, - "ConnectivityService"); - - if (DBG) { - int pid = getCallingPid(); - int uid = getCallingUid(); - String s = pid + "(" + uid + ") reports inet is " + - (percentage > 50 ? "connected" : "disconnected") + " (" + percentage + ") on " + - "network Type " + networkType + " at " + GregorianCalendar.getInstance().getTime(); - mInetLog.add(s); - while(mInetLog.size() > INET_CONDITION_LOG_MAX_SIZE) { - mInetLog.remove(0); - } - } - mHandler.sendMessage(mHandler.obtainMessage( - 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"); - return; - } - if (mActiveDefaultNetwork != netType) { - if (DBG) log("handleInetConditionChange: net=" + netType + - " != default=" + mActiveDefaultNetwork + " - ignore"); - return; - } - if (VDBG) { - log("handleInetConditionChange: net=" + - netType + ", condition=" + condition + - ",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) { - delay = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.INET_CONDITION_DEBOUNCE_UP_DELAY, 500); - } else { - 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, - 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) { - if (DBG) { - log("handleInetConditionHoldEnd: net=" + netType + - ", condition=" + mDefaultInetCondition + - ", published condition=" + mDefaultInetConditionPublished); - } - mInetConditionChangeInFlight = false; - - if (mActiveDefaultNetwork == -1) { - if (DBG) log("handleInetConditionHoldEnd: no active default network - ignoring"); - return; - } - if (mDefaultConnectionSequence != sequence) { - 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 = getNetworkInfoForType(mActiveDefaultNetwork); - if (networkInfo.isConnected() == false) { - if (DBG) log("handleInetConditionHoldEnd: default network not connected - ignoring"); - return; - } - mDefaultInetConditionPublished = mDefaultInetCondition; - sendInetConditionBroadcast(networkInfo); - return; - } - - 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) { - ProxyInfo ret = mGlobalProxy; - if ((ret == null) && !mDefaultProxyDisabled) ret = mDefaultProxy; - return ret; - } - } - - public void setGlobalProxy(ProxyInfo proxyProperties) { - enforceConnectivityInternalPermission(); - - synchronized (mProxyLock) { - if (proxyProperties == mGlobalProxy) return; - if (proxyProperties != null && proxyProperties.equals(mGlobalProxy)) return; - if (mGlobalProxy != null && mGlobalProxy.equals(proxyProperties)) return; - - String host = ""; - int port = 0; - String exclList = ""; - String pacFileUrl = ""; - if (proxyProperties != null && (!TextUtils.isEmpty(proxyProperties.getHost()) || - (proxyProperties.getPacFileUrl() != null))) { - if (!proxyProperties.isValid()) { - if (DBG) - log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); - return; - } - mGlobalProxy = new ProxyInfo(proxyProperties); - host = mGlobalProxy.getHost(); - port = mGlobalProxy.getPort(); - exclList = mGlobalProxy.getExclusionListAsString(); - if (proxyProperties.getPacFileUrl() != null) { - pacFileUrl = proxyProperties.getPacFileUrl().toString(); - } - } else { - mGlobalProxy = null; - } - ContentResolver res = mContext.getContentResolver(); - 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); - Settings.Global.putString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC, pacFileUrl); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - if (mGlobalProxy == null) { - proxyProperties = mDefaultProxy; - } - sendProxyBroadcast(proxyProperties); - } - - private void loadGlobalProxy() { - ContentResolver res = mContext.getContentResolver(); - 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); - String pacFileUrl = Settings.Global.getString(res, Settings.Global.GLOBAL_HTTP_PROXY_PAC); - if (!TextUtils.isEmpty(host) || !TextUtils.isEmpty(pacFileUrl)) { - ProxyInfo proxyProperties; - if (!TextUtils.isEmpty(pacFileUrl)) { - proxyProperties = new ProxyInfo(pacFileUrl); - } else { - proxyProperties = new ProxyInfo(host, port, exclList); - } - if (!proxyProperties.isValid()) { - if (DBG) log("Invalid proxy properties, ignoring: " + proxyProperties.toString()); - return; - } - - synchronized (mProxyLock) { - mGlobalProxy = proxyProperties; - } - } - } - - 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. - // enforceAccessPermission(); - synchronized (mProxyLock) { - return mGlobalProxy; - } - } - - private void handleApplyDefaultProxy(ProxyInfo proxy) { - if (proxy != null && TextUtils.isEmpty(proxy.getHost()) - && (proxy.getPacFileUrl() == null)) { - proxy = null; - } - synchronized (mProxyLock) { - if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return; - if (mDefaultProxy == proxy) return; // catches repeated nulls - if (proxy != null && !proxy.isValid()) { - 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; - if (!mDefaultProxyDisabled) { - sendProxyBroadcast(proxy); - } - } - } - - private void handleDeprecatedGlobalHttpProxy() { - String proxy = Settings.Global.getString(mContext.getContentResolver(), - 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) { - try { - proxyPort = Integer.parseInt(data[1]); - } catch (NumberFormatException e) { - return; - } - } - ProxyInfo p = new ProxyInfo(data[0], proxyPort, ""); - setGlobalProxy(p); - } - } - - 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); - intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING | - Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - intent.putExtra(Proxy.EXTRA_PROXY_INFO, proxy); - final long ident = Binder.clearCallingIdentity(); - try { - mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); - } finally { - Binder.restoreCallingIdentity(ident); - } - } - - private static class SettingsObserver extends ContentObserver { - private int mWhat; - private Handler mHandler; - SettingsObserver(Handler handler, int what) { - super(handler); - mHandler = handler; - mWhat = what; - } - - void observe(Context context) { - ContentResolver resolver = context.getContentResolver(); - resolver.registerContentObserver(Settings.Global.getUriFor( - Settings.Global.HTTP_PROXY), false, this); - } - - @Override - public void onChange(boolean selfChange) { - mHandler.obtainMessage(mWhat).sendToTarget(); - } - } - - private static void log(String s) { - Slog.d(TAG, s); - } - - private static void loge(String s) { - Slog.e(TAG, s); - } - - int convertFeatureToNetworkType(int networkType, String feature) { - int usedNetworkType = networkType; - - if(networkType == ConnectivityManager.TYPE_MOBILE) { - if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_MMS; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_SUPL; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) || - TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_FOTA; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_IMS; - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) { - usedNetworkType = ConnectivityManager.TYPE_MOBILE_CBS; - } else { - Slog.e(TAG, "Can't match any mobile netTracker!"); - } - } else if (networkType == ConnectivityManager.TYPE_WIFI) { - if (TextUtils.equals(feature, "p2p")) { - usedNetworkType = ConnectivityManager.TYPE_WIFI_P2P; - } else { - Slog.e(TAG, "Can't match any wifi netTracker!"); - } - } else { - Slog.e(TAG, "Unexpected network type"); - } - return usedNetworkType; - } - - private static T checkNotNull(T value, String message) { - if (value == null) { - throw new NullPointerException(message); - } - return value; - } - - /** - * Protect a socket from VPN routing rules. This method is used by - * VpnBuilder and not available in ConnectivityManager. Permissions - * are checked in Vpn class. - * @hide - */ - @Override - public boolean protectVpn(ParcelFileDescriptor socket) { - throwIfLockdownEnabled(); - try { - int type = mActiveDefaultNetwork; - int user = UserHandle.getUserId(Binder.getCallingUid()); - if (ConnectivityManager.isNetworkTypeValid(type) && mNetTrackers[type] != null) { - synchronized(mVpns) { - mVpns.get(user).protect(socket); - } - return true; - } - } catch (Exception e) { - // ignore - } finally { - try { - socket.close(); - } catch (Exception e) { - // ignore - } - } - return false; - } - - /** - * Prepare for a VPN application. This method is used by VpnDialogs - * and not available in ConnectivityManager. Permissions are checked - * in Vpn class. - * @hide - */ - @Override - public boolean prepareVpn(String oldPackage, String newPackage) { - throwIfLockdownEnabled(); - int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized(mVpns) { - return mVpns.get(user).prepare(oldPackage, newPackage); - } - } - - @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 - * and not available in ConnectivityManager. Permissions are checked in - * Vpn class. - * @hide - */ - @Override - public ParcelFileDescriptor establishVpn(VpnConfig config) { - throwIfLockdownEnabled(); - int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized(mVpns) { - return mVpns.get(user).establish(config); - } - } - - /** - * Start legacy VPN, controlling native daemons as needed. Creates a - * secondary thread to perform connection work, returning quickly. - */ - @Override - public void startLegacyVpn(VpnProfile profile) { - throwIfLockdownEnabled(); - final LinkProperties egress = getActiveLinkProperties(); - if (egress == null) { - throw new IllegalStateException("Missing active network connection"); - } - int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized(mVpns) { - mVpns.get(user).startLegacyVpn(profile, mKeyStore, egress); - } - } - - /** - * Return the information of the ongoing legacy VPN. This method is used - * by VpnSettings and not available in ConnectivityManager. Permissions - * are checked in Vpn class. - * @hide - */ - @Override - public LegacyVpnInfo getLegacyVpnInfo() { - throwIfLockdownEnabled(); - int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized(mVpns) { - return mVpns.get(user).getLegacyVpnInfo(); - } - } - - /** - * 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 - * needs to override DNS servers but never takes the default routes. It - * relies on another data network, and it could keep existing connections - * alive after reconnecting, switching between networks, or even resuming - * from deep sleep. Calls from applications should be done synchronously - * to avoid race conditions. As these are all hidden APIs, refactoring can - * be done whenever a better abstraction is developed. - */ - public class VpnCallback { - private VpnCallback() { - } - - public void onStateChanged(NetworkInfo info) { - mHandler.obtainMessage(EVENT_VPN_STATE_CHANGED, info).sendToTarget(); - } - - public void override(String iface, List dnsServers, List searchDomains) { - if (dnsServers == null) { - restore(); - return; - } - - // Convert DNS servers into addresses. - List addresses = new ArrayList(); - for (String address : dnsServers) { - // Double check the addresses and remove invalid ones. - try { - addresses.add(InetAddress.parseNumericAddress(address)); - } catch (Exception e) { - // ignore - } - } - if (addresses.isEmpty()) { - restore(); - return; - } - - // Concatenate search domains into a string. - StringBuilder buffer = new StringBuilder(); - if (searchDomains != null) { - for (String domain : searchDomains) { - buffer.append(domain).append(' '); - } - } - String domains = buffer.toString().trim(); - - // Apply DNS changes. - synchronized (mDnsLock) { - // TODO: Re-enable this when the netId of the VPN is known. - // updateDnsLocked("VPN", netId, addresses, domains); - } - - // Temporarily disable the default proxy (not global). - synchronized (mProxyLock) { - mDefaultProxyDisabled = true; - if (mGlobalProxy == null && mDefaultProxy != null) { - sendProxyBroadcast(null); - } - } - - // TODO: support proxy per network. - } - - public void restore() { - synchronized (mProxyLock) { - mDefaultProxyDisabled = false; - if (mGlobalProxy == null && mDefaultProxy != null) { - sendProxyBroadcast(mDefaultProxy); - } - } - } - - 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, boolean forwardDns) { - int uidStart = uid * UserHandle.PER_USER_RANGE; - int uidEnd = uidStart + UserHandle.PER_USER_RANGE - 1; - addUidForwarding(interfaze, uidStart, uidEnd, forwardDns); - } - - 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, forwardDns); - } - - public void addUidForwarding(String interfaze, int uidStart, int uidEnd, - boolean forwardDns) { - // 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) { - // TODO: Re-enable this when the netId of the VPN is known. - // try { - // mNetd.clearUidRangeRoute(interfaze, uidStart, uidEnd); - // } catch (RemoteException e) { - // } - - } - } - - @Override - public boolean updateLockdownVpn() { - 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(); - if (mLockdownEnabled) { - if (!mKeyStore.isUnlocked()) { - 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)); - int user = UserHandle.getUserId(Binder.getCallingUid()); - synchronized(mVpns) { - setLockdownTracker(new LockdownVpnTracker(mContext, mNetd, this, mVpns.get(user), - 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); - mNetd.setFirewallInterfaceRule("lo", 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"); - } - } - - public void supplyMessenger(int networkType, Messenger messenger) { - enforceConnectivityInternalPermission(); - - if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) { - 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; - } - - /** - * 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)); - } - - 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. - * This is NOT a warm sim. - */ - 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. - */ - 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 NOT a warm sim since provisioning network is supported. - */ - private static final int CMP_RESULT_CODE_NO_DNS = 2; - - /** - * A connection was made but could not open a TCP connection. - * This is NOT a warm sim since provisioning network is supported. - */ - 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 such as AT&T. - */ - 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 - 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 mobile notification off - setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); - - CheckMp checkMp = new CheckMp(mContext, this); - CheckMp.CallBack cb = new CheckMp.CallBack() { - @Override - void onComplete(Integer result) { - if (DBG) log("CheckMp.onComplete: result=" + result); - NetworkInfo ni = - mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI].getNetworkInfo(); - switch(result) { - case CMP_RESULT_CODE_CONNECTABLE: - 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; - } - 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) { - if (DBG) log("CheckMp.onComplete: warm (redirected), url=" + url); - setProvNotificationVisible(true, - ConnectivityManager.TYPE_MOBILE_HIPRI, ni.getExtraInfo(), - url); - } else { - if (DBG) log("CheckMp.onComplete: warm (redirected), no url"); - } - break; - } - 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); - 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]; - - // Disable radio until user starts provisioning - mdst.setRadio(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; - } - } - mIsCheckingMobileProvisioning.set(false); - } - }; - CheckMp.Params params = - new CheckMp.Params(checkMp.getDefaultUrl(), timeOutMs, cb); - if (DBG) log("checkMobileProvisioning: params=" + 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"); - } - return timeOutMs; - } - - 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; - 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 + "}"; - } - } - - // 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. - */ - abstract static class CallBack { - // Called on the main thread. - abstract void onComplete(Integer result); - } - - 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; - - // 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 = CMP_RESULT_CODE_NO_CONNECTION; - Uri orgUri = Uri.parse(params.mUrl); - Random rand = new Random(); - mParams = params; - - if (mCs.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false) { - result = CMP_RESULT_CODE_NO_CONNECTION; - log("isMobileOk: X not mobile capable result=" + result); - 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) - 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; - } - - try { - // 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(POLLING_SLEEP_SEC); - } - } - - log("isMobileOk: start hipri url=" + params.mUrl); - - // 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 = CMP_RESULT_CODE_NO_CONNECTION; - sleep(POLLING_SLEEP_SEC); - } - - // Continue trying to connect until time has run out - 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) { - if (true/*VDBG*/) { - log("isMobileOk: not connected ni=" + - mCs.getNetworkInfo(ConnectivityManager.TYPE_MOBILE_HIPRI)); - } - sleep(POLLING_SLEEP_SEC); - 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()) { - 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"); - } - - // 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 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) { - result = CMP_RESULT_CODE_NO_DNS; - log("isMobileOk: X UnknownHostException result=" + result); - return result; - } - log("isMobileOk: addresses=" + inetAddressesToString(addresses)); - - // Get the type of addresses supported by this link - LinkProperties lp = mCs.getLinkPropertiesForTypeInternal( - ConnectivityManager.TYPE_MOBILE_HIPRI); - boolean linkHasIpv4 = lp.hasIPv4Address(); - boolean linkHasIpv6 = lp.hasIPv6Address(); - log("isMobileOk: linkHasIpv4=" + linkHasIpv4 - + " linkHasIpv6=" + linkHasIpv6); - - final ArrayList validAddresses = - new ArrayList(addresses.length); - - 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 MAX_LOOPS valid addresses or until - // we run out of time - if (addrTried++ >= MAX_LOOPS) { - log("isMobileOk: too many loops tried - giving up"); - break; - } - if (SystemClock.elapsedRealtime() >= endTime) { - log("isMobileOk: 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, - hostAddr.getAddress(), null)) { - // Wait a short time to be sure the route is established ?? - log("isMobileOk:" - + " wait to establish route to hostAddr=" + hostAddr); - 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 - // 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 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); - 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(); - - // For debug display the headers - Map> headers = urlConn.getHeaderFields(); - log("isMobileOk: headers=" + headers); - - // Close the connection - 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 got expected responseCode=" + responseCode - + " result=" + result); - 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); - // 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) { - 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); - 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); - - // 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(POLLING_SLEEP_SEC); - continue; - } - } - - 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) { - long stopTime = System.nanoTime() + (seconds * 1000000000); - long sleepTime; - while ((sleepTime = stopTime - System.nanoTime()) > 0) { - try { - Thread.sleep(sleepTime / 1000000); - } catch (InterruptedException ignored) { - } - } - } - - private static void log(String s) { - Slog.d(ConnectivityService.TAG, "[" + CHECKMP_TAG + "] " + s); - } - } - - // 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 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) { - // Mark notification as not visible - setProvNotificationVisible(false, ConnectivityManager.TYPE_MOBILE_HIPRI, null, null); - - // 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() && !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"); - mIsProvisioningNetwork.set(false); - // 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); - } - } - } - } - - 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 - .getSystemService(Context.NOTIFICATION_SERVICE); - - if (visible) { - CharSequence title; - CharSequence details; - int icon; - Intent intent; - Notification notification = new Notification(); - switch (networkType) { - case ConnectivityManager.TYPE_WIFI: - title = r.getString(R.string.wifi_available_sign_in, 0); - details = r.getString(R.string.network_available_sign_in_detailed, - 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: - 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: - title = r.getString(R.string.network_available_sign_in, 0); - details = r.getString(R.string.network_available_sign_in_detailed, - 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.when = 0; - notification.icon = icon; - notification.flags = Notification.FLAG_AUTO_CANCEL; - notification.tickerText = title; - notification.setLatestEventInfo(mContext, title, details, notification.contentIntent); - - try { - notificationManager.notify(NOTIFICATION_ID, networkType, notification); - } catch (NullPointerException npe) { - loge("setNotificaitionVisible: visible notificationManager npe=" + npe); - npe.printStackTrace(); - } - } else { - try { - notificationManager.cancel(NOTIFICATION_ID, networkType); - } catch (NullPointerException npe) { - loge("setNotificaitionVisible: cancel notificationManager npe=" + npe); - npe.printStackTrace(); - } - } - mIsNotificationVisible = visible; - } - - /** 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; - } - - @Override - public String getMobileRedirectedProvisioningUrl() { - enforceConnectivityInternalPermission(); - String url = getProvisioningUrlBaseFromFile(REDIRECTED_PROVISIONING); - if (TextUtils.isEmpty(url)) { - url = mContext.getResources().getString(R.string.mobile_redirected_provisioning_url); - } - 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("getMobileProvisioningUrl: mobile_provisioining_url from resource =" + url); - } else { - log("getMobileProvisioningUrl: 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(); - if (TextUtils.isEmpty(phoneNumber)) { - phoneNumber = "0000000000"; - } - url = String.format(url, - mTelephonyManager.getSimSerialNumber() /* ICCID */, - mTelephonyManager.getDeviceId() /* IMEI */, - phoneNumber /* Phone numer */); - } - - return url; - } - - @Override - public void setProvisioningNotificationVisible(boolean visible, int networkType, - String extraInfo, String url) { - enforceConnectivityInternalPermission(); - setProvNotificationVisible(visible, networkType, extraInfo, url); - } - - @Override - public void setAirplaneMode(boolean enable) { - enforceConnectivityInternalPermission(); - 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); - } - } - - 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); - } - } - }; - - @Override - public LinkQualityInfo getLinkQualityInfo(int networkType) { - enforceAccessPermission(); - if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) { - return mNetTrackers[networkType].getLinkQualityInfo(); - } else { - return null; - } - } - - @Override - public LinkQualityInfo getActiveLinkQualityInfo() { - enforceAccessPermission(); - if (isNetworkTypeValid(mActiveDefaultNetwork) && - mNetTrackers[mActiveDefaultNetwork] != null) { - return mNetTrackers[mActiveDefaultNetwork].getLinkQualityInfo(); - } else { - return null; - } - } - - @Override - public LinkQualityInfo[] getAllLinkQualityInfo() { - enforceAccessPermission(); - final ArrayList result = Lists.newArrayList(); - for (NetworkStateTracker tracker : mNetTrackers) { - if (tracker != null) { - LinkQualityInfo li = tracker.getLinkQualityInfo(); - if (li != null) { - result.add(li); - } - } - } - - return result.toArray(new LinkQualityInfo[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); - } - - 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; - 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); - } - - public String toString() { - return (isRequest ? "Request" : "Listen") + " from uid/pid:" + mUid + "/" + - mPid + " for " + request; - } - } - - @Override - public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities, - Messenger messenger, int timeoutSec, IBinder binder, int legacyType) { - 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), legacyType, nextNetworkRequestId()); - 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), TYPE_NONE, nextNetworkRequestId()); - 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, String name) { - enforceConnectivityInternalPermission(); - NetworkFactoryInfo nfi = new NetworkFactoryInfo(name, messenger, new AsyncChannel()); - mHandler.sendMessage(mHandler.obtainMessage(EVENT_REGISTER_NETWORK_FACTORY, nfi)); - } - - 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); - } - - /** - * 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(); - - 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 = - 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, mContext, mTrackerHandler); - if (VDBG) log("registerNetworkAgent " + nai); - 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); - mNetworkForNetId.put(na.network.netId, 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; - - updateInterfaces(newLp, oldLp, 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); - 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 (na.networkInfo.isConnected()) { - mClat.startClat(na); - } else { - mClat.stopClat(); - } - } - } - - 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) { - 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.getDnsServers(); - 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); - } - 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? - // 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 (NetworkFactoryInfo nfi : mNetworkFactoryInfos.values()) { - nfi.asyncChannel.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK, score, 0, - networkRequest); - } - } - - private void callCallbackForRequest(NetworkRequestInfo nri, - NetworkAgentInfo networkAgent, int notificationType) { - 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) { - 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 - 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 - if (VDBG) { - log("currentScore = " + - (currentNetwork != null ? currentNetwork.currentScore : 0) + - ", newScore = " + newNetwork.currentScore); - } - if (currentNetwork == null || - currentNetwork.currentScore < newNetwork.currentScore) { - if (currentNetwork != null) { - 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(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 - // netid->request mapping to each factory? - sendUpdatedScoreToFactories(nri.request, newNetwork.currentScore); - if (mDefaultRequest.requestId == nri.request.requestId) { - isNewDefault = true; - updateActiveDefaultNetwork(newNetwork); - if (newNetwork.linkProperties != null) { - setDefaultDnsSystemProperties( - newNetwork.linkProperties.getDnsServers()); - } else { - setDefaultDnsSystemProperties(new ArrayList()); - } - mLegacyTypeTracker.add(newNetwork.networkInfo.getType(), 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); - 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 { - BatteryStatsService.getService().noteNetworkInterfaceType( - newNetwork.linkProperties.getInterfaceName(), - newNetwork.networkInfo.getType()); - } catch (RemoteException e) { } - 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(); - } - } - - - 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) { - 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 + ": " - + e.getMessage()); - return; - } - - updateLinkProperties(networkAgent, null); - notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_PRECHECK); - networkAgent.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED); - } else if (state == NetworkInfo.State.DISCONNECTED || - state == NetworkInfo.State.SUSPENDED) { - networkAgent.asyncChannel.disconnect(); - } - } - - 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 - 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); -// } - 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++) { - NetworkRequest nr = networkAgent.networkRequests.valueAt(i); - NetworkRequestInfo nri = mNetworkRequests.get(nr); - if (VDBG) log(" sending notification for " + nr); - callCallbackForRequest(nri, networkAgent, notifyType); - } - } - - private LinkProperties getLinkPropertiesForTypeInternal(int networkType) { - NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); - return (nai != null) ? - new LinkProperties(nai.linkProperties) : - new LinkProperties(); - } - - private NetworkInfo getNetworkInfoForType(int networkType) { - 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) { - NetworkAgentInfo nai = mLegacyTypeTracker.getNetworkForType(networkType); - return (nai != null) ? - new NetworkCapabilities(nai.networkCapabilities) : - new NetworkCapabilities(); - } -} diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java deleted file mode 100644 index 096ab66b42..0000000000 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ /dev/null @@ -1,219 +0,0 @@ -/* - * 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.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; - -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; - // 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"; - - 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(); - - // 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. - } - - /** - * 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(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()); - 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. - */ - 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; - } - 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; - mNetworkMessenger = null; - mBaseLP = null; - mLP.clear(); - } else { - Slog.e(TAG, "stopClat: already stopped"); - } - } - - public boolean isStarted() { - return mIsStarted; - } - - public boolean isRunning() { - 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)) { - Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + - " added, mIsRunning = " + mIsRunning + " -> true"); - mIsRunning = true; - - // 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), - clatAddress.getAddress(), iface); - mLP.addRoute(ipv4Default); - mLP.addLinkAddress(clatAddress); - mBaseLP.addStackedLink(mLP); - Slog.i(TAG, "Adding stacked link. tracker LP: " + mBaseLP); - updateConnectivityService(); - } catch(RemoteException e) { - Slog.e(TAG, "Error getting link properties: " + e); - } - } - } - - @Override - public void interfaceRemoved(String iface) { - if (iface == CLAT_INTERFACE_NAME) { - if (mIsRunning) { - 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; - mLP.clear(); - Slog.i(TAG, "mLP = " + mLP); - } - } -}; diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java deleted file mode 100644 index b03c247e80..0000000000 --- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java +++ /dev/null @@ -1,83 +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 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; - -/** - * 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; - public final NetworkMonitor networkMonitor; - - // The list of NetworkRequests being satisfied by this Network. - public final SparseArray networkRequests = new SparseArray(); - public final ArrayList networkLingered = 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, Context context, - Handler handler) { - this.messenger = messenger; - asyncChannel = ac; - network = new Network(netId); - networkInfo = info; - linkProperties = lp; - networkCapabilities = nc; - currentScore = score; - networkMonitor = new NetworkMonitor(context, handler, this); - } - - public void addRequest(NetworkRequest networkRequest) { - networkRequests.put(networkRequest.requestId, networkRequest); - } - - public String toString() { - return "NetworkAgentInfo{ ni{" + networkInfo + "} network{" + - network + "} lp{" + - linkProperties + "} nc{" + - networkCapabilities + "} Score{" + currentScore + "} }"; - } - - public String name() { - return "NetworkAgentInfo [" + networkInfo.getTypeName() + " (" + - networkInfo.getSubtypeName() + ")]"; - } -} diff --git a/services/tests/servicestests/res/raw/netstats_uid_v4 b/services/tests/servicestests/res/raw/netstats_uid_v4 deleted file mode 100644 index e75fc1ca5c2e6c01a907792cc88faeddce61f1e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 156516 zcmeFacR*D~)&Ty_-10g_id~5%pot|ho0w{{>4|Yo*=%+fl=8B^N9s9dbYKkj~#%)a_nt4EXQ7$#~i@z z=}};aDdEiV0}q-K<8CR$4j3#4>@3F`Yr>un23NMw3Si-q;5A!XRPW3xoAhInV|O zV^15nAa1mOu+403x9JQwgd7Q@Aolnc%nbau;jn@)F=|EAQUx1^Sl>2cYeVcrjK7Bw zJ-iva`sPf`>?-I?G3&|rhYmACKW^a{B# z$ev&kMw=OWtS#s*6YA)h1zRh~ge@xtTk^4T_QnELE?Bnh4f#{{Hjiw@?K=*_*xSjh z0qv^~Cnh`DqMNxsCVE!3fufU>vCd%1XHw1I@%l28Xqdb%(>}&_w6lJk$vA*3mSdua z5?6XVS}@av7kh3i%rlDIY=xOjVeD)JZ%f-_amsS;Yx}hotnL4aWi-Eu@uwJJ+p|Hc zQZ4z**YcpZqXloo)e@BDTGFhX8Lsx$Z#vBgT)bFzwwA-jzMb{K{<0T0)^4sZ*)=Ix zVC<2_SbZEQ2Pljk<*+ukw+&eTFvyYgXHK$q^7f&rc9t_DA0-{!r_hBY2n|T-wBSVU=kY=3JDSSTeS9wv0CRNC~4T*gPe6@+t9o z`s&xGM5YFqb5~|!PO^4l1;ZG-NP;8l0F0g8%Sgh4w5|1FZ9r#hJ4oEy0)u7QQx0&c zz-|~ja2sL$(u{8X8s*Va%E+hFTG^|gIKnKk9F?7V5Mz9HGG!(-U|BTS+FOnYSB_W> z|3gffQS5(!`Wza8*lw0!YyU7ha9}c1**BRvGRZj19aMI5AqRwACLr6}){e{)2xBkz zW_{|&EMX^%BSJM}+;%Dnj#!+r9D5CBXhF9GTgMN=*xNr27#bb2;5Z;eJ7T?XNb%!y zmKSSo8{3-WW+&}nId)obMimJeveqLm&6%IsSRaRs)M(hY1Y66QZvmiZTVWird0Jqw zI9tp4n7(W8_(2#;u(cd!{i8tmzP&J5maQ<@*7nxNVwprZTg$P)*kjFnA1h)G_LPJ3 zsXgT|I-oH2)CY01x80^AjGe{^gi+ZEL#tvpZU|!uwzf5^j~U1w7)Q#n*RaZPv(I?R z`RF6|X}C;An(u%XNntS9+HOo=Z~!-4@U%mVF*DGitWdfkUdMBWk@xg#CY8>~%y8Vf6O@z9{C9y6uQLgwd!2 z_4yAtZ!+?cA|s0VUKG;yNrE+^oi1Jjeu6AzYcuQ3+Ou>@P`f{j5wSJ{l41;(EKLO)U(gew@a z%m4n9FGmCe#0?iFFxXm-1;(EG%;!beRgMD-uijV{dl#%7ndGrP_Kw@pCV7piFXYMS>1!C-Az?AuI;>b@Ilk6mGOrjG=*K)G? zA#?0CDZrmnGQ!ywD;3-yPrnFd|*a+j$0@HL$A@r;) z=YON}Y|x`I!`_}pDe^zzEyg&2xdD`wHz!#;-E(um_icq?RB5O5&1Me=a6=F~aAUI| z_K&5HRH~m*lPm6pU`=0;%)8E%UQVS3i-G9V)L_Al6a$01nUO-;S3rUvFW4(zJ1>?W zqIs#Lkn)FGC$vtuI{xZ-yzLXHfdZMXl=`~jjJd=bj%H7s$5UqjfZK0 zkT#4ZLh~NBA;s+kOAE6tn&=Z2@D-Knzqj#?CKQO~&NyglxUU<;<$=cXjgNI_f4(LA z4O)u0^2XF{!;^ZCM1ubieord4h<(C&mso5c@xpC&TDDxi+vDbKBi_f!@#00d-N@8X z;-O(wCT5|C>stn>IV-<=h{kI|>S`Y})tA+?rF1F(%Gmk~hL)2*t{wj6w*Jp(ZcPOklh>%WvBHlrWDIPLap!!MWxQSGM|L5mbzJ(QCt+4zom=3PLO4B*ByOEtvSso(}Q&jaqI^y`a<4iECuIs)r=oGR% zP#7#p7VhpY7B*L>3N^chhN=KqcJ1}-BtuH*i#tzq0Vmz`mburz+M{nQ{sntUguqvba1Grg1 zvnHgABI{p%p2oX}`|csmdE96u!>eT*fwH1Z_yS4VCyMaYW-EPU1Le0XYcMmK)nyafg z@%ARuJo(>( z=2@Kb-7fxlU~J2{onu#ak^WZqoiLy~<+(K&Ho6^|RR4L!xQKs-%O_ke%{e+7U;d}( zIFBeHY#h}ZXO080A74+5|MC>TU7lVy-#b7wZNSJS6GJk4EA%XzT z7o-GEBdwV4FefhC;1vx@G%PdOe?+zsuF}%&Yz!{DFuX@%Zcegx;;TCLSx6Xemdunb zq_)B$M+{>o4>DFr!PQL%2FcZm5Mh6PBcVf?vb{T{Um~x=hrSEC(xLk(383;{uH?%G zwEGLofq;NTstccLN{9M5C=r*5Ly{lP#Okq&p0Yfqw>&uH9l*GiIRj+{J^$C(!2fLK z@Z6S=0Dd{ef~jPyu#6sfM$WMPS{g)d2!+dM2FSsE$-;#?I>p;tos$*xGU`&R+KzCAJYM}DP{(?t$vOKo?^=9NUx)%@sB(zXC zP(&`}k)!`e9ui_MoFwmNN#FU+cfR;&UKX5TB`oro zLSG$AE!cG4Hy{|L4a)90gRvr!us3Xo{!fxZ$M!6^yPcDOk`!|8a8f8Jp>zFZP6}I2 zr3%Blg`6QKWTb916sOIJOj;-O_-|pPP*r3RGCV^|#<#qn_n#D4B6gO_ewnarM)eOGOtA0Pf^J`9&Pq5I#d;xWYz}$q*(OplHh^g2 zVe=2trUbb9l62`P%uNA*k~cZbErLX_Ud`%MSL_q6rjQlCSsw$d3e-VakUYgy2P;EJ zc@0EghtrF0K6XfROi$s{q`?E}z%(lq|EvZ+eORH0|H1UZOu<%!RI3Q^#Cu8t-YSVqA>6kwL$L*pG@?8P zeb~e}<>RS_#gs#uJ!`yZ;;8wAcVGb!`x}fWVPs<30uC9>hXu=p5*N!eE9ZL>AwIJe z20I0fI2i1O`MMMdeBz-wK^apZp&rE*V2W8HIz0eW)o8sO@qXjq{7_uKUam#M=E5HH z4L4b2Rnad>ioIom!pP6Lgeq*fkfg-}3Zi zX<9<4h;pw~`e;N8SxQx?QD2q1>YTvELvx|m-d3qH&^km53zahdYp4cpZ70586#jc)IW~mL><~kc;Nt4~@N`$0{K}7g zW}C3#T{1q}vQOQ*hBVCCI{Wm40Y7d2e#5jNDdv?k+hJ!H9R2;8FD`Z>!*qE*P``&v znKbd0h2w;W{t^iq31Y8%k4y-Dq{Aj5z764r_j4}mAO;Zl>YadUPf^YmDHUVU*>i# zF5;H-e@6AQOT9@D-u{cteWzHrnN~l1?xpgFRxQ~5@SPW1C!C+ZV#>*>=jLu+R5bO{ zUoX5GzK^|iNF49#;yh7n)asqwwbMMmO)KqE7fTL2c4B7k)V8U0Pi`>Odn|V^cB!7a zerADl;>#<23L_cl4Kmro-F1rI*Y~d~9Xp(`mu>mScgz z3MtD`OpUEXotnKRiD z3|4bwx-##k@kYREcN3a9}A?zX*a<%>9GW7tC zADS!>RDfNliGR*o#C@}o4Eja(_vt;~&po7cw2AO9mAKvaVXZJU?z zY5RbVa@sHt!oDuoTDQo}G=jW$zVRECfb zRoZ;gC>4w?7Ag!UBs7iV)O9a#dBQ%%_;eBCWj1q$K{9e&^Bv~P9aiy*1|@y+6ss{G zx#pp0E6jAvYQ7iCPzj?Drz%e~!7w$8jU;MAQ$Z;+Q?pBYd#_+5FJ&eySL+ey{8kFK zNE+N4$nCAneoFHZt9Q(z)IbqhF^ps?wrnFEKi{P;9zxW_IZh&0N8I?(1*e8FeKYWS zwt=V7YZ|<<)A3ylwqlC@#+IOjaT-C~+-|8f2;MK0@acq$CdvVz5KU-7PWkE2?(hF> zSN~_F{hyU{86=@K0q6**?EkDX>9=$o1V2sz2I0W0^09+;;$u-yurQi(MBu>T4pX@yh z<@+F_0!oTuM-|-3mABo1MqlFB2yt=JomoFw#oj#di!P{xTAEcOoFW5ogJu#9W7rZ5 z&hR4wXSI|pzfK*NIo={ilDMnHyhP{su40yceDY&t2#1V~v`bF11P#rvdMvH#^5YMtAU6&JsJ z;h(7TiE9JI{m0eYn}s$5-Uh?JR0 z*R9o3tS<1)C=%dueh*n4?tCa$stFPMcR}|8bJs1~*c9Zfbc3(Ivof z5>Af7n_dsplNI0#KRVB{!knod`A%+eX_c-Eg=iyz|imiqXzQ)7mHd1q43w>HiS zHSp<6edZ`Q>pk=`l8rjMWO}n}hTEYR)=bWvz@{>F<6BOKvCjOl3rHF&FPP~ZamJuT zm8V#Zxx8Y2q=fOXLYVg}NZ-7;rJUF7Uk~-@%};>T6Uop}<4?>QRBwM8P|tvnDo(n% zQi`NYXTh!6%!rxssd=H)Lcd?>;~slX+<9SDjOWQ^khfs@oWR$crUg~C!bQ{M?rm~e zt4QU=&c0rRJ`x7&;fh>|il@hl9S0#S90vce%B#k!_t}#1hgYgw{9R8Rl**$-DqZG9 zyEK1E<;$k!a{h67*LBjIDdhS|^;eJ%J=*ewWAK8f+jQsKx^ig?ISY-_%5jes3+D{0 zgcvA+PB|7k%R|(uMM+jo`0e`(RTJD*qW2r$Hh57=_?SMlMhOb#$aEYLg_1^QNX*5z zp{2erLZ5^a3ko7U=q&=T`F2gI5DNkNOgTroOe+?xe$Ax2j9sL^DHBhfMk_jj z2evdam#+fbnbLBr9Dah?r9go&eN8yIAsQ&(I97{fBBXmqd0jy5PI$%%Wi26U?tr=# z_m|2xF02@pUE5jMT74 zn~{`OtFLL;gWW!L7kto4MJK8CJ2io|8-RL+?b*42j)TNf6smNqDrOAd{MChoZ?&I$ zcJ)@*?xWkG?}R$I_xUZ6TZQgRy3I*a%}RN7 z2V~W|HN8@B!nk2hHP&3WPCQ}gly9n2Nb=ZU`|0N5@E@sHV?&{h>g$awn>Y^|t-6*8 zSZ=uD#AjbxvCOOmeD;+qe;hD#=(C&SPyQ(Bx3mD+(`meV98#QI_K@$GmZyfDHht^Z z6L|lC^DO;Lv^pYgEU*qooW9<9#EjED2P9fH*PKZ`slvC->V2887kL6V#vp+^wp9!x z-be2Lv|}WHRC?1Wc_ruDN`Z1DS?D*FGA|o+JE1K|4VXs`T!noHs&SQ`8o(1GJ~H#j zp%_XG`p`wHikC9K-Tm#}2{G#0x%-h^^=)2)o66PQT|*35fBlu>SvBgD-l}rSnN;aqNaBn~f`0xD-AdB`|}GHOt&6?_)BzyIa`-Vx$o9voq zOm{6Aizy3@E=Ii(rwF7!9ymGEYvd_PzVZ#^oHd~wiH~R*84u_?7)Ld*7<0XsC*COY zw0YQW=~>3?=A0vyZvMV`;I{p1$f%#&T9i+vy~-BlQ%RrSEY~wmLh*3DwB7xZ>E+c_`8130xz(HD zPH!p1?|E;}-2A&naJgN!uq8=+Z#s?br z2@S>*WRvKULORH8WB-^&ti9`EB0L&STwNp=K~@Qp-WBWbdg{?e=pol4h5GBBJG5I} zQpFUHlfn(jB}~{W45(MSlw)JLzAs9TuO@D8(j-ws7eI|3$U1O%+!wGcq#O)Xa{4Z}E1u5ScBqz;w*hij6=pZP=bn9ZOTMr%Vn4`SiH1JkzYTTq}8j(mZj zDglX{oe%tpP?Jn$Sc&9Z5iJD?LYPJOo;>JS^!aBAA1A5M+*`%#pT z2s7Z24-u9b1I-I^*f91w)LW3iuEN8X#zdHV{bVByigOrD^su)advIf7qn+hUr|v^`kDYE#yC2 z++pxTd7I!g&Ws*34kBnyrJpKejOh#oh7i3`W`_?)2@ZW%jA+|ijw9dQIr4impDHS9 zV;iu~$n32TmSZo>YYfJ&JtMpk21~-SY^)D69N3E+wCm=H?Z2la+hFpdB?P ze-9!;R0CKBVTu8H#ve&g=|DW4-do$p3rtn%dl@T-^~?rI-{UO_rOb3~nQHha8u*k3 zTdR(eki9>jgqW&ayfC)8ocHOw)|!}@zkTpMS;^{1vJJr~-xFjTmXWKviF!0)izR&I zBHE}@;pA;kRW0rdw!$FVmS7{ysA3eDEVCf+DR5NQID-~xt+6baSUHa>4qAEFlH`rt z(av%lQfe3%HkWE+D{_;fo!fm;g0R~U0o&RVY{iWYn)&uo-*ha*N_`Z+A;9?rv>;If zi@H!l;+OPd)ZeEOOh<3~Q^}9Ze>=DJGg(W>Hl`W2Ml*Z*HOwwv(`|CuwS*0-8Es& zxHFI4bU!fZ%0nrJ)2|&i+{P)|;7?2Usicn|$q zz28;bD4S7{{Pj!DD$S|3!ni1Mu@wf#h_xuj{W0Fr1A{UL zo?^JBAB-pBV1w( zn1ztOi)JAc$^|3Eex|Q8B)Qbjj1F{v zdWMmlgL`UWoosCbOF8!RH@2H4D9ZsZi_=HIyrto*{yxqIGV3z>m``wa4k$;QQCaP% zaA`-2upJ7m)y|S;QIK{gAGTu@}11s{oKfzV=~k(qsb zW2exfY1MEIOfL8nm1lgI9wyJHq6}m4a?Q^Zv_5&7$Cy$k&l9NZihW79PT+wJ3wwtW zV>RXsl<2#g;wzWkQ|Y)sSFxq}o><3s_+xo*=R-6}?nxoOyOMLPAs z@$t01in_7N?y5WbzpFBx){{12HK@M#ixn_TRF7p!DWJ;J;8<~2xdC09)zH?Yn?kBU zA}Z?SO4C1Rk{|nC0+>j<_Ob6je+VAS)da!ECZSe})P+kpdfd_7SP%`g!Rco~0Foeb zQ2NYDuxLh%|sw97<(kGht2gtyllk{ z+rZjq9GE;x;Ec~sDIM#Bp^zoW<|}!JVptl zepfuo`zqDlyLWFY9@^S&NN;xfN3c?`Pchh74u9DkD`A|>W;4!R`D%4}#BIuBnZ(b{ zwI*gxGxJr>QMcXNPPr?eQaE4bskhdSvi53 z7o5K2=+G4bpHl?ChroL$jvQSepqvg>WR+7adFI9E24PU^<4>NYeuc4QDJIjcb?LWR zG@@fdjZ!2oc8v^}YH6rZe#GV9R0wfIi~FgfBxQSAZ26XUAUVyNu3Lx*N%LK4+nm&NHJ?s>m-W(X-tF9a z(sS}UP2pxH?rC|(zvmtaL}Xv4*PIaiZza& z9)H&DiK(v`7nor7qf^l-bN0cHm$@aqa>o!jcFoLy=NlVf{mf-j(A z5B9lTUbJ~}xpCu+H5;MCF!X-P!;Q|3+P)t|9)ji1?pkE>XnZzh+Lm|r8gD&wc@0$0 zzx3p)Y3or7o&CAz+b$Cydi^3iJpLK2i^o3rrRVG4b(vKPE}t)SGrsCeUVnSSYd#;j zyqpbBzBmhgd}q_c<}j-0uQ3xhCt^;loG7_;*Vz?*kFYXVbThKhG;SifyCC-GS^aQj z0Ltgxcz-=EPHG}2MocW5V4ARZLihN{iQ91PP@~gn)EZfbv#6#-AE7VN_vj+@S2Yp( zeq=ZrotF9_tF`PoWiKq4RTT>}QI2?x*|VB^1@fVEs`nTjEXqN|jgM?lU>UiUq@fUY z9Tuv7R{u^$J%r7QM7xkCwMjgG4z@PR*=~{Ak~qmH5+_#87t`xOHUt8o_M~acfFSMh zyMn)P?ydFJbdR6F1(^KD3Hv~HO9q0TKvc%Ggi*ix(wnzHS27bm4{)a8pR|wGf)D>K z8CU3aNqiI?=G=H{QBL&DlP||e*XNeBK->k*ria!oY}!m#ZWY3FrFDxb4*I2E9vZ)@ zE*2`r=8s)kyZaD?_lA?)9Xk!k#`Q#S_IEbu$yWE?3A@)Z8?S!p(ngPjV3KY);qDU~ zAsmbo%Ld)~+r+6#mh=#)TVou29_xs!Ltlk^jPvXA&IBur^P8FFH#0@f2ssPn%x^S? z$C(_rz2DE?ER1c!nKm7jvbiZBgT{5e-x@$r_WajB{f0fp|oIf_sCkI zIy4AU3a`N4&|T8*^OucRZU@4pxNMh;XV@2nF6X^PcR#PHXM*M&d@*i9v(GML%DAwX zi;H26+wyJDiaMZ6`!UJq{J3jPLi2z+bBp8`q^=1TPG1%G4?}00(BrFVI^NJ`6bN-$&vUUPEVUI!{w-KKl8cA6SSLAE<&PUpY^_B%Ts8bO#Yz`el|#nXQav zYM%LYK=ASLIU(P{L9PKJ(MQy?8DF~>?xFhi(XMbaphJhgudqPf#7w@jIDUe6<{Xu^ zwX7%ek4Y_zTZmr$owyU@%L8#H5$;6Ya9K6bBwY?4KrDsr@udEH=V#$%WZ$fyx-qG- zh^=t(&!KY@a8l(3cz;YUt(7U74IXzYiYc4rA~utM==);zX;|^Z`q>*=5mM|pE~o#a z>d8}VQxmZSCcC|Z$sxy}WM;o-@6Yk35gr`>Q@o%D4c=H)OHfwT%RJ+T6$Q}&RMi(s zV?LymgNbv?`@P|n-(~aVHsyd*F1ndcucFnuf7Oz&m-2?@q9xz+^S+^}+z^?sW8QNy z^2$z^ch8M2fUC(;}Vi-Rk~ z;GZ>jlFkWTGkQo$jJWc+l-UVG2O;{c6{+HhtJr8>4Q0}-O5IvxrEaCGihZ-AQtcx? z`*kaf1Nz4<=zO;8RQq+RUBVsWvyZ5jGGg`m07M<#AB#6THIPX%NYqS5|ESKQB6Mv~ z<<;iwb3nV&^?-I8o#VBG!Z7qo!!Qg!K6TnF+H3kjd7nfyB?h%aFlV0 z=KA#>3F_RI(`;m(TS3IO&uMN#bLoT2)wk+Ub`mQ7DrY`|7xbXD@}ZHn(%4h$(Wt9F zubMY<=D$&v-h6{9b9^e}woWdKDMzC3hHyF_cOH+R@zsbmG~QAZM`O;6PY$f7*Rh!y zH0Gn#6i`I3OLlFe@#V`qXq=m~hsH{2=gzrSnzAkFB#j4~I%u2|c9zCn`?_h&S$k{Y zMS9I8L2ehgUx_SU=1(VBu1aPNgwX3V8DTU|Y+p^|mNn5djyM=gLhAlMi3@)T`LfKXtH(f8GF}Lk<36%ea8&^;B_Z^~7IfqFvY@*j(){b9)f?gkO zJw@ZNh%+>nzesk&Qq8#WG+?bYJuPbsCoy79Dj+d=j9cwO9e^~G^5zJ_a?)q!{AfLd+ZT6OzA zb>AKRol5<#V_N?q&FTSN>uK%odhMPJ-AZ3wMY4YL9p|-?+M72tYYWv!@^s6ZG>s?p zL$`lkdrmsMQSNS$D@%mr3uEfH>4rje@$K5`8tu?AU22%Fb#hyUuJ*bve5+>fIc->? z+BZyhpkCW@OINf}v$av(@25L*Lw9gUd&^I^x>L^HroOsCGZ?MDP@yf2bt!zP=J|b- z_m9mq&DlG}hkiJp~zFGGRf2&WOb0F0iU}fa@$w07eja!Y}*34X|Th%ss@g)fvs!cRwP{Yg`6lz z&wf`a}69*cc6mQ(@J5xD*Wq*>JspY~PPvTjLLjF>t8}uJ3`Jn@I1!u7yB) zD&!e99VG+taCrkl}?~Ds66@!Ex56G#V%wmXcK|1*3$-$a{tm z?()SgXTcWWiFeKPrGFrn^W?uyX)o##LPOo z>CMVvxwHN4-md8d)rN}+)63T3Fq&)}r~1t&mxKex402=2H844^6`nYt$rSW)q+C2t zl8oErV`85s76SG8;#Jrs#$p#ut{%V4tqC%Il>YZs`-G$-IsYQ;>vulzuj(ds=o)hU zyS^#vp4()rQ)wz}Wkap&fZP-))igj>l32ACR@tYuK$gb9A81@%CgeSkjv`|mD%iZ zIEo>c7VWzJp`oAD4T`g?JZ&gg)UHxg>uZ2;) z;wGD|gj~MkIu@7XdX}xDau%27lrq|A@)x&=a@mSYRa`z&+DN(l%Ppn+S8sW5rLWGX zEQ7Crb9sjw<=Ia#aU;9QVpE-5(o9Z<88+=uNBcwChyA||kB8fJWb9e6iftp?S=fJI1a?LMm{uDazTof7HEob~|caKx$GO_eF8&+qRRyKgi zOO-)47`T2GjySDH%Z14TGGF?15dk|{hYMh?&?`;hbvQq4M=ln^i``wykLtOzR&Mum_*1N#F?XTO) z;OuXM^WbnfWTm1tdP0g&Eu;v;1P@D`CZ>sjLZ&=SGG%2s6F(dw45`0=wMwkF-FJeJP6&p=N80a-V zrN^j&Zzf`&Ll9rFu=2g1(LA=fPN%e{^D(Rx1o*_xts=^0v4bZz(Pb{nq-~^QukZch z{hG4Rc4t84k7`q){`+gsLwp{&_V zFB`pdIvi^je;#_t!l<9T*gkbR1*k)2y0;1tf=TB>GVKYbP={Qq8hAq`e^dixz1xB8B7I{&r2^V-Pu zq^4@}wgb=9x0Jy34(|h%hN9FT7B-R7-DA4C=0x5|0V+Eu+5`(Y3kHjf=L{Q* zy&?i9ZCE|A_reo_d6R-R|1dEo6_VA9UA1!TwcA*n{4 z3rW&NuVb$J#)iu~gxBKqZSd4a>4GL|@{l@BxNUr|n^daLj(xjK)9h5E%_B}7g0FZ~ zxU7kn&KXk24!dIZ1%9q2n>GHW>ila$;H1({D9k1$#p=MHTnTVb>VnSU@#h+al4vP^ z4Q$#kY_FVAxo%8jxJN{&rtbpjUL0C#Xu1N?k2Y_X6LxBYGrTVaxa{gy2elgZ|JHAr zxM@&(F2wWdck@>n54E~S#A=rXlHr#&RFK_~;=U6?N1@?*iTcWBbxQR3v}oM_^pOas zFzr<-Nc74i@pK>JMfqdSLD_^x@vNK#HRATkb;e5fFuEA}@=EC9{rIdT2R$EpaGsSiIN zmtokwG%^L~qEzf&k~q6542tFj4@2H#k^frjUHaVu@AL^~ar^rG0%|CM%nUKKM%dd1 zs}Jj1H$nfm>kmm6AEmwg_+SJqj-$)&7pN$Hi5`oC#hONSP%T`c@_3|i zaS;^9lWJkf;w7=LT3_W-E$oIAp;oJ^rSERkr3j0;s9qjP7H@RlG~txfK7EMmX6-8N zwgAG6EsuLpXZLs(kv2aUVKgQ>h;L|KT zvq$tXNj{5xmilaSUc6UY;pr>oNNsK{Vx-Vd^TfQz5<#N+0|7TlgbAQ0YMJU3bLoC{ zgy@{8LZAjM=nzME5cD28ovT)Uh+$TH8$M|6KAL!SapMeXtvhGCZ7=6o}o_PawVUhmo#-FZETe@#T<^Y=8^fOxKTb^T>PMID37~lSXOHQdV%h6-x#eQ23e?uPk5JQI2|U-sB@%xhl-pgSmLYM=@7l z3rm;N5z4I>+*YCdu9dq5D(n`t0^_L=8ghxyMc~W~;rvGESVm5M)cp5j)o`VQ^u|JZ z6YTi>#4nclLgQM^(WRGGLfR({8A5BCQ26n&Plh8%BdP)HcT?%vYWU`dK1-K2fv*$^ zK27lJFPi{wzx0)UP4Aj$2b7T<;ny_V@suh>g8(9-Uw;x&FwmhyHCdVYY<*J+4sFtb zQm!Q^`%xj~Mx>+U3VZUH_dEMh88Cf{Nu@|@Y_{q)U(nNtsSEg`JU(st0^@XC9A+9g zG_q`&fd zn4z$CHA5F*h;= zMd#7$`;GN%<3y8E+~JGiE%mkZ{fMA?8rSYQLgRpIO*Fob1>X~oLc_ey`3n8lq`g;3 z-BHNhN!C9R{`A=tC@&R?Vl=re&bjs4Ro?Y$g*{2StUqThBg>x-PbU{Upf7>6_(~;Z zVr#GvvBUk+I%r%+wI-o3c-+Y&t{cufhnG2R3DRX3l927%ux7}N6;|w*hcAu0H0ZMS zhI7DSQaK>dA9ri5la8euO) zL29XHIb9Qds_>I#-!1!SRjs=Af-(2R*mF7R&NJGM1kI84x{78^;4Wc#x3M$QIndV- zP$VUH$~Ug*VxKrm)sjfvuD#mM4Bh5sn!sT(cDeJGc5>LO@x|l?8GkE&BKsD!bO|{- zq_z#h`7ZG?{b9yH61hT33W2Ca>A&(@l=bV3)za}KeNiFFYZC@eL-GYubQ7W%>`2la z*gZKsQCQcZPF}5V+o`*DLDQM8-hX03NUl?7$drB8$EAeG0~f~CA9l{JBs;scS9&#v zg0&%?W8y-c2JZx8w^e#*n0%_60;dfUbgsKE6`RnZk&F%7~ z*(<7Gccb7N2dAGY+Y24DcRYIO`QGsxgT)oWQin-8vR~>rAe{Jk@S#m_-B?sO@y5i0 zkDB%i>z&Sh(emllNny{Ic^#aw_OspPnv7Z~zeaY(OT`<+{0wR3G4ax(q(nHfo)q1J zn!}K@8Ira`^wf~G(#irUHBAcGA*Jt!qG6$}k7O>al`gyOntuBALz6SsL+o3f4;0aNDgQ+h(IoqXnjMH1O@YvWT?w;d}hhaIn z1<9lorjMC2NvEBWuT#&SVH{_0nwR19Ry>4~F4#ye!o(;3`J3-8{*FG1#1M)Sd8_)M?5bl_E!R=;}_LNVWw%apgZkK1!_x8LVF{5Z&yvOzDvZqB)Jvz4C zSULNYTjK1?ZzudEY}Sq^PQMqipv^VY(=_YYYZ0#d32o6u^ZMdhlpS?XRR1~R|rZXn_oEI07Gb92%W6gxQY|>h6kQ>P4JjX^zw60 z>*vh+f#$`>W=@;_W(;^Od}@|c+zh9u*T7uQC9dNp>1wHG$~B<7y2CWrDU)>?Z@)3} z!!r%Ec+= z0}vk{+0V*we!p2y{B)(UE1+~o_ttf9Zxa-zZ33# zTxX&Y$?aZe2{4=Gg{ zF2``WL}`TJ=7;;GhtXsL?l*nEb(AYQ-2A|2S<7bv-l=~$`cc_cp?5jdEr+U9A^3se zOHi04L@qk~&)y}gAG$p!e@R9Roc(B^R!n%deNJ&DIdu%m=12Yd+LQw?m7RdlG{~8g zau|Xa1ue>+cIKpz^v8zpRbGXoF;MVl+5z5e9(iK&+-*MlU6N+q78~V(SF7CiPRn;6 zl&TE_o(JZHkGc5wYA4l(S~|ydNZThxNf*1J$cxTEQup&iGYbsCVytV3Zim+Aws+GE z%uy#qft$vi2oGqSG=iiXqkTqF6{wvBC!t%?XoPV_nP_AY+|btUJ*aEZ43>Hx^cjFw zXP!wIgK?4y|bI+%Fzl1;fYSEH$eSz>Ym| za~EX)iDs?od-c%U`LCZ?T(o${8^>Qe^cJR#pEPFD#PJhxk1b8e{LXoUb9^6Zo!>LJ zWS%b?RW;+s(dQmx*>f3##D2R9ztXgPub@QP*$M;Ts?+@@7^RPda-ME&gry8^Xbv$e9>jA%O!f1 z?V?JeCzUhRJn6qc>w*`khdQH9ibt8WT`rT#Xd2x?iz%x2-o}+Zk-x2{AAbSpbUG~% z4g0Ak{3OH@lnnyhtVtiyZvillW=cGZmg2odr)T@PTFb$bX5~EUZq14xyEtq@bf7VQ z7o*@~W7u5}EA|XpnivtY)j2E6fR^v+l%6u2L30a|(ssnGMl?gsg%;@8Bv8vw-n?}y z2{ZIiGY>vVZg}8Q%6gI)F2;n4MM24Mqh)$hVGI>#AH>I*LffP#pE&2dU%26P9?{lp zd3kG;*yVP{xu%5NSzMVw*8LEZPePROVV~pbPPi#A$EsjO%z@kWtt=2*Ua)d@XyeK6 z(2THF7?fSEH@li}A9AJ5o=<{Y8Rp6-SNxQ=ZDvKIIqGwEk~MW?(_hd2{%|O)T1K)r z!HF~>Kbd5u2sMFNuzqdX+zXcsYpxlht~srYa*Ina6#GrC3tqUnW$L=DM~61xN|3%t zJqU56itH0wAyo3!M9L|eZfrAsV1d4@n>5@IPWA|gqvh(oBz}iFFIC&WP1|`+d)y!S zk-lFOL3RpJ!Y=B$6)A7g465_AwOCygWxfjD*cz6gY>k)^zxw$<_q6|JvySq!v;S|6 zJNNtH-|uzLg_-|}S;sLC{QFmRzS#_<9OeHRlaO-N$QENz%g_Kd04YsE+|}y;f?ZIB?nd(28%}Jnr6G>N2#BdH5+offk|ESbtuAR3x6Dgi z+Hu3!SMOA?t zxqiux#k-cATT;Qnx{Jrnu>n zaJ)b~cMK9bNcr?Q?==q{?9c{1?Hdm(pSbz+-dpm@$Z@^Vy43~hsw_Ai0;hAN^>0_a z-T3!9@1Rp2;S0DyDCTrMxuvTI&ca4cAiFm&s?^^t}?eUKbuNX`~l%29^?B60a$ zxP-6N`;!nkSZ*1Hi_#r^lm3q0*Whc|zmK#U`V7JHpz)+(uiRts+bfx5lfh)jG&FA@ zjl;stZZX*qD__-bG2ma?S(2GfZp_MjO|>CJEH|AT}lr6=fek#>qOhvr5DUEdU+ zqj2IY@Jsq&ny3+U^F+G46kUTIBg=o20|c`44VnHx2XP^b5WD4b?`XQ0w35UR;+@+4 zARG>8Q`Gq+mHpj$_J~vPmu)|3hnt!``b3gQip72EM3VeMDoOtU@9{5{T!mDU@@fRV z9{hQ$6#slGS+5I+tJGsX94zmolC5uIuHleiNMsOOf0k;_A$0P|U-X8;9s1Cc>6*nY zW9sz-uHlgVc`Au`35$t@bP5m-RrSLDM^e<+za37?O(g5x%j8JNd86IH^SdH*oG`0h zFGRvl9o`Snw=X5q{8MR1n#LrO71~4+@7y%wi170;xlfHpI9&HUqq|{j|8O%2sT8W< z>JN{9?=pQal^k*phZLtsNPZhz?MbKas6VE=DhPTF>LO3Ny_p1()*#D9t^B0?6HKE* z{Tq_}ch`mTB&yxgPv>cPoqj;CqYr+MH?zJ7px-Xz)e8?8-Gsl&FVLs-f3@(O<_&t` z?k2qGLZ7OcuJav1E6eW)kw6n>$~xKkTQZSoR>F9lJ_OWRg7n!>C@vm?r+|KXG4%Mq z8Q4Z**2L9sK-c?y`p_DTWKu32D?P{9v_+w$uoFUirPMv~V4{$di{hq~8tz_x^0_i0 zI9^UXfwHAkPL9iD9ejer=C--Sj|Fn`kKkrS0`{Y$51RnUWf4ML4CGP9s<;i2-tRp}D)yy9} z`v0)^9bj1>|>8?;wIAU7Cs_ zNKrsUKtx4EM3kn2D2f7#|C#rKdlSIFX21G8-|%qX+h*?Exl_)Z`JLbS!Qi82SpVK? zTM`TZKX#asoRo*CZK&6wVM&_0CJMSqosN`-98c*NhPOI@VmXQIMZC0deuD!DbI`xM zi_gGEB#`lxKc^FpS;%lU$ec2kn^SNLw4B5{ZnrDMv=c$=!q?S)l(+iK_i03NChRoo zH1fv(okn3)CwZt)C}e~}oxQx!PwXeoWXU!kogg!Np;Ri8N-6Tb1T4b^jwy`jb8z72 zjyp5y_F#rMPq5M*@t;GF*<*7$DsB!xK6|IPKE3N7Sdm+@6i1^gQ=srS zgKg0HE;%yPvm+C8I*>|Xx`nkevM*5^lQ$vR!a=9Pn2aMBoOOyad<%r@bc#tjJO}As z;a}P${P`cI@Y5I7PNJaWR1|#OJg2hb+fP1Pea9gO`0MO^t}$-n!mV6$Afa)Eo)*)( z+zN)Hg;d~-TXs>)Fl|)k(gxEz8}8JjaZrBZqQ)SUuweM@ZGYGn$NC1NE-M|Kl=i+X zNvDIjNyv13>m^WHXZW=k@Z--i;-{mR!%cV z;^Cl+I_6V#+&qPIK+UPuIE)&nP~&60`O|JbFpFEk7}qY#%fsn>JGV?lpMC3YlgQJ-}I<`ew@@P5wrgecf)^%Mroo$_5Tb2(L^27e54Iwu*{jpYsb58o>fK4!9FDQM)S;~L)=RtK5Hio>FMDGpH#6nY0mjMkqVp|`_Z{|F zx9H|caZwS|=*0{S8oBov>#>5H>+*Jp+Gg&FxogV7U zo07&XZQVubb{|pCeK>R!9UMj%ol$43rmTmpEns&&5Em7*`TJ#eTSdFvZ2BLV=hi@M zIof_2`4)>3B2Dtj47XpDCVQBjK4x4|BFc23i2|&`3sP!CRa*@kJ?Xp{guzllr-Ub) zB@rQ#!VrmT1!~EhTb(Akb81@HtDSD*<6Z`5j;g)Uz;z%vAgmD(N$AV@vy>G(I6{9$sSaoD9!rZQKl6tHLi*# zt&6Pp=_r#M)_v?K6|eXz;id3JC-Ke02E*F4vsC;1%X0!|xg8N+o*SKGRHiv>oh@#c zv`Y?}l%O_IWDoX4RVHj0Roxq?>@1U=g(O0>u}bvCQDt)CVt z?1z*+P?SsUP@alHp022uZZ*rYZMRM^Px&O+Fgltld$|NT8|^?P*ih!O&{Z7FBnLtf zIwA{Z+Nkz=#^;w2HBv&=)!&GZ@Y>PEKxYKh&cpOy^O8 zf=%LQX4#e4_QP#|$oX(^5WdP-aebI79~8DTHAd&Pkp^i!kZW`&58Q~fo%)96FUu`1 zz!z1t>0)y$iy5N*VDi}xKyxhST4sUGYbshFJmF(I3+vgtsK39z$&>l?yu|z|3sX~j zky$EClTa25RxWb9OWO{C#Ytq52qu5CGP9WX<@+J%*AYl0mq`3@&J@!q>c!uhtu(W+ zU#4KYU>CCav<4_^yO}oIVX-$80ivZsOc1INp97(#SQd%?u!|B&WO9=PbPm2ufk60N zh#}j=x3lic92?YdR1Jf-7amS(^ljg--`oJ zxS@sA!c(n9kigHxkKTCXA0REl`mT;9Pxz~cGpu) z^wqbT=<9Pl>H8*k*a4=AZV>L#FVZ{kR;T&Z)d`r4WheGP+dY5Kp^fqs+DAj0S)YC@ z>=Z|%^AHAYtSgfb4QqxS1F47^y|eZ~Fx7}Mv0wJ2nVHh!csOO30J|g@%Laic72QVN zuy5%eEbpDilrM3w4$O%70^>OG)iUHR-2LH+rO}pU%WLdIXBA^Cd^V@>M?fqw`^Y8#Y&@29GSW>-i3z3Oa*J+=#Qo6$Pk(At0t*6q^ z-zgSv1u#+=DxWu+C8O17;}U(1QZowAELapmJ%5N*%~s0gDoXKBjhIqt3^fJ=NG}GI zCqelS`C2`-(rEe81MqGUA!wuD{+n0>)N%{Pm}O|SoOZ>;G?EQ}qeOU?_$$jO>TTMT zp;=bMYz11)Fm3RD0HPUMs5}II@X8-PT!|%eERJKTSEP{21c~rT2!ch}%myJwB<%&u zXx(%-6~D>V{}9uC1Y+u-j?Y)Hl(XX;?Ed zDN_#{owl#gPZXWA$&uarAj9am{-8y_$rXcWg}33Tx<%_rrdew3mr5MRQy%dIIN=T2a+>@ zk_u7B0168cpE^agTmkQH(2*ucws}lDe4`ed?=I-MYMhW(4G#wXmgwy0GrSX$onLA1 zCo+KK3e|6ORd|~UGB~XoVKdadqVLIRk5;%{B(BM0&IMA9Cs}7-$pvp}e>;_bkaGDo zxuFob>t(T*s4KD()ops8sE_%IoW}n@4y33^c--P5I`Q$qkMm=lIA^ELVFw@T#0$IN zTp$cjEB~%ghf!h%sX@vJSejLuWL?H&BnleVAJrYHbX$Bz@bJ~i znMb~QsNYzUyD1-CVmj0vN)g{B(Ga6M_oF0#noDwV((qtv#}ZgIOI$kQXt1w~6er}L zBv~CZysGVgo*Yz@VkcK0mikX$2RM>%a$D3IvgN#Vky-#9bZ1Bj}WcJ){W`%o^#h1wYG45_#@;;D3pf|I^QKeoLMI9WKuQD3h=M)6Yx< ze{*us{}%lWXH52Joy_R=U~K+16^iIT-@Gj4#9g|;9UknJ)b*QY-dKDw-?XyKu&4Ti zEFW>eb@s%DuD{f6@T!y*H7V}jH%>{A1h?t!>^D5oigJ?7E*+H~+HiD(%YL?JROWL? zG+HG(gn2jDW}ZdbJoWEX7?yuj$h-FEj}G$zrWrnIK!&@!t9iRSw(%S zgSo8RJKNvc5)RwjRKd|R69=v0kL&fFlkV=39L=PA%Z>JRs<9nc$FFz$K~}G}cgv!f zoLSq0GicvMzTmOOIIgcUu;>OAld_ z??ceMA+O7(p&0E5p!4EU$h@>SAM6uGMu|?gnRiCRSuY4{fDCVl8ie{Fwj@KGe?U}r zLUMI4J8+We-_Ks3bH5%cxPF62)L5`VBto zTi-c;R2g_x>2pXtSS>x}%+%-01_njt5A;J@Oiyp9O@LeOkm@ZfNwoDnrL6N4rMD=$ zVvPrV#P>QOVs=-Vq9~D$xW-(rGrPGm%DQob*Z098a4HOq<`?3MU0oqdkYyRQd}-Qdp(Je?e$mnSq)HP_IE>rB8_NX({7u0ZvlyCru;7iS(Uqw0g8 zy#c}s(SZC!F1q<~r){Y7g5>o(r5PqIx1i=Fj}X*p*1nsG?}FH?P_QCk;3RUJStU-A zWQccXqAjxyo z*f#yLN$fN?v#ryL4BbpGXrdLzq}OC4ii?)1mN$$mf0eAfWE5}Lt{SrK7uSo@4H~?t z%Dq%YFXSz{^>*rfuchUIaDQo)I83^0X6Y>m4y4<2sG>!AUnlLTg_a<=z_!{Z8+v~1 zVzqq-Y@;$EST-QPDUW+S5S=>66t6kq0zEgNV_`}I>V4hA+RbGUI;{%mLi$>C>X|oaVU&}%)x*aKD*|vUp}>L)j#H&FfwTbvOWN* znB?`vE_iO5T&VZE)z5z+|IpU*KD|(`w*{80GA@Nh-YKOuIXuL$lYg=pS zll91NFXO2h%EfS_E(%*v`NH7hi&apU1eHlJdR=^25?>E{rODX3D$72m9PWOXyCG

fR5L9&pwwY;iIQzDx&Sr@ULxt~vL&K-DP{yKYVVfT4DH+^|v}Qk`(+Jg!+tF zJzy&jyieqB5=6Qk?)(c1TRW8k6R2Q(!7KwE#()UgLZLp1iSHptIEaOsahGV^iAQa1 zL}RgVY-1%6-^Y`|dz{paxd8Ebp+F?Z&(KNY;|cPmY98hz>ndsga7V}S1Y5X+FUYAH zotTgJIBTN$TtfV0CZh`Zk0L$goAU7KPB|loi8k~_Kt$XimLR=w8#6ZjDr?0I!^?Erm zPAGm~@K5|>tmJ9{VX?s4EP+I(BD*Txyw$i%n$BI;0V@Q=P%DtyD)Nw)labIvD%eV< zYsN|)Ll-s#vBWd8?T}>e+zvbr-Fj7SO(uE zxj=CgX&~tCa~V24&QVxK4)H%n(E=)xy&so~@mRg(NL4udrm5J-IJ5%ifr4+$%Mq^g zEl~Ji7e1(nQ`~aUA`W!Q>9Qv?&NV(52HsEKpS#P}ZB^AW51WzI^)_3d+l}dl-oEo< zutVUl4p&e~voWq{G-8^_okw;L6wG4`#jAi%JZZm>#Jw5V&C z3x-G8Blg)$tT4>1n~B-zMW2=hni3;Jfw4r1f#wW$^(GZz)G?z^F*0P1gt}qI*j?SI zzRzy1W`cx{sZ#qENwBcb_!wISp^}_wPM6sjrBnHGr~QiE(s%-(F_tUv>IH>65-}^G z7@+~8#K;B-#pE+Rl9PxuG#n;WJ?`|R+ZpqDr};Jh+aKAn@ht%PWXXI#C!B(QBGP4I zAI3+n@aqDfsfrs^I9Sv~I?RdmH5_pbUmwl4Rr)`q$deM#zBMMo-UN#pVf3ia&y!50s4S9A^9r~lO``q@duw(u8HWh@IeB!RKbC@ zhiwkn1{9#!mveKeW`E|!r(Jge)BGiW+tDq~DME?1akjBZ%lsO|$?38KJ5W-(aF@3% zF+15PwTMIzceq}Wr-=0$6^ z?=g0LrR{~?Ydagohp(_cyA2Mu%Wicpa^3ywPOo?4f0<>w&-U!{Ys-V-bSmTsLUq2-7n3Vvn+HNy%y3e3}N&Kh9h8awOQEu|v z`?u5EsvwuXm_?;-3NJ!c%2LWxa!g#sdMr9DEwgG1f|1qD?6x$h^@l!#hE>T4yKi012X*TYnOCy8IL5w}NeODwG1zo6+xoG zp_3rEk8_RtuW!Xd2~xaF|hkowNb1w`1)2T2*p zQX^{Ba-jyB_bA0in1?_v!qNj}EW$1@XPB6XF@2#{;UGPX(vXdoqQui!h0;(+=}WO0 zNFO7ANw`2j5%K=pFy#etp2R6bRXocLdpNMqlUx$-WiE&_AWzaL7i?krUWm~YfUD|) z)c%qyZY78r>)}5JaB!>rvUAhJ8j`O=b4-Wf5jIeE!oRzM( zLodB1(IUi}U?>2hv{D9(zot?ppn2A_<+vcH8?Tfkp;36jil(Kj#QOSL1#PAfiNwQ5 z@3)eLSVAVx#sB}MK_@5)CJ|}A_>rf8sT_e#bOFYPk@Ahc`6kH|9f3_`mwU7eFg{bt zL=Vyv9e!~}$DETdzI!juu@|2+j_+}r8+17bUfj?-)o{xnV)+0}jt`FWnmCdDjpKde z8}?4c?8ce#a-41xSMsM~bNhFA+_+(n4~^u2kQ`szRA#w9m!0j4xNx-NH_^YvK=_-h z^J1Vn4sw@OFYhWt>Gyh{sW^Pdkv3Z9sqohu@`5tw3WtazbF$-L((DCKxa^!7C=`H7o?EOXY^s3oS4lO3vZ5rv* zZw1dAVD7wFygZX_S=}Ma)E`+DwkGi9cqX$5?tOO3EDclUzPZglgZRQ#S8GZvlUG%4 zJhHN8xu-f^-KM%y3@%pLboL@wJWA}a^Lj1Kuu~doKD26|MUxl!XuFiDrbn=IE{X3i z-IT5C!VOzq8(h+0S*Xoc2d^J7-a9k=uR#ulCLYTo3LBSrR2k~!KF1LD=MwXtI3rL zxg6Q3kXD~DVugAd?9F7lc)68|!t(@~fxbq?GK_nToY4 zp+smVQqPu4^+d*Ydg29EYFl&cAwnTFW=vVhBFaGWirFfWo|-5nzGzX`8{RhwR=2C1 z+8i>}_OaHUhHY%mj2fA%@Sb{yroz&`@0|m)iWS|9FD$;My~)_uDyrn|>Tc6pnn2}< zaf&3LO_4OsC{{$X_tZ|=l412}`$1U?+bFzeSEWi;4~s4f^9{?U1q%;byUWu}PDpAj zYBf=!OyNG&e!Fyer9sacPt8I7>jr6tSu5fe<{L&TVjb_b!bMpLExe|sjs$5 z)n%N=Mp~U`?+cHQlXIJ$&?(7)D%X9DOEXQrHOop&go@cpiBe`^XCRty zp|P@1*hv*qEv2PJODH4RdgE0htw#4K{J8&`z#(-e@wCZ~;khOn+;AQAIKYG5w+GIy z+4g=~1e7hg8BM0??8RxG^ZSLh8&jtZ5k&tCs7>8$1=nx6y{}R%!TZu$%1+8l=zu)juAM!0WcddrUE|y>v0O; zf~`>8Lh0y#$$kDG#-+d|yHru8lgl$hzxTD<^V%)*15Ro01-wr#n>{V1j5X6_CSt7- zfh5RB3`bXYO6-%gS+Xqqz0xv+z0!mFRhIphwAnOn7=IA`UPt@7uld{R~Z06CREFaB(7szGSn$EtZ>I}^Fv zSVw-2dC#*`slyl9)@nGhruFyP`Lb4jD#}L_8mn!qM{#=<#g~-Msm%VX%A7suO1@ry zfl2ii+V5AX*QfRFp+k1Ceb43>V>PwFyyA$=4bMJmn&{wl0oNs0TI`ZTG)b|d7Jq2) zLC23y5AdZst6bq+djTBx(GDc9JK4OxyV|5S<+JeGbm%{p2bFa@!0pPy*17wuq9~WV zB^L)AgZ_3h(T*g43yKWALB9(2Flp3YuzvOyyA{&(ub3B7CuIi}^_Yp^pk9<|nR&ZN z)x9)b>@2oEtjky0Hp=;~qV*EGKkJM)+A>U+)-ly5(3!XUu*b*>iO(67d0L(4Y}w;U zyVt2M2N_+=rSr4JgZ09Tr!AbTXAJC;G#IsX%{%fyw&j}W{0UN4=g^-cvT{`Ug2Uc)4yi;v^J{4hR!SlAo zI&k5_J1f)Dfv^i6w>x4|bDp_Rr!j@t%7ML|V^pQrZ~+Lo^B*Z-wSiNO?Cj2gOXk>IuR6cO4oX?noQ9qC&A3Ju35i z&OYlnnPD!}H^U5sO1VFtZ`;$glxPMXy&0LgLj&!A!H)Zd%PH*~%tdHsW4uZ+ja94I z6*Ll=LJX;Y3-6i^Tk8l38!-?x^eOwzb+e+`K_4nXKk<1?OPDG>C9X5fnVGb3?@n}n zl_Sxyp1&OcSqq}Yes=Zib@YTWa|h<+YPY;GY#6#Ag(_Qc*mzWZ(#ciq)MgmB(okhqF?{tf}!J2ah_leXjX71S=hkhMaYKAMh)xcYyDw^eAWQpGNIG@>FZ=Qt%+lVU z$>yaqJ9mq=CMqyX`>j6McL-ID&~AzLT~|%Ko9#Sr>hG#odtOmgH5+4=_P#w3u;}11 z%B4)%Fl3RNrk@t0N{o{a9H;9~K<22)m5b)--Gr+B+!5*J#2E>G_D9nhOw}HBP_=)D zK4xpzX%R+ZL|p;sc0Apcu3u3ob=wYZzsdi^_bh5DM_wk0M`S&5%8UJ$n72LXfw(D1 z%<;Bw85Y+hD3aUvn7(~SDN}w-99w}&6;u~Wn50TJv7Rl;fs82XMk174hQ3n}8K!Jb*6%Km zqL{m*ykW;Z zbUGP!`GL=ixhcXMvj(w3o-OGm~7;|UoAIqG|XBq~X{F_YiQ7Db4ll`bXC;NMb zr#~JsCM53%!eLhuWK}}>hR`Y){@$$~y1&KQKRbVD{m@6ZjzdBc9NG!k8Qj%q=s5v* zdLj11teMB8L~9Z}@9J|^uUs1Ad=GA6Zu_x0)6!#6_3KGHnLT=VwKlPus`f&Kr{G+h z(07!{OAw~VQs)}bp6Ka8WSowgEw>aatPHH=^A^wrr%`D2KT3xs<{M0mP1G%ri^<=2qm$sMv9O^u3JbMey+r?|X+}o2 zT59nT#mBJ_fO)?&P(RFAmJUDcfDb>xc)D1Go#di7k4po<2E=wEx!Lli>n&%`TRm@y z+I+g>(r15IwtC|XLsn`mH#0RNJn%y>46<+S&Vzh;E`0V}9dbuGC=|Y^rU?un%2V8; zcA0%pbKfL?UZ+X!+)jh6=VD*q{Z;lmJ!OOqK3jPEr5ag{CU8Y@2JE$O{Zr)fs*R!2 z5$rTO2I4llzLBu!?(@>+-G&u&uRqiMZi+XQExoaHk3-X^ew%V%zo!kE zR<@$e>GXzs&QMhV9UId&ItRhlHHVE_)I?vDVwg8C^`!$ZUh1dL6*Iw+Ojk3VYng+6 z+AX@#jJBGMY!2B)ox21VBcRBWi7KO$&(Q_PQFJtn+yzfE^N%uDnu!!v8Z+t4xvOSZ z8CWvYS> zgTX=|vlPlq=Pg)oG0Xb-g^N^{R;w1T{oS(V@6XgQQmxFu+M)|8&_1*isa(Of8KjO4 z@Y`2TqitvpX3P5WGDTE6QG{KN1{On$M0%=~QY6M?BvPbc7~0rCD3lmaGoEFjRw^(< ziPV0U&_ID*{OVa4TiC3Ts^r*OkHYI@LKTbGXM_T=1*30P%KPVHP8ziHbqPQ5qu9ywB*80nEE zKjw;IwaJk23F8KWh+y zTdJ;oeoxp*GjUU1AjiI_l+pZexJ z-W5!+cxsG9W0qM5*env6vxY}5KJdC`6=Pque~ed#7IRkckhd6Y;@$-$DAkYzd1 zDPc5=iKRRpn$RiXO`E{o({uX7qN1m_fvM8RnV|BW` z*W#RIkmZmx+Cp&UQ-Pb}f@RN~d>cWlZSb_6HdhTUJ~c#Y$h=rFkm8$BsI@sEF07uSYRrV zDewaJTpNrSkSGi({A4_@HxwWVUOC4HGL0@9*a0)tbE^D8YIR@)`_TbMa#{l$p9C274UW?chr!a7<}9KIx3O9**nIbXOl}1lC5|HkfpXD;`3slMe;7zotMMyf^!CH>m`P9R3Ho6| z6L)@&Bfy{Ke|@S2iiufzc;;sj+b@0?{l}jKoV|xm){xN>c9XgUF{D{?-UTytIw`E; z;xtj1OX6X8+@k;FVT}LJW66EGDl>+FC;Q}o26?LP0{(r>r%vge7bh`Qm=ZBLRRnx~ z26?-mmA5Cv|IQ$pP;qk5W0nC&tBT{0{5?q=_?dA?pZK`XA$I2D;W6WIjcY8@W5(gc z#h(%93BM`VM?T?mZ1Me*p|8i1ne1mu5qz?n$IdM#!uT2%EWLKOj!ua_o{a8A;C}WZNFE^gvB)?Oxqfc`0_$giGgGmhe z$8VVA_u*jspFKe9WbmJnH^F=^*N zr*v*I$-U#Jba9@vzD+gX8BcVQU#`AQ;)`vPd&f`d>JAwso}{dG-v`Gb;c>sI?tL^9 z=WkpplWw_s{e;gUc_V|-le`bf8$4m&NPUARENfjI9edTsEjL}9`Bu7Ej~ho<*6JrK z>#5v|k7akVA5K^pyYjesBNk2L;Ys5Boc04xSO!F3deY~R?*mWxeROfg3gI!!;Ne7v zM8k{9lTCCm4fK?g#j&SN_A{ldEFV)XacVhE4Z?wl{ev%KRR#wK=GG)R5CsS3<-oa| zwMb-pE4B)`85pIb!;x>j!vvfVbqkO8&FU>zjRu$uUVA&+RalWlZAmmfc=N6H@((gI zKF7I~H(XMj%3v=rHv=fQnZvbk*;AA}%4U^AWc{ovuSEq|wOaK@a$^~a0Qg9@x(xDR zaR^(?I;QgNz@3AV0f%JvQ7Y8c5IsrcRCGmHaLDy+@Xoe*1zVyOg zYDb~4jctu)?%Y$hnOu8HAgI*lzHmNTv`g>whDvR3nX-~tY8uSwM6D1DOaCeOJ_$*2 zu?vk|ffWlquo@a)?wDSA8I2x>{SHZn9>4pd|C5wX@Hadw`e&#xTfS|6@*5+PK&DV0 zdl<6G=Q5ZRN8N`XriTIilrqWvAuH56?mdx_5%VwHjb>61j!h&D;5s?-qsaZXi9D$A30BSa7$5Bz*E&RqNA zS{5Hrq-$R|3WJ-_#bNut5$Z;u>{2Gl40EzsEZBU^^nM*tN;9`XKuH@&j+n&jV86*- zi3tnHQ7<-+RVC_n@gWH_rg6WzEk7T;(?8wilq*jtw!e*2nXHVEGlz`Sy*0iE?SCV@ z=6$jw$gU!9g9IHU9y%=A*+hyPQJK0QyvwP1;AiB7L?(g%#%QeM$0^&8&$*9tBZ*jn z;>^hBLUy{0G~f!34`%ANWHZ(Wb8-tmMT;@?Xls8`&2(q3y>tC3*P^*M=Xz4kMLlQb z%C~Rj+u(66nyaU`vIcN%&FUP)+wQnwyiGiHA8%WHx8U~9wR+BYfwRObI2-n`AIPYR z#rvHPw&5+u9>jA z(Gd#wfEU_RP|oR3BCYjwk zuPwlRNPj3%16TwYr+k6ELk=#pN}>HTQY-B& zJ!>N==_o83HO;Tat_rpfpW9$~QoF+>MVq3{ksMUj%FZvj@T)MBQBB83?XuygxBa2S?y70ku?en`OLW{b7d+cg+h#07vn}K&YXuEr?}egdM^RjSgy|V z6xq&vyfcU4xl-7O@8o;X(g$^)XnV{ZWET*O9Qp#p}IAn>L%+shaazdie8c=#>zkq@^} zUL$|Jb-*9|`xDWbEmTjOH1ha&6(K}!+LbV;=N80oMXdufPBf{D1L|Rmzd=ckIN|Qn zR!?EUp83N;FJ#|MhoO)IfCuiOSiobq*O5RN2)D26)cBsDal380Yq{$|3LGz&1?;A4 zFB!C!dqH@MACCF%Yl7VZ;B_CXw;FoFccQ__Ds<`0ebiaCi#ie!OSPWPp-$v}eq!g_N8Lv-bC1Ek1dG}?al6>C z*L*i}-I&<{gRiyMFe%Wbf7CwGtRV$OTV6G)qL*i)#2Pv-jM^C}Ei5M$JwEJE%s-!lQIbF$SypVsOx1$bTWpVKJ= zeWN)WmWc!^Y+8We`#G?o3uS;8=3m+e^MA1wzJ4wNp6Z2*a23ko)ir-r zTae*ogP%blv|mK~-5|grqMlluK^47mNA78VM8BJAMw<>p(uZg7Q?4g49d*3;n!^E2 zku1%A)8dpjuB1SH2i+G47oam1x_3e45$LUiJLOc)AUvSn*(z!g9j<|pNci>QU58Lp zFq?|g$ft4jYYt!z9YU!mpmA<_Dt$ASc4>pHCsBM8O8a6>04k&z(x&zAN1-M~CS5vcU-ryud@M6O8!zBnGpuEY2NCfYI4X~&7AiAQXmLSyVAf5aA! zjnZ6?%gN*1Sk3iVT<@YAOL1)BG0zLwNRDkj!<=gTDnI%4`YOk=?r+GILzsQk>2?*e z$Bxaa0*JsO^acTX3Ep^}>|ZMZfz$m!5FGx)j^C3LZusJQ!K*Kk{XesU4YD^kjEOh+ zj4trADId!w*R6A61i#bdPXIXKfD;J#LcouQd^vfQGcBLsp}ss$h$m)P>hCPkq`R16 z!M~(L7}4?u9=8u({vPK=9-eL{IO!@ms^3IyrLqr+{ppe@ncze)D!2eT>LqzKC2$1| zLYINb1;J`Vl6kprHR`4UXGN^r{Hc#WeOm1ELlu<2mcTZW;*npZL|>aw)OBDzfLW(c zJ`@>S`C$f;!bpW6fnOfnnMt>tPHF7YW5)Se{_H%{2&21MS3!SqEm=;ktc3 zHh=Iq_T@F_v#_`2Yp(L=?vNfoS`Eob zui(M0q%53NLCZ*VGU$cw2TTGRQ^6)zYrMLY0Xfo$_-9LFMS+(WSNjT+%Eb>(V`l@I zXM`OEwjGULH$hsd4en_3Fp zWPj3kh7)utHbL+cHG_-jyLj}m{GTV-X4K8pLaF6jBZeNZT`~fjuSkE>rwJxPwPiM) zQy~xk%2ig0QK7!f(L|J*hxXp1u3dy{DWU`GGcaq!P829g$$?wD#Tngn<~d320o3)t zqSh($fTrOpgxr@!bi>V57(K2E{wi;;{=hM^xNE5>mAitSCtPKYqXN{%UV~iG4;Rs2 zO}^bDETAIU9*D61bhmaVcuP)zHIn{WwFrsVW{< z<@nW%KW&<-QcYc*3`k|d@*1v553AAMv--Fi;X1_imD}1~Aui@y=hMG?SY=3k@$6LM z`r_J3rq~91-BH5xx8Leow{yu6X@}vpZ_g=DK6U2TF#%|sCu%wfA=1!4G&+nNgl&p@ z2f&l`bOy07(_#8Fp<<=b=BWs*+4@TOyz!T!&xsnspd$}r=6WwopFKPyhD}opKUE>h zu{-_zwj8*W2$%kJk=^^^X_K>?^Tolxtso2b2DPw!#lpoR&3cK$YscUa_=D(8D}Ru< zf*HAt|0fHN@J6VU?QtCN4tNa$hkt=g(N%gWGye!PoeU-SQ)kmAZ;cs1mk> zO`zJu_oxK?S1F1jZzLryWGOL&Aw0UnebPO2f@p`xlg^S|7e>>*bdRJ|cSTH#M6^tZ zxi55wIPSl~c)94#@Za%Yw@la@pGQt8OUju)r`NqLj!a$f*#n)2t^%jFqrzrfdT}#3 zuh5bQQca3dEvaafQcLp3WkOf>ldbNL%SL=XFV|mBXgoMEAt~dVZ{_wHP&P1hi6&dQWi5cGL?D@D| zd^jZ(bu8J*ex`(PPImLyxf!|)JRv@1yzEID{P%m*b3Vrx$!8>i9|t&X9X<=Y>fRtf zu|#A9qOSut-R?s~k}Wwm-wJPkoQBYuufyQ?9XxT&SvRxCF@-y}G2ZENtn|VX87GeU zc9X7EC`fxtFhF}RaQS@$shL8&yhJ)LgY)(hWs;Cm0lr3Z$xTJ@ zj(`IqO;VVwGp7dPJ@PMVKO7_eYM2$7>8t#C!N(7jz$3FiD<(Qyk)(pe^A$^0QS}=DJOp zuFT0J$Tyo3h=P^A5m{K_rIU>DjToW-JzjkvdtRGH=aFBnPWOADE-AP_;}dnqZQOMvYZ8UKPVPQn*5KwTT?uxC*X#vi~QtZ)HK=nkq8h zY1%+mGbnRYBD-_-e@fVz>PKV+TnY1Mh+O^QE9SWT@ReoUY>`*H#?-_*GI^W@)s3q% zqRz@4TEop2(+_;+aedW|yUN(%XODze!M;ES3qh@())D2H5INzyJLgHRRrcZEos5Di z;UQlXpx${5f|lMj2)YgFvPN{9P8T|@CpUqDpc74E0p0yPkc_WRj-l_F)GxA z8J(3kP!-Yy(~S?PVnv9ay)KSGUv27OVky#2$Alm%T|ZB{rk@0E*=Ot|SBxB_)xepX zYUD*P$73OJcbB zWAhS$4Sl{evhNiv*Ffv+)?S9m2Z`nK<I zUxD0BwmRNvMs>Di#i{T8R_hAsQtiYsRBostx7W7B%r&}b$!hOHbz?E&n*)57v9 zR1iw}U!(F;7_Sy4{Q&D6%X-{nZxo_^N1&&GcIsQPmkfN4Vu$yXuge$evCQw}|3qen zrlzvl(`Uc=*FaDk|6Q$+no5O8f%ZW>=D9CL-q<+I6SB}{^p7Ywic!rWXg@X(Y(Rf` zy$+C>F2&2H=UpHw4bEBBd|qp~^`pvp!|D$8z7Fu$4&H>d0gG#mqUZWAJ79Qfe&0t$ zUzVrA?Hdqv6NTGtT@nH!3 zAWy^@)tH*eW-VIu3oqCUN^@V(Qz$K@EXW}fbEx#8AgUC#pj5bqFe4Zgz+EUn$B+l* zO6|l-^^aWaff*Tu${L|b)Bg9XQFs8lLo}FjF(VO+h3qrz?4?`;e3Bn@ z#t-8s_yhj%H99j#YAP-q2OS3C{w;_2%xu7`rWmcnsdMr8)Oarn zj_(u2xKnuQS9IGV{P;|)(mj0F{Cee#Z3P>$YL(SJpZ6V?ri{K;6Rzy!M0^!-%2erC*yT@iHdJ-SU9rW~GmAXgNoY}ieQDTii` znhwuAbd)`RQG09St&M%_B6cy?;?c#*XDTFN$~24NnYT6$&y2Ysxoy!oKVn7kDQV## zRrgDx5OJ_qQHuo3FWwWY-~Lj_igy6}0V}o@|D~1IXcXVs9FU4xnOGw}404&W65cf; zt=_?J^(muD+Vd@^eu(_E=JR^#LF4{ULVtHz(j=*u;$`4$NpmvZ)Jway^-{OZVLnWP zHbJ{j8Q}~a`tJ4eR&ln((;!89*|1)E^Miv1p?a4Mc7#Cv#}}=2niPj+#`HUg{pOEy zqpv-%>?bb)aR`Xzi{-vBN}HJI1%vrsnNqALGnUtZzQ&*qeq}+bwgdiuf}raM@% z%)$9#KbRUd4c`IIM|3J4E3)5D`UD_?sjd$s?Rc^t9iN^m%pmRfN#nf8OO4--d8dE6 zJEot(SS)>HFA{+)grfEdCFc(fJcB{>st6FP(F0e-0Hj0~I``}-BDjs3ynLwK(us(89aa{n!);{m3`ZxM z_vpmy{2j4B!EKzqaT~@#8;j5DwQkIM>!^k2x(8N=zd7P~2us#IH{qsr(IEJ*NU}R* zS@=w!mAmQC8)r6#|0Bi~`IMnzqf09*FT+XegKN%C8%jYT2ZcG|?5!j=t(V^2N$+Sz z9x+UIKjV{xj`>qbm#E|-IwXMcOJah~Fe$!l>XL~XoCUl4l5A7yCNHO zn(oD+rWe1v^PZ1YzJ0Bs#|L-j68YJ$5Hq1Cl!4!(L~V*;=h9%qNNv^!r+#(KA3Cl< z*i{ri?b4#meyFg#Zgs$LC>)L_F(ucS0T1@dO?u0I`rrxF>&`S(Gk%FE=sL>VN}u0J z4+Sz^S@77&Q`!^3fmTp%MDP7qgHQqB`{X3oT$u+CLd5enuG6^KwGxllCJ| z(qBzwIz^4C{dfpx{2EkU-#0o4GTG0+B^}9<`x3F4N2J%YdfgeXQ);03sdc4kwHoL>_RE>EdX&RVZZXd`6 z66Gr0+LFY{3+1?@>t-fd(^_nrZ8GFrNGVAW<%0AD28Ii{yYQ)pVMv4WaGeFp&L$^ShvF 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 diff --git a/services/tests/servicestests/res/raw/netstats_v1 b/services/tests/servicestests/res/raw/netstats_v1 deleted file mode 100644 index e80860a6b9599fd1588a36b77b95a8e90a003efc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18742 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 trackerHandler = ArgumentCaptor.forClass(Handler.class); - doNothing().when(mMobile.tracker) - .startMonitoring(isA(Context.class), trackerHandler.capture()); - - mService = new ConnectivityService( - mServiceContext, mNetManager, mStatsService, mPolicyService, mNetFactory); - mService.systemReady(); - - mTrackerHandler = trackerHandler.getValue(); - mTrackerHandler.getLooper().setMessageLogging(new LogPrinter(Log.INFO, TAG)); - } - - @Override - public void tearDown() throws Exception { - super.tearDown(); - } - - public void testMobileConnectedAddedRoutes() throws Exception { - Future nextConnBroadcast; - - // bring up mobile network - mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null); - mMobile.link.setInterfaceName(MOBILE_IFACE); - mMobile.link.addRoute(MOBILE_ROUTE_V4); - mMobile.link.addRoute(MOBILE_ROUTE_V6); - mMobile.doReturnDefaults(); - - nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE); - mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget(); - nextConnBroadcast.get(); - - // verify that both routes were added and DNS was flushed - 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); - - } - - public void testMobileWifiHandoff() throws Exception { - Future nextConnBroadcast; - - // bring up mobile network - mMobile.info.setDetailedState(DetailedState.CONNECTED, null, null); - mMobile.link.setInterfaceName(MOBILE_IFACE); - mMobile.link.addRoute(MOBILE_ROUTE_V4); - mMobile.link.addRoute(MOBILE_ROUTE_V6); - mMobile.doReturnDefaults(); - - nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE); - mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget(); - nextConnBroadcast.get(); - - reset(mNetManager); - - // now bring up wifi network - mWifi.info.setDetailedState(DetailedState.CONNECTED, null, null); - mWifi.link.setInterfaceName(WIFI_IFACE); - mWifi.link.addRoute(WIFI_ROUTE_V4); - mWifi.link.addRoute(WIFI_ROUTE_V6); - mWifi.doReturnDefaults(); - - // expect that mobile will be torn down - doReturn(true).when(mMobile.tracker).teardown(); - - nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE); - mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mWifi.info).sendToTarget(); - nextConnBroadcast.get(); - - // verify that wifi routes added, and teardown requested - 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 - mMobile.info.setDetailedState(DetailedState.DISCONNECTED, null, null); - mMobile.link.clear(); - mMobile.doReturnDefaults(); - - nextConnBroadcast = mServiceContext.nextBroadcastIntent(CONNECTIVITY_ACTION_IMMEDIATE); - mTrackerHandler.obtainMessage(EVENT_STATE_CHANGED, mMobile.info).sendToTarget(); - nextConnBroadcast.get(); - - verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V4)); - verify(mNetManager).removeRoute(eq(mobileNetId), eq(MOBILE_ROUTE_V6)); - - } - - private static InetAddress parse(String addr) { - return InetAddress.parseNumericAddress(addr); - } -} diff --git a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java deleted file mode 100644 index 0d5daa5def..0000000000 --- a/services/tests/servicestests/src/com/android/server/NetworkManagementServiceTest.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * 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.LinkAddress; -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, 0); - - sendMessage("613 IfaceClass active rmnet0 1234"); - expectSoon(observer).interfaceClassDataActivityChanged("rmnet0", true, 1234); - - sendMessage("613 IfaceClass idle eth0"); - expectSoon(observer).interfaceClassDataActivityChanged("eth0", false, 0); - - 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. - - - /** - * IP address changes. - */ - sendMessage("614 Address updated 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("wlan0", new LinkAddress("fe80::1/64", 128, 253)); - - sendMessage("614 Address removed 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. - - sendMessage("666 Address removed 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); - } -} diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java deleted file mode 100644 index a1af8cb79f..0000000000 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ /dev/null @@ -1,1057 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server; - -import static android.content.Intent.ACTION_UID_REMOVED; -import static android.content.Intent.EXTRA_UID; -import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; -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.NetworkStats.IFACE_ALL; -import static android.net.NetworkStats.SET_ALL; -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.SET_FOREGROUND; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkStatsHistory.FIELD_ALL; -import static android.net.NetworkTemplate.buildTemplateMobileAll; -import static android.net.NetworkTemplate.buildTemplateWifiWildcard; -import static android.net.TrafficStats.MB_IN_BYTES; -import static android.net.TrafficStats.UID_REMOVED; -import static android.net.TrafficStats.UID_TETHERING; -import static android.text.format.DateUtils.DAY_IN_MILLIS; -import static android.text.format.DateUtils.HOUR_IN_MILLIS; -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.capture; -import static org.easymock.EasyMock.createMock; -import static org.easymock.EasyMock.eq; -import static org.easymock.EasyMock.expect; -import static org.easymock.EasyMock.expectLastCall; -import static org.easymock.EasyMock.isA; - -import android.app.AlarmManager; -import android.app.IAlarmManager; -import android.app.PendingIntent; -import android.content.Intent; -import android.net.IConnectivityManager; -import android.net.INetworkManagementEventObserver; -import android.net.INetworkStatsSession; -import android.net.LinkProperties; -import android.net.NetworkInfo; -import android.net.NetworkInfo.DetailedState; -import android.net.NetworkState; -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; -import android.test.suitebuilder.annotation.Suppress; -import android.util.TrustedTime; - -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; - -/** - * Tests for {@link NetworkStatsService}. - */ -@LargeTest -public class NetworkStatsServiceTest extends AndroidTestCase { - private static final String TAG = "NetworkStatsServiceTest"; - - private static final String TEST_IFACE = "test0"; - private static final String TEST_IFACE2 = "test1"; - private static final long TEST_START = 1194220800000L; - - private static final String IMSI_1 = "310004"; - private static final String IMSI_2 = "310260"; - private static final String TEST_SSID = "AndroidAP"; - - private static NetworkTemplate sTemplateWifi = buildTemplateWifiWildcard(); - private static NetworkTemplate sTemplateImsi1 = buildTemplateMobileAll(IMSI_1); - private static NetworkTemplate sTemplateImsi2 = buildTemplateMobileAll(IMSI_2); - - private static final int UID_RED = 1001; - private static final int UID_BLUE = 1002; - private static final int UID_GREEN = 1003; - - private long mElapsedRealtime; - - private BroadcastInterceptingContext mServiceContext; - private File mStatsDir; - - private INetworkManagementService mNetManager; - private IAlarmManager mAlarmManager; - private TrustedTime mTime; - private NetworkStatsSettings mSettings; - private IConnectivityManager mConnManager; - - private NetworkStatsService mService; - private INetworkStatsSession mSession; - private INetworkManagementEventObserver mNetworkObserver; - - @Override - public void setUp() throws Exception { - super.setUp(); - - mServiceContext = new BroadcastInterceptingContext(getContext()); - mStatsDir = getContext().getFilesDir(); - if (mStatsDir.exists()) { - IoUtils.deleteContents(mStatsDir); - } - - mNetManager = createMock(INetworkManagementService.class); - mAlarmManager = createMock(IAlarmManager.class); - mTime = createMock(TrustedTime.class); - mSettings = createMock(NetworkStatsSettings.class); - mConnManager = createMock(IConnectivityManager.class); - - mService = new NetworkStatsService( - mServiceContext, mNetManager, mAlarmManager, mTime, mStatsDir, mSettings); - mService.bindConnectivityManager(mConnManager); - - mElapsedRealtime = 0L; - - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectSystemReady(); - - // catch INetworkManagementEventObserver during systemReady() - final Capture networkObserver = new Capture< - INetworkManagementEventObserver>(); - mNetManager.registerObserver(capture(networkObserver)); - expectLastCall().atLeastOnce(); - - replay(); - mService.systemReady(); - mSession = mService.openSession(); - verifyAndReset(); - - mNetworkObserver = networkObserver.getValue(); - - } - - @Override - public void tearDown() throws Exception { - IoUtils.deleteContents(mStatsDir); - - mServiceContext = null; - mStatsDir = null; - - mNetManager = null; - mAlarmManager = null; - mTime = null; - mSettings = null; - mConnManager = null; - - mSession.close(); - mService = null; - - super.tearDown(); - } - - public void testNetworkStatsWifi() throws Exception { - // pretend that wifi network comes online; service should ask about full - // network state, and poll any existing interfaces before updating. - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildWifiState()); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - - // verify service has empty history for wifi - assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); - verifyAndReset(); - - // modify some number on wifi, and trigger poll event - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 1024L, 1L, 2048L, 2L)); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertNetworkTotal(sTemplateWifi, 1024L, 1L, 2048L, 2L, 0); - verifyAndReset(); - - // and bump forward again, with counters going higher. this is - // important, since polling should correctly subtract last snapshot. - incrementCurrentTime(DAY_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 4096L, 4L, 8192L, 8L)); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertNetworkTotal(sTemplateWifi, 4096L, 4L, 8192L, 8L, 0); - verifyAndReset(); - - } - - public void testStatsRebootPersist() throws Exception { - assertStatsFilesExist(false); - - // pretend that wifi network comes online; service should ask about full - // network state, and poll any existing interfaces before updating. - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildWifiState()); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - - // verify service has empty history for wifi - assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); - verifyAndReset(); - - // modify some number on wifi, and trigger poll event - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 1024L, 8L, 2048L, 16L)); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 2) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 256L, 2L, 128L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 256L, 2L, 128L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 128L, 1L, 128L, 1L, 0L)); - expectNetworkStatsPoll(); - - mService.setUidForeground(UID_RED, false); - mService.incrementOperationCount(UID_RED, 0xFAAD, 4); - mService.setUidForeground(UID_RED, true); - mService.incrementOperationCount(UID_RED, 0xFAAD, 6); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0); - assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10); - assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, 512L, 4L, 256L, 2L, 4); - assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, 512L, 4L, 256L, 2L, 6); - assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0); - verifyAndReset(); - - // graceful shutdown system, which should trigger persist of stats, and - // clear any values in memory. - expectCurrentTime(); - expectDefaultSettings(); - replay(); - mServiceContext.sendBroadcast(new Intent(Intent.ACTION_SHUTDOWN)); - verifyAndReset(); - - assertStatsFilesExist(true); - - // boot through serviceReady() again - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectSystemReady(); - - // catch INetworkManagementEventObserver during systemReady() - final Capture networkObserver = new Capture< - INetworkManagementEventObserver>(); - mNetManager.registerObserver(capture(networkObserver)); - expectLastCall().atLeastOnce(); - - replay(); - mService.systemReady(); - - mNetworkObserver = networkObserver.getValue(); - - // after systemReady(), we should have historical stats loaded again - assertNetworkTotal(sTemplateWifi, 1024L, 8L, 2048L, 16L, 0); - assertUidTotal(sTemplateWifi, UID_RED, 1024L, 8L, 512L, 4L, 10); - assertUidTotal(sTemplateWifi, UID_RED, SET_DEFAULT, 512L, 4L, 256L, 2L, 4); - assertUidTotal(sTemplateWifi, UID_RED, SET_FOREGROUND, 512L, 4L, 256L, 2L, 6); - assertUidTotal(sTemplateWifi, UID_BLUE, 128L, 1L, 128L, 1L, 0); - verifyAndReset(); - - } - - // TODO: simulate reboot to test bucket resize - @Suppress - public void testStatsBucketResize() throws Exception { - NetworkStatsHistory history = null; - - assertStatsFilesExist(false); - - // pretend that wifi network comes online; service should ask about full - // network state, and poll any existing interfaces before updating. - expectCurrentTime(); - expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - expectNetworkState(buildWifiState()); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - verifyAndReset(); - - // modify some number on wifi, and trigger poll event - incrementCurrentTime(2 * HOUR_IN_MILLIS); - expectCurrentTime(); - expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 512L, 4L, 512L, 4L)); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL); - assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0); - assertEquals(HOUR_IN_MILLIS, history.getBucketDuration()); - assertEquals(2, history.size()); - verifyAndReset(); - - // now change bucket duration setting and trigger another poll with - // exact same values, which should resize existing buckets. - expectCurrentTime(); - expectSettings(0L, 30 * MINUTE_IN_MILLIS, WEEK_IN_MILLIS); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify identical stats, but spread across 4 buckets now - history = mSession.getHistoryForNetwork(sTemplateWifi, FIELD_ALL); - assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, 512L, 4L, 512L, 4L, 0); - assertEquals(30 * MINUTE_IN_MILLIS, history.getBucketDuration()); - assertEquals(4, history.size()); - verifyAndReset(); - - } - - public void testUidStatsAcrossNetworks() throws Exception { - // pretend first mobile network comes online - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - verifyAndReset(); - - // create some traffic on first network - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); - expectNetworkStatsPoll(); - - mService.incrementOperationCount(UID_RED, 0xF00D, 10); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0); - assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); - assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10); - assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0); - verifyAndReset(); - - // now switch networks; this also tests that we're okay with interfaces - // disappearing, to verify we don't count backwards. - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_2)); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - verifyAndReset(); - - // create traffic on second network - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 2176L, 17L, 1536L, 12L)); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1536L, 12L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 640L, 5L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xFAAD, 128L, 1L, 1024L, 8L, 0L)); - expectNetworkStatsPoll(); - - mService.incrementOperationCount(UID_BLUE, 0xFAAD, 10); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify original history still intact - assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0); - assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 512L, 4L, 10); - assertUidTotal(sTemplateImsi1, UID_BLUE, 512L, 4L, 0L, 0L, 0); - - // and verify new history also recorded under different template, which - // verifies that we didn't cross the streams. - assertNetworkTotal(sTemplateImsi2, 128L, 1L, 1024L, 8L, 0); - assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); - assertUidTotal(sTemplateImsi2, UID_BLUE, 128L, 1L, 1024L, 8L, 10); - verifyAndReset(); - - } - - public void testUidRemovedIsMoved() throws Exception { - // pretend that network comes online - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildWifiState()); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - verifyAndReset(); - - // create some traffic - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) - .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); - expectNetworkStatsPoll(); - - mService.incrementOperationCount(UID_RED, 0xFAAD, 10); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0); - assertUidTotal(sTemplateWifi, UID_RED, 16L, 1L, 16L, 1L, 10); - assertUidTotal(sTemplateWifi, UID_BLUE, 4096L, 258L, 512L, 32L, 0); - assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0); - verifyAndReset(); - - // now pretend two UIDs are uninstalled, which should migrate stats to - // special "removed" bucket. - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 4128L, 258L, 544L, 34L)); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xFAAD, 16L, 1L, 16L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 4096L, 258L, 512L, 32L, 0L) - .addValues(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 16L, 1L, 16L, 1L, 0L)); - expectNetworkStatsPoll(); - - replay(); - final Intent intent = new Intent(ACTION_UID_REMOVED); - intent.putExtra(EXTRA_UID, UID_BLUE); - mServiceContext.sendBroadcast(intent); - intent.putExtra(EXTRA_UID, UID_RED); - mServiceContext.sendBroadcast(intent); - - // existing uid and total should remain unchanged; but removed UID - // should be gone completely. - assertNetworkTotal(sTemplateWifi, 4128L, 258L, 544L, 34L, 0); - assertUidTotal(sTemplateWifi, UID_RED, 0L, 0L, 0L, 0L, 0); - assertUidTotal(sTemplateWifi, UID_BLUE, 0L, 0L, 0L, 0L, 0); - assertUidTotal(sTemplateWifi, UID_GREEN, 16L, 1L, 16L, 1L, 0); - assertUidTotal(sTemplateWifi, UID_REMOVED, 4112L, 259L, 528L, 33L, 10); - verifyAndReset(); - - } - - public void testUid3g4gCombinedByTemplate() throws Exception { - // pretend that network comes online - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - verifyAndReset(); - - // create some traffic - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); - expectNetworkStatsPoll(); - - mService.incrementOperationCount(UID_RED, 0xF00D, 5); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertUidTotal(sTemplateImsi1, UID_RED, 1024L, 8L, 1024L, 8L, 5); - verifyAndReset(); - - // now switch over to 4g network - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildMobile4gState(TEST_IFACE2)); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - verifyAndReset(); - - // create traffic on second network - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L) - .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, TAG_NONE, 512L, 4L, 256L, 2L, 0L) - .addValues(TEST_IFACE2, UID_RED, SET_DEFAULT, 0xFAAD, 512L, 4L, 256L, 2L, 0L)); - expectNetworkStatsPoll(); - - mService.incrementOperationCount(UID_RED, 0xFAAD, 5); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify that ALL_MOBILE template combines both - assertUidTotal(sTemplateImsi1, UID_RED, 1536L, 12L, 1280L, 10L, 10); - - verifyAndReset(); - } - - public void testSummaryForAllUid() throws Exception { - // pretend that network comes online - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildWifiState()); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - verifyAndReset(); - - // create some traffic for two apps - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0L)); - expectNetworkStatsPoll(); - - mService.incrementOperationCount(UID_RED, 0xF00D, 1); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertUidTotal(sTemplateWifi, UID_RED, 50L, 5L, 50L, 5L, 1); - assertUidTotal(sTemplateWifi, UID_BLUE, 1024L, 8L, 512L, 4L, 0); - verifyAndReset(); - - // now create more traffic in next hour, but only for one app - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 0L) - .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0L)); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // first verify entire history present - NetworkStats stats = mSession.getSummaryForAllUid( - sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); - assertEquals(3, stats.size()); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 1); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, 10L, 1L, 10L, 1L, 1); - assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, 2048L, 16L, 1024L, 8L, 0); - - // now verify that recent history only contains one uid - final long currentTime = currentTimeMillis(); - stats = mSession.getSummaryForAllUid( - sTemplateWifi, currentTime - HOUR_IN_MILLIS, currentTime, true); - assertEquals(1, stats.size()); - assertValues(stats, IFACE_ALL, UID_BLUE, SET_DEFAULT, TAG_NONE, 1024L, 8L, 512L, 4L, 0); - - verifyAndReset(); - } - - public void testForegroundBackground() throws Exception { - // pretend that network comes online - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildWifiState()); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - verifyAndReset(); - - // create some initial traffic - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L)); - expectNetworkStatsPoll(); - - mService.incrementOperationCount(UID_RED, 0xF00D, 1); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertUidTotal(sTemplateWifi, UID_RED, 128L, 2L, 128L, 2L, 1); - verifyAndReset(); - - // now switch to foreground - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 0L) - .addValues(TEST_IFACE, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 0L)); - expectNetworkStatsPoll(); - - mService.setUidForeground(UID_RED, true); - mService.incrementOperationCount(UID_RED, 0xFAAD, 1); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // test that we combined correctly - assertUidTotal(sTemplateWifi, UID_RED, 160L, 4L, 160L, 4L, 2); - - // verify entire history present - final NetworkStats stats = mSession.getSummaryForAllUid( - sTemplateWifi, Long.MIN_VALUE, Long.MAX_VALUE, true); - assertEquals(4, stats.size()); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 1); - assertValues(stats, IFACE_ALL, UID_RED, SET_DEFAULT, 0xF00D, 64L, 1L, 64L, 1L, 1); - assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, TAG_NONE, 32L, 2L, 32L, 2L, 1); - assertValues(stats, IFACE_ALL, UID_RED, SET_FOREGROUND, 0xFAAD, 1L, 1L, 1L, 1L, 1); - - verifyAndReset(); - } - - public void testTethering() throws Exception { - // pretend first mobile network comes online - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - verifyAndReset(); - - // create some tethering traffic - incrementCurrentTime(HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); - - final NetworkStats uidStats = new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 128L, 2L, 128L, 2L, 0L); - final String[] tetherIfacePairs = new String[] { TEST_IFACE, "wlan0" }; - final NetworkStats tetherStats = new NetworkStats(getElapsedRealtime(), 1) - .addValues(TEST_IFACE, UID_TETHERING, SET_DEFAULT, TAG_NONE, 1920L, 14L, 384L, 2L, 0L); - - expectNetworkStatsUidDetail(uidStats, tetherIfacePairs, tetherStats); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history - assertNetworkTotal(sTemplateImsi1, 2048L, 16L, 512L, 4L, 0); - assertUidTotal(sTemplateImsi1, UID_RED, 128L, 2L, 128L, 2L, 0); - assertUidTotal(sTemplateImsi1, UID_TETHERING, 1920L, 14L, 384L, 2L, 0); - verifyAndReset(); - - } - - public void testReportXtOverDev() throws Exception { - // bring mobile network online - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); - expectNetworkStatsSummary(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(CONNECTIVITY_ACTION_IMMEDIATE)); - verifyAndReset(); - - // create some traffic, but only for DEV, and across 1.5 buckets - incrementCurrentTime(90 * MINUTE_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummaryDev(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 6000L, 60L, 3000L, 30L)); - expectNetworkStatsSummaryXt(buildEmptyStats()); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify service recorded history: - // 4000(dev) + 2000(dev) - assertNetworkTotal(sTemplateImsi1, 6000L, 60L, 3000L, 30L, 0); - verifyAndReset(); - - // create traffic on both DEV and XT, across two buckets - incrementCurrentTime(2 * HOUR_IN_MILLIS); - expectCurrentTime(); - expectDefaultSettings(); - expectNetworkStatsSummaryDev(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 6004L, 64L, 3004L, 34L)); - expectNetworkStatsSummaryXt(new NetworkStats(getElapsedRealtime(), 1) - .addIfaceValues(TEST_IFACE, 10240L, 0L, 0L, 0L)); - expectNetworkStatsUidDetail(buildEmptyStats()); - expectNetworkStatsPoll(); - - replay(); - mServiceContext.sendBroadcast(new Intent(ACTION_NETWORK_STATS_POLL)); - - // verify that we switching reporting at the first atomic XT bucket, - // which should give us: - // 4000(dev) + 2000(dev) + 1(dev) + 5120(xt) + 2560(xt) - assertNetworkTotal(sTemplateImsi1, 13681L, 61L, 3001L, 31L, 0); - - // also test pure-DEV and pure-XT ranges - assertNetworkTotal(sTemplateImsi1, startTimeMillis(), - startTimeMillis() + 2 * HOUR_IN_MILLIS, 6001L, 61L, 3001L, 31L, 0); - assertNetworkTotal(sTemplateImsi1, startTimeMillis() + 2 * HOUR_IN_MILLIS, - startTimeMillis() + 4 * HOUR_IN_MILLIS, 7680L, 0L, 0L, 0L, 0); - - verifyAndReset(); - } - - private void assertNetworkTotal(NetworkTemplate template, long rxBytes, long rxPackets, - long txBytes, long txPackets, int operations) throws Exception { - assertNetworkTotal(template, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes, - txPackets, operations); - } - - private void assertNetworkTotal(NetworkTemplate template, long start, long end, long rxBytes, - long rxPackets, long txBytes, long txPackets, int operations) throws Exception { - // verify history API - final NetworkStatsHistory history = mSession.getHistoryForNetwork(template, FIELD_ALL); - assertValues(history, start, end, rxBytes, rxPackets, txBytes, txPackets, operations); - - // verify summary API - final NetworkStats stats = mSession.getSummaryForNetwork(template, start, end); - assertValues(stats, IFACE_ALL, UID_ALL, SET_DEFAULT, TAG_NONE, rxBytes, rxPackets, txBytes, - txPackets, operations); - } - - private void assertUidTotal(NetworkTemplate template, int uid, long rxBytes, long rxPackets, - long txBytes, long txPackets, int operations) throws Exception { - assertUidTotal(template, uid, SET_ALL, rxBytes, rxPackets, txBytes, txPackets, operations); - } - - private void assertUidTotal(NetworkTemplate template, int uid, int set, long rxBytes, - long rxPackets, long txBytes, long txPackets, int operations) throws Exception { - // verify history API - final NetworkStatsHistory history = mSession.getHistoryForUid( - template, uid, set, TAG_NONE, FIELD_ALL); - assertValues(history, Long.MIN_VALUE, Long.MAX_VALUE, rxBytes, rxPackets, txBytes, - txPackets, operations); - - // verify summary API - final NetworkStats stats = mSession.getSummaryForAllUid( - template, Long.MIN_VALUE, Long.MAX_VALUE, false); - assertValues(stats, IFACE_ALL, uid, set, TAG_NONE, rxBytes, rxPackets, txBytes, txPackets, - operations); - } - - private void expectSystemReady() throws Exception { - mAlarmManager.remove(isA(PendingIntent.class)); - expectLastCall().anyTimes(); - - mAlarmManager.set(eq(AlarmManager.ELAPSED_REALTIME), anyLong(), anyLong(), anyLong(), - isA(PendingIntent.class), isA(WorkSource.class)); - expectLastCall().atLeastOnce(); - - mNetManager.setGlobalAlert(anyLong()); - expectLastCall().atLeastOnce(); - - expect(mNetManager.isBandwidthControlEnabled()).andReturn(true).atLeastOnce(); - } - - private void expectNetworkState(NetworkState... state) throws Exception { - expect(mConnManager.getAllNetworkState()).andReturn(state).atLeastOnce(); - - final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null; - expect(mConnManager.getActiveLinkProperties()).andReturn(linkProp).atLeastOnce(); - } - - private void expectNetworkStatsSummary(NetworkStats summary) throws Exception { - expectNetworkStatsSummaryDev(summary); - expectNetworkStatsSummaryXt(summary); - } - - private void expectNetworkStatsSummaryDev(NetworkStats summary) throws Exception { - expect(mNetManager.getNetworkStatsSummaryDev()).andReturn(summary).atLeastOnce(); - } - - private void expectNetworkStatsSummaryXt(NetworkStats summary) throws Exception { - expect(mNetManager.getNetworkStatsSummaryXt()).andReturn(summary).atLeastOnce(); - } - - private void expectNetworkStatsUidDetail(NetworkStats detail) throws Exception { - expectNetworkStatsUidDetail(detail, new String[0], new NetworkStats(0L, 0)); - } - - private void expectNetworkStatsUidDetail( - NetworkStats detail, String[] tetherIfacePairs, NetworkStats tetherStats) - throws Exception { - expect(mNetManager.getNetworkStatsUidDetail(eq(UID_ALL))).andReturn(detail).atLeastOnce(); - - // also include tethering details, since they are folded into UID - expect(mNetManager.getNetworkStatsTethering()) - .andReturn(tetherStats).atLeastOnce(); - } - - private void expectDefaultSettings() throws Exception { - expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - } - - private void expectSettings(long persistBytes, long bucketDuration, long deleteAge) - throws Exception { - expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes(); - expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes(); - expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes(); - expect(mSettings.getReportXtOverDev()).andReturn(true).anyTimes(); - - final Config config = new Config(bucketDuration, deleteAge, deleteAge); - expect(mSettings.getDevConfig()).andReturn(config).anyTimes(); - expect(mSettings.getXtConfig()).andReturn(config).anyTimes(); - expect(mSettings.getUidConfig()).andReturn(config).anyTimes(); - expect(mSettings.getUidTagConfig()).andReturn(config).anyTimes(); - - expect(mSettings.getGlobalAlertBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - expect(mSettings.getDevPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - expect(mSettings.getXtPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - expect(mSettings.getUidPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - expect(mSettings.getUidTagPersistBytes(anyLong())).andReturn(MB_IN_BYTES).anyTimes(); - } - - private void expectCurrentTime() throws Exception { - expect(mTime.forceRefresh()).andReturn(false).anyTimes(); - expect(mTime.hasCache()).andReturn(true).anyTimes(); - expect(mTime.currentTimeMillis()).andReturn(currentTimeMillis()).anyTimes(); - expect(mTime.getCacheAge()).andReturn(0L).anyTimes(); - expect(mTime.getCacheCertainty()).andReturn(0L).anyTimes(); - } - - private void expectNetworkStatsPoll() throws Exception { - mNetManager.setGlobalAlert(anyLong()); - expectLastCall().anyTimes(); - } - - private void assertStatsFilesExist(boolean exist) { - final File basePath = new File(mStatsDir, "netstats"); - if (exist) { - assertTrue(basePath.list().length > 0); - } else { - assertTrue(basePath.list().length == 0); - } - } - - private static void assertValues(NetworkStats stats, String iface, int uid, int set, - int tag, long rxBytes, long rxPackets, long txBytes, long txPackets, int operations) { - final NetworkStats.Entry entry = new NetworkStats.Entry(); - if (set == SET_DEFAULT || set == SET_ALL) { - final int i = stats.findIndex(iface, uid, SET_DEFAULT, tag); - if (i != -1) { - entry.add(stats.getValues(i, null)); - } - } - if (set == SET_FOREGROUND || set == SET_ALL) { - final int i = stats.findIndex(iface, uid, SET_FOREGROUND, tag); - if (i != -1) { - entry.add(stats.getValues(i, null)); - } - } - - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - assertEquals("unexpected txPackets", txPackets, entry.txPackets); - assertEquals("unexpected operations", operations, entry.operations); - } - - private static void assertValues(NetworkStatsHistory stats, long start, long end, long rxBytes, - long rxPackets, long txBytes, long txPackets, int operations) { - final NetworkStatsHistory.Entry entry = stats.getValues(start, end, null); - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - assertEquals("unexpected txPackets", txPackets, entry.txPackets); - assertEquals("unexpected operations", operations, entry.operations); - } - - private static NetworkState buildWifiState() { - final NetworkInfo info = new NetworkInfo(TYPE_WIFI, 0, null, null); - info.setDetailedState(DetailedState.CONNECTED, null, null); - final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(TEST_IFACE); - return new NetworkState(info, prop, null, null, TEST_SSID); - } - - private static NetworkState buildMobile3gState(String subscriberId) { - final NetworkInfo info = new NetworkInfo( - TYPE_MOBILE, TelephonyManager.NETWORK_TYPE_UMTS, null, null); - info.setDetailedState(DetailedState.CONNECTED, null, null); - final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(TEST_IFACE); - return new NetworkState(info, prop, null, subscriberId, null); - } - - private static NetworkState buildMobile4gState(String iface) { - final NetworkInfo info = new NetworkInfo(TYPE_WIMAX, 0, null, null); - info.setDetailedState(DetailedState.CONNECTED, null, null); - final LinkProperties prop = new LinkProperties(); - prop.setInterfaceName(iface); - return new NetworkState(info, prop, null); - } - - private NetworkStats buildEmptyStats() { - return new NetworkStats(getElapsedRealtime(), 0); - } - - private long getElapsedRealtime() { - return mElapsedRealtime; - } - - private long startTimeMillis() { - return TEST_START; - } - - private long currentTimeMillis() { - return startTimeMillis() + mElapsedRealtime; - } - - private void incrementCurrentTime(long duration) { - mElapsedRealtime += duration; - } - - private void replay() { - EasyMock.replay(mNetManager, mAlarmManager, mTime, mSettings, mConnManager); - } - - private void verifyAndReset() { - EasyMock.verify(mNetManager, mAlarmManager, mTime, mSettings, mConnManager); - EasyMock.reset(mNetManager, mAlarmManager, mTime, mSettings, mConnManager); - } -} diff --git a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java b/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java deleted file mode 100644 index 1a6c289316..0000000000 --- a/services/tests/servicestests/src/com/android/server/net/NetworkStatsCollectionTest.java +++ /dev/null @@ -1,193 +0,0 @@ -/* - * 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.net; - -import static android.net.NetworkStats.SET_DEFAULT; -import static android.net.NetworkStats.TAG_NONE; -import static android.net.NetworkStats.UID_ALL; -import static android.net.NetworkTemplate.buildTemplateMobileAll; -import static android.text.format.DateUtils.HOUR_IN_MILLIS; -import static android.text.format.DateUtils.MINUTE_IN_MILLIS; - -import android.content.res.Resources; -import android.net.NetworkStats; -import android.net.NetworkTemplate; -import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.MediumTest; - -import com.android.frameworks.servicestests.R; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.OutputStream; - -import libcore.io.IoUtils; -import libcore.io.Streams; - -/** - * Tests for {@link NetworkStatsCollection}. - */ -@MediumTest -public class NetworkStatsCollectionTest extends AndroidTestCase { - - private static final String TEST_FILE = "test.bin"; - private static final String TEST_IMSI = "310260000000000"; - - @Override - public void setUp() throws Exception { - super.setUp(); - - // ignore any device overlay while testing - NetworkTemplate.forceAllNetworkTypes(); - } - - public void testReadLegacyNetwork() throws Exception { - final File testFile = new File(getContext().getFilesDir(), TEST_FILE); - stageFile(R.raw.netstats_v1, testFile); - - final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS); - collection.readLegacyNetwork(testFile); - - // verify that history read correctly - assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), - 636016770L, 709306L, 88038768L, 518836L); - - // now export into a unified format - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - collection.write(new DataOutputStream(bos)); - - // clear structure completely - collection.reset(); - assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), - 0L, 0L, 0L, 0L); - - // and read back into structure, verifying that totals are same - collection.read(new ByteArrayInputStream(bos.toByteArray())); - assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), - 636016770L, 709306L, 88038768L, 518836L); - } - - public void testReadLegacyUid() throws Exception { - final File testFile = new File(getContext().getFilesDir(), TEST_FILE); - stageFile(R.raw.netstats_uid_v4, testFile); - - final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS); - collection.readLegacyUid(testFile, false); - - // verify that history read correctly - assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), - 637076152L, 711413L, 88343717L, 521022L); - - // now export into a unified format - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - collection.write(new DataOutputStream(bos)); - - // clear structure completely - collection.reset(); - assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), - 0L, 0L, 0L, 0L); - - // and read back into structure, verifying that totals are same - collection.read(new ByteArrayInputStream(bos.toByteArray())); - assertSummaryTotal(collection, buildTemplateMobileAll(TEST_IMSI), - 637076152L, 711413L, 88343717L, 521022L); - } - - public void testReadLegacyUidTags() throws Exception { - final File testFile = new File(getContext().getFilesDir(), TEST_FILE); - stageFile(R.raw.netstats_uid_v4, testFile); - - final NetworkStatsCollection collection = new NetworkStatsCollection(30 * MINUTE_IN_MILLIS); - collection.readLegacyUid(testFile, true); - - // verify that history read correctly - assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI), - 77017831L, 100995L, 35436758L, 92344L); - - // now export into a unified format - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - collection.write(new DataOutputStream(bos)); - - // clear structure completely - collection.reset(); - assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI), - 0L, 0L, 0L, 0L); - - // and read back into structure, verifying that totals are same - collection.read(new ByteArrayInputStream(bos.toByteArray())); - assertSummaryTotalIncludingTags(collection, buildTemplateMobileAll(TEST_IMSI), - 77017831L, 100995L, 35436758L, 92344L); - } - - public void testStartEndAtomicBuckets() throws Exception { - final NetworkStatsCollection collection = new NetworkStatsCollection(HOUR_IN_MILLIS); - - // record empty data straddling between buckets - final NetworkStats.Entry entry = new NetworkStats.Entry(); - entry.rxBytes = 32; - collection.recordData(null, UID_ALL, SET_DEFAULT, TAG_NONE, 30 * MINUTE_IN_MILLIS, - 90 * MINUTE_IN_MILLIS, entry); - - // assert that we report boundary in atomic buckets - assertEquals(0, collection.getStartMillis()); - assertEquals(2 * HOUR_IN_MILLIS, collection.getEndMillis()); - } - - /** - * Copy a {@link Resources#openRawResource(int)} into {@link File} for - * testing purposes. - */ - private void stageFile(int rawId, File file) throws Exception { - new File(file.getParent()).mkdirs(); - InputStream in = null; - OutputStream out = null; - try { - in = getContext().getResources().openRawResource(rawId); - out = new FileOutputStream(file); - Streams.copy(in, out); - } finally { - IoUtils.closeQuietly(in); - IoUtils.closeQuietly(out); - } - } - - private static void assertSummaryTotal(NetworkStatsCollection collection, - NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) { - final NetworkStats.Entry entry = collection.getSummary( - template, Long.MIN_VALUE, Long.MAX_VALUE).getTotal(null); - assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets); - } - - private static void assertSummaryTotalIncludingTags(NetworkStatsCollection collection, - NetworkTemplate template, long rxBytes, long rxPackets, long txBytes, long txPackets) { - final NetworkStats.Entry entry = collection.getSummary( - template, Long.MIN_VALUE, Long.MAX_VALUE).getTotalIncludingTags(null); - assertEntry(entry, rxBytes, rxPackets, txBytes, txPackets); - } - - private static void assertEntry( - NetworkStats.Entry entry, long rxBytes, long rxPackets, long txBytes, long txPackets) { - assertEquals("unexpected rxBytes", rxBytes, entry.rxBytes); - assertEquals("unexpected rxPackets", rxPackets, entry.rxPackets); - assertEquals("unexpected txBytes", txBytes, entry.txBytes); - assertEquals("unexpected txPackets", txPackets, entry.txPackets); - } -} diff --git a/tests/CoreTests/android/core/NsdServiceInfoTest.java b/tests/CoreTests/android/core/NsdServiceInfoTest.java deleted file mode 100644 index 5bf0167f1c..0000000000 --- a/tests/CoreTests/android/core/NsdServiceInfoTest.java +++ /dev/null @@ -1,163 +0,0 @@ -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()); - } -}