resolved conflicts for merge of 26ecc31f to honeycomb-plus-aosp
Change-Id: I23f42e247884f0c9d5ae4d3466213592dd3433d9
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 494e922..5b8076e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -164,15 +164,19 @@
public static final String EXTRA_ERRORED_TETHER = "erroredArray";
/**
+ * The absence of APN..
+ * @hide
+ */
+ public static final int TYPE_NONE = -1;
+
+ /**
* The Default Mobile data connection. When active, all data traffic
- * will use this connection by default. Should not coexist with other
- * default connections.
+ * will use this connection by default.
*/
public static final int TYPE_MOBILE = 0;
/**
* The Default WIFI data connection. When active, all data traffic
- * will use this connection by default. Should not coexist with other
- * default connections.
+ * will use this connection by default.
*/
public static final int TYPE_WIFI = 1;
/**
@@ -208,23 +212,47 @@
public static final int TYPE_MOBILE_HIPRI = 5;
/**
* The Default WiMAX data connection. When active, all data traffic
- * will use this connection by default. Should not coexist with other
- * default connections.
+ * will use this connection by default.
*/
public static final int TYPE_WIMAX = 6;
+
/**
- * Bluetooth data connection.
- * @hide
+ * The Default Bluetooth data connection. When active, all data traffic
+ * will use this connection by default.
*/
public static final int TYPE_BLUETOOTH = 7;
+
/** {@hide} */
public static final int TYPE_DUMMY = 8;
- /** {@hide} */
+
+ /**
+ * The Default Ethernet data connection. When active, all data traffic
+ * will use this connection by default.
+ */
public static final int TYPE_ETHERNET = 9;
- /** {@hide} TODO: Need to adjust this for WiMAX. */
- public static final int MAX_RADIO_TYPE = TYPE_ETHERNET;
- /** {@hide} TODO: Need to adjust this for WiMAX. */
- public static final int MAX_NETWORK_TYPE = TYPE_ETHERNET;
+ /**
+ * Over the air Adminstration.
+ * {@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;
+
+ /** {@hide} */
+ public static final int MAX_RADIO_TYPE = TYPE_MOBILE_CBS;
+
+ /** {@hide} */
+ public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_CBS;
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
@@ -273,6 +301,24 @@
}
}
+ /** @hide */
+ public LinkProperties getActiveLinkProperties() {
+ try {
+ return mService.getActiveLinkProperties();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /** @hide */
+ public LinkProperties getLinkProperties(int networkType) {
+ try {
+ return mService.getLinkProperties(networkType);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
/** {@hide} */
public boolean setRadios(boolean turnOn) {
try {
@@ -376,14 +422,14 @@
* <p>
* All applications that have background services that use the network
* should listen to {@link #ACTION_BACKGROUND_DATA_SETTING_CHANGED}.
- *
+ *
* @return Whether background data usage is allowed.
*/
public boolean getBackgroundDataSetting() {
try {
return mService.getBackgroundDataSetting();
} catch (RemoteException e) {
- // Err on the side of safety
+ // Err on the side of safety
return false;
}
}
@@ -541,6 +587,17 @@
}
}
+ /**
+ * {@hide}
+ */
+ public String[] getTetherableBluetoothRegexs() {
+ try {
+ return mService.getTetherableBluetoothRegexs();
+ } catch (RemoteException e) {
+ return new String[0];
+ }
+ }
+
/** {@hide} */
public static final int TETHER_ERROR_NO_ERROR = 0;
/** {@hide} */
@@ -579,6 +636,21 @@
}
/**
+ * Ensure the device stays awake until we connect with the next network
+ * @param forWhome The name of the network going down for logging purposes
+ * @return {@code true} on success, {@code false} on failure
+ * {@hide}
+ */
+ public boolean requestNetworkTransitionWakelock(String forWhom) {
+ try {
+ mService.requestNetworkTransitionWakelock(forWhom);
+ return true;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
* @param networkType The type of network you want to report on
* @param percentage The quality of the connection 0 is bad, 100 is good
* {@hide}
@@ -589,4 +661,51 @@
} catch (RemoteException e) {
}
}
+
+ /**
+ * @param proxyProperties The definition for the new global http proxy
+ * {@hide}
+ */
+ public void setGlobalProxy(ProxyProperties p) {
+ try {
+ mService.setGlobalProxy(p);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * @return proxyProperties for the current global proxy
+ * {@hide}
+ */
+ public ProxyProperties getGlobalProxy() {
+ try {
+ return mService.getGlobalProxy();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @return proxyProperties for the current proxy (global if set, network specific if not)
+ * {@hide}
+ */
+ public ProxyProperties getProxy() {
+ try {
+ return mService.getProxy();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * @param networkType The network who's dependence has changed
+ * @param met Boolean - true if network use is ok, false if not
+ * {@hide}
+ */
+ public void setDataDependency(int networkType, boolean met) {
+ try {
+ mService.setDataDependency(networkType, met);
+ } catch (RemoteException e) {
+ }
+ }
}
diff --git a/core/java/android/net/DhcpInfo.java b/core/java/android/net/DhcpInfo.java
index 1178bec..e2660e4 100644
--- a/core/java/android/net/DhcpInfo.java
+++ b/core/java/android/net/DhcpInfo.java
@@ -18,6 +18,7 @@
import android.os.Parcelable;
import android.os.Parcel;
+import java.net.InetAddress;
/**
* A simple object for retrieving the results of a DHCP request.
@@ -37,6 +38,19 @@
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();
@@ -52,10 +66,7 @@
}
private static void putAddress(StringBuffer buf, int addr) {
- buf.append(addr & 0xff).append('.').
- append((addr >>>= 8) & 0xff).append('.').
- append((addr >>>= 8) & 0xff).append('.').
- append((addr >>>= 8) & 0xff);
+ buf.append(NetworkUtils.intToInetAddress(addr).getHostAddress());
}
/** Implement the Parcelable interface {@hide} */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index afccdd9..8be492c 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -1,22 +1,24 @@
/**
* 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
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * http://www.apache.org/licenses/LICENSE-2.0
*
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
+ * 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.NetworkInfo;
+import android.net.ProxyProperties;
import android.os.IBinder;
/**
@@ -36,6 +38,10 @@
NetworkInfo[] getAllNetworkInfo();
+ LinkProperties getActiveLinkProperties();
+
+ LinkProperties getLinkProperties(int networkType);
+
boolean setRadios(boolean onOff);
boolean setRadio(int networkType, boolean turnOn);
@@ -75,5 +81,17 @@
String[] getTetherableWifiRegexs();
+ String[] getTetherableBluetoothRegexs();
+
+ void requestNetworkTransitionWakelock(in String forWhom);
+
void reportInetCondition(int networkType, int percentage);
+
+ ProxyProperties getGlobalProxy();
+
+ void setGlobalProxy(in ProxyProperties p);
+
+ ProxyProperties getProxy();
+
+ void setDataDependency(int networkType, boolean met);
}
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
new file mode 100644
index 0000000..f6a114c
--- /dev/null
+++ b/core/java/android/net/LinkAddress.java
@@ -0,0 +1,147 @@
+/*
+ * 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;
+
+/**
+ * Identifies an address of a network link
+ * @hide
+ */
+public class LinkAddress implements Parcelable {
+ /**
+ * IPv4 or IPv6 address.
+ */
+ private final InetAddress address;
+
+ /**
+ * Network prefix length
+ */
+ private final int prefixLength;
+
+ public LinkAddress(InetAddress address, int prefixLength) {
+ if (address == null || prefixLength < 0 ||
+ ((address instanceof Inet4Address) && prefixLength > 32) ||
+ (prefixLength > 128)) {
+ throw new IllegalArgumentException("Bad LinkAddress params " + address +
+ prefixLength);
+ }
+ this.address = address;
+ this.prefixLength = prefixLength;
+ }
+
+ public LinkAddress(InterfaceAddress interfaceAddress) {
+ this.address = interfaceAddress.getAddress();
+ this.prefixLength = interfaceAddress.getNetworkPrefixLength();
+ }
+
+ @Override
+ public String toString() {
+ return (address == null ? "" : (address.getHostAddress() + "/" + prefixLength));
+ }
+
+ /**
+ * Compares this {@code LinkAddress} instance against the specified address
+ * in {@code obj}. Two addresses are equal if their InetAddress and prefixLength
+ * are equal
+ *
+ * @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;
+ }
+
+ @Override
+ /*
+ * generate hashcode based on significant fields
+ */
+ public int hashCode() {
+ return ((null == address) ? 0 : address.hashCode()) + prefixLength;
+ }
+
+ /**
+ * Returns the InetAddress for this address.
+ */
+ public InetAddress getAddress() {
+ return address;
+ }
+
+ /**
+ * Get network prefix length
+ */
+ public int getNetworkPrefixLength() {
+ return prefixLength;
+ }
+
+ /**
+ * Implement the Parcelable interface
+ * @hide
+ */
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ public void writeToParcel(Parcel dest, int flags) {
+ if (address != null) {
+ dest.writeByte((byte)1);
+ dest.writeByteArray(address.getAddress());
+ dest.writeInt(prefixLength);
+ } else {
+ dest.writeByte((byte)0);
+ }
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ public static final Creator<LinkAddress> CREATOR =
+ new Creator<LinkAddress>() {
+ public LinkAddress createFromParcel(Parcel in) {
+ InetAddress address = null;
+ int prefixLength = 0;
+ if (in.readByte() == 1) {
+ try {
+ address = InetAddress.getByAddress(in.createByteArray());
+ prefixLength = in.readInt();
+ } catch (UnknownHostException e) { }
+ }
+ return new LinkAddress(address, prefixLength);
+ }
+
+ 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
new file mode 100644
index 0000000..132f3ba
--- /dev/null
+++ b/core/java/android/net/LinkProperties.java
@@ -0,0 +1,435 @@
+/*
+ * 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.ProxyProperties;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.text.TextUtils;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+
+/**
+ * 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.
+ *
+ * Because it's a single network, the dns's
+ * are interchangeable and don't need associating with
+ * particular addresses. The gateways similarly don't
+ * need associating with particular addresses.
+ *
+ * A dual stack interface works fine in this model:
+ * each address has it's own prefix length to describe
+ * the local network. The dns servers all return
+ * both v4 addresses and v6 addresses regardless of the
+ * address family of the server itself (rfc4213) and we
+ * don't care which is used. The gateways will be
+ * selected based on the destination address and the
+ * source address has no relavence.
+ * @hide
+ */
+public class LinkProperties implements Parcelable {
+
+ String mIfaceName;
+ private Collection<LinkAddress> mLinkAddresses = new ArrayList<LinkAddress>();
+ private Collection<InetAddress> mDnses = new ArrayList<InetAddress>();
+ private Collection<RouteInfo> mRoutes = new ArrayList<RouteInfo>();
+ private ProxyProperties mHttpProxy;
+
+ public static class CompareResult<T> {
+ public Collection<T> removed = new ArrayList<T>();
+ public Collection<T> added = new ArrayList<T>();
+
+ @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;
+ }
+ }
+
+ public LinkProperties() {
+ clear();
+ }
+
+ // copy constructor instead of clone
+ public LinkProperties(LinkProperties source) {
+ if (source != null) {
+ mIfaceName = source.getInterfaceName();
+ mLinkAddresses = source.getLinkAddresses();
+ mDnses = source.getDnses();
+ mRoutes = source.getRoutes();
+ mHttpProxy = (source.getHttpProxy() == null) ?
+ null : new ProxyProperties(source.getHttpProxy());
+ }
+ }
+
+ public void setInterfaceName(String iface) {
+ mIfaceName = iface;
+ }
+
+ public String getInterfaceName() {
+ return mIfaceName;
+ }
+
+ public Collection<InetAddress> getAddresses() {
+ Collection<InetAddress> addresses = new ArrayList<InetAddress>();
+ for (LinkAddress linkAddress : mLinkAddresses) {
+ addresses.add(linkAddress.getAddress());
+ }
+ return Collections.unmodifiableCollection(addresses);
+ }
+
+ public void addLinkAddress(LinkAddress address) {
+ if (address != null) mLinkAddresses.add(address);
+ }
+
+ public Collection<LinkAddress> getLinkAddresses() {
+ return Collections.unmodifiableCollection(mLinkAddresses);
+ }
+
+ public void addDns(InetAddress dns) {
+ if (dns != null) mDnses.add(dns);
+ }
+
+ public Collection<InetAddress> getDnses() {
+ return Collections.unmodifiableCollection(mDnses);
+ }
+
+ public void addRoute(RouteInfo route) {
+ if (route != null) mRoutes.add(route);
+ }
+ public Collection<RouteInfo> getRoutes() {
+ return Collections.unmodifiableCollection(mRoutes);
+ }
+
+ public void setHttpProxy(ProxyProperties proxy) {
+ mHttpProxy = proxy;
+ }
+ public ProxyProperties getHttpProxy() {
+ return mHttpProxy;
+ }
+
+ public void clear() {
+ mIfaceName = null;
+ mLinkAddresses.clear();
+ mDnses.clear();
+ mRoutes.clear();
+ mHttpProxy = null;
+ }
+
+ /**
+ * 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 routes = "Routes: [";
+ for (RouteInfo route : mRoutes) routes += route.toString() + ",";
+ routes += "] ";
+ String proxy = (mHttpProxy == null ? "" : "HttpProxy: " + mHttpProxy.toString() + " ");
+
+ return ifaceName + linkAddresses + routes + dns + proxy;
+ }
+
+ /**
+ * Compares this {@code LinkProperties} interface name against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalInterfaceName(LinkProperties target) {
+ return TextUtils.equals(getInterfaceName(), target.getInterfaceName());
+ }
+
+ /**
+ * Compares this {@code LinkProperties} interface name against the target
+ *
+ * @param target LinkProperties to compare.
+ * @return {@code true} if both are identical, {@code false} otherwise.
+ */
+ public boolean isIdenticalAddresses(LinkProperties target) {
+ Collection<InetAddress> targetAddresses = target.getAddresses();
+ Collection<InetAddress> 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.
+ */
+ public boolean isIdenticalDnses(LinkProperties target) {
+ Collection<InetAddress> targetDnses = target.getDnses();
+ 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.
+ */
+ public boolean isIdenticalRoutes(LinkProperties target) {
+ Collection<RouteInfo> 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.
+ */
+ public boolean isIdenticalHttpProxy(LinkProperties target) {
+ return getHttpProxy() == null ? target.getHttpProxy() == null :
+ getHttpProxy().equals(target.getHttpProxy());
+ }
+
+ @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;
+
+ return isIdenticalInterfaceName(target) &&
+ isIdenticalAddresses(target) &&
+ isIdenticalDnses(target) &&
+ isIdenticalRoutes(target) &&
+ isIdenticalHttpProxy(target);
+ }
+
+ /**
+ * Return two lists, a list of addresses that would be removed from
+ * mLinkAddresses and a list of addresses that would be added to
+ * mLinkAddress which would then result in target and mLinkAddresses
+ * being the same list.
+ *
+ * @param target is a LinkProperties with the new list of addresses
+ * @return the removed and added lists.
+ */
+ public CompareResult<LinkAddress> 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<LinkAddress> result = new CompareResult<LinkAddress>();
+ result.removed = new ArrayList<LinkAddress>(mLinkAddresses);
+ result.added.clear();
+ if (target != null) {
+ for (LinkAddress newAddress : target.getLinkAddresses()) {
+ if (! result.removed.remove(newAddress)) {
+ result.added.add(newAddress);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return two lists, a list of dns addresses that would be removed from
+ * mDnses and a list of addresses that would be added to
+ * mDnses which would then result in target and mDnses
+ * being the same list.
+ *
+ * @param target is a LinkProperties with the new list of dns addresses
+ * @return the removed and added lists.
+ */
+ public CompareResult<InetAddress> 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<InetAddress> result = new CompareResult<InetAddress>();
+
+ result.removed = new ArrayList<InetAddress>(mDnses);
+ result.added.clear();
+ if (target != null) {
+ for (InetAddress newAddress : target.getDnses()) {
+ if (! result.removed.remove(newAddress)) {
+ result.added.add(newAddress);
+ }
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Return two lists, a list of routes that would be removed from
+ * mRoutes and a list of routes that would be added to
+ * mRoutes which would then result in target and mRoutes
+ * being the same list.
+ *
+ * @param target is a LinkProperties with the new list of routes
+ * @return the removed and added lists.
+ */
+ public CompareResult<RouteInfo> compareRoutes(LinkProperties target) {
+ /*
+ * Duplicate the RouteInfos into removed, we will be removing
+ * routes which are common between mDnses and target
+ * leaving the routes that are different. And route address which
+ * are in target but not in mRoutes are placed in added.
+ */
+ CompareResult<RouteInfo> result = new CompareResult<RouteInfo>();
+
+ result.removed = new ArrayList<RouteInfo>(mRoutes);
+ result.added.clear();
+ if (target != null) {
+ for (RouteInfo r : target.getRoutes()) {
+ 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
+ + mRoutes.size() * 41
+ + ((null == mHttpProxy) ? 0 : mHttpProxy.hashCode()));
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ 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.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);
+ }
+ }
+
+ /**
+ * Implement the Parcelable interface.
+ * @hide
+ */
+ public static final Creator<LinkProperties> CREATOR =
+ new Creator<LinkProperties>() {
+ public LinkProperties createFromParcel(Parcel in) {
+ LinkProperties netProp = new LinkProperties();
+ String iface = in.readString();
+ if (iface != null) {
+ try {
+ netProp.setInterfaceName(iface);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+ int addressCount = in.readInt();
+ for (int i=0; i<addressCount; i++) {
+ netProp.addLinkAddress((LinkAddress)in.readParcelable(null));
+ }
+ addressCount = in.readInt();
+ for (int i=0; i<addressCount; i++) {
+ try {
+ netProp.addDns(InetAddress.getByAddress(in.createByteArray()));
+ } catch (UnknownHostException e) { }
+ }
+ addressCount = in.readInt();
+ for (int i=0; i<addressCount; i++) {
+ netProp.addRoute((RouteInfo)in.readParcelable(null));
+ }
+ if (in.readByte() == 1) {
+ netProp.setHttpProxy((ProxyProperties)in.readParcelable(null));
+ }
+ return netProp;
+ }
+
+ public LinkProperties[] newArray(int size) {
+ return new LinkProperties[size];
+ }
+ };
+}
diff --git a/core/java/android/net/NetworkConfig.java b/core/java/android/net/NetworkConfig.java
new file mode 100644
index 0000000..3cc0bc5
--- /dev/null
+++ b/core/java/android/net/NetworkConfig.java
@@ -0,0 +1,80 @@
+/*
+ * 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.util.Log;
+
+/**
+ * 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();
+ 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
index 649cb8c..5f5e11c 100644
--- a/core/java/android/net/NetworkInfo.java
+++ b/core/java/android/net/NetworkInfo.java
@@ -97,7 +97,7 @@
stateMap.put(DetailedState.DISCONNECTED, State.DISCONNECTED);
stateMap.put(DetailedState.FAILED, State.DISCONNECTED);
}
-
+
private int mNetworkType;
private int mSubtype;
private String mTypeName;
@@ -121,7 +121,10 @@
*/
public NetworkInfo(int type) {}
- NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
+ /**
+ * @hide
+ */
+ public NetworkInfo(int type, int subtype, String typeName, String subtypeName) {
if (!ConnectivityManager.isNetworkTypeValid(type)) {
throw new IllegalArgumentException("Invalid network type: " + type);
}
@@ -141,7 +144,9 @@
* @return the network type
*/
public int getType() {
- return mNetworkType;
+ synchronized (this) {
+ return mNetworkType;
+ }
}
/**
@@ -150,12 +155,16 @@
* @return the network subtype
*/
public int getSubtype() {
- return mSubtype;
+ synchronized (this) {
+ return mSubtype;
+ }
}
void setSubtype(int subtype, String subtypeName) {
- mSubtype = subtype;
- mSubtypeName = subtypeName;
+ synchronized (this) {
+ mSubtype = subtype;
+ mSubtypeName = subtypeName;
+ }
}
/**
@@ -164,7 +173,9 @@
* @return the name of the network type
*/
public String getTypeName() {
- return mTypeName;
+ synchronized (this) {
+ return mTypeName;
+ }
}
/**
@@ -172,7 +183,9 @@
* @return the name of the network subtype
*/
public String getSubtypeName() {
- return mSubtypeName;
+ synchronized (this) {
+ return mSubtypeName;
+ }
}
/**
@@ -185,7 +198,9 @@
* of being established, {@code false} otherwise.
*/
public boolean isConnectedOrConnecting() {
- return mState == State.CONNECTED || mState == State.CONNECTING;
+ synchronized (this) {
+ return mState == State.CONNECTED || mState == State.CONNECTING;
+ }
}
/**
@@ -194,7 +209,9 @@
* @return {@code true} if network connectivity exists, {@code false} otherwise.
*/
public boolean isConnected() {
- return mState == State.CONNECTED;
+ synchronized (this) {
+ return mState == State.CONNECTED;
+ }
}
/**
@@ -210,7 +227,9 @@
* @return {@code true} if the network is available, {@code false} otherwise
*/
public boolean isAvailable() {
- return mIsAvailable;
+ synchronized (this) {
+ return mIsAvailable;
+ }
}
/**
@@ -220,7 +239,9 @@
* @hide
*/
public void setIsAvailable(boolean isAvailable) {
- mIsAvailable = isAvailable;
+ synchronized (this) {
+ mIsAvailable = isAvailable;
+ }
}
/**
@@ -231,7 +252,9 @@
* otherwise.
*/
public boolean isFailover() {
- return mIsFailover;
+ synchronized (this) {
+ return mIsFailover;
+ }
}
/**
@@ -241,7 +264,9 @@
* @hide
*/
public void setFailover(boolean isFailover) {
- mIsFailover = isFailover;
+ synchronized (this) {
+ mIsFailover = isFailover;
+ }
}
/**
@@ -251,11 +276,15 @@
* @return {@code true} if roaming is in effect, {@code false} otherwise.
*/
public boolean isRoaming() {
- return mIsRoaming;
+ synchronized (this) {
+ return mIsRoaming;
+ }
}
void setRoaming(boolean isRoaming) {
- mIsRoaming = isRoaming;
+ synchronized (this) {
+ mIsRoaming = isRoaming;
+ }
}
/**
@@ -263,7 +292,9 @@
* @return the coarse-grained state
*/
public State getState() {
- return mState;
+ synchronized (this) {
+ return mState;
+ }
}
/**
@@ -271,7 +302,9 @@
* @return the fine-grained state
*/
public DetailedState getDetailedState() {
- return mDetailedState;
+ synchronized (this) {
+ return mDetailedState;
+ }
}
/**
@@ -281,12 +314,15 @@
* 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
*/
- void setDetailedState(DetailedState detailedState, String reason, String extraInfo) {
- this.mDetailedState = detailedState;
- this.mState = stateMap.get(detailedState);
- this.mReason = reason;
- this.mExtraInfo = extraInfo;
+ 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;
+ }
}
/**
@@ -295,7 +331,9 @@
* @return the reason for failure, or null if not available
*/
public String getReason() {
- return mReason;
+ synchronized (this) {
+ return mReason;
+ }
}
/**
@@ -305,20 +343,24 @@
* @return the extra information, or null if not available
*/
public String getExtraInfo() {
- return mExtraInfo;
+ synchronized (this) {
+ return mExtraInfo;
+ }
}
@Override
public String toString() {
- StringBuilder builder = new StringBuilder("NetworkInfo: ");
- 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);
- return builder.toString();
+ synchronized (this) {
+ StringBuilder builder = new StringBuilder("NetworkInfo: ");
+ 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);
+ return builder.toString();
+ }
}
/**
@@ -334,17 +376,19 @@
* @hide
*/
public void writeToParcel(Parcel dest, int flags) {
- 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.writeString(mReason);
- dest.writeString(mExtraInfo);
+ 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.writeString(mReason);
+ dest.writeString(mExtraInfo);
+ }
}
/**
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 8bdfdf9..76534ef 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -38,30 +38,22 @@
/** 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;
+
/**
- * Add a route to the routing table.
+ * Reset IPv6 or IPv4 sockets that are connected via the named interface.
*
- * @param interfaceName the interface to route through.
- * @param dst the network or host to route to. May be IPv4 or IPv6, e.g.
- * "0.0.0.0" or "2001:4860::".
- * @param prefixLength the prefix length of the route.
- * @param gw the gateway to use, e.g., "192.168.251.1". If null,
- * indicates a directly-connected route.
+ * @param interfaceName is the interface to reset
+ * @param mask {@see #RESET_IPV4_ADDRESSES} and {@see #RESET_IPV6_ADDRESSES}
*/
- public native static int addRoute(String interfaceName, String dst,
- int prefixLength, String gw);
-
- /** Return the gateway address for the default route for the named interface. */
- public native static int getDefaultRoute(String interfaceName);
-
- /** Remove host routes that uses the named interface. */
- public native static int removeHostRoutes(String interfaceName);
-
- /** Remove the default route for the named interface. */
- public native static int removeDefaultRoute(String interfaceName);
-
- /** Reset any sockets that are connected via the named interface. */
- public native static int resetConnections(String interfaceName);
+ public native static int resetConnections(String interfaceName, int mask);
/**
* Start the DHCP client daemon, in order to have it request addresses
@@ -73,7 +65,17 @@
* the IP address information.
* @return {@code true} for success, {@code false} for failure
*/
- public native static boolean runDhcp(String interfaceName, DhcpInfo ipInfo);
+ public native static boolean runDhcp(String interfaceName, DhcpInfoInternal ipInfo);
+
+ /**
+ * 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 ipInfo 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, DhcpInfoInternal ipInfo);
/**
* Shut down the DHCP client daemon.
@@ -100,125 +102,137 @@
public native static String getDhcpError();
/**
- * When static IP configuration has been specified, configure the network
- * interface according to the values supplied.
- * @param interfaceName the name of the interface to configure
- * @param ipInfo the IP address, default gateway, and DNS server addresses
- * with which to configure the interface.
- * @return {@code true} for success, {@code false} for failure
- */
- public static boolean configureInterface(String interfaceName, DhcpInfo ipInfo) {
- return configureNative(interfaceName,
- ipInfo.ipAddress,
- ipInfo.netmask,
- ipInfo.gateway,
- ipInfo.dns1,
- ipInfo.dns2);
- }
-
- private native static boolean configureNative(
- String interfaceName, int ipAddress, int netmask, int gateway, int dns1, int dns2);
-
- /**
* Convert a IPv4 address from an integer to an InetAddress.
- * @param hostAddr is an Int corresponding to the IPv4 address in network byte order
- * @return the IP address as an {@code InetAddress}, returns null if
- * unable to convert or if the int is an invalid address.
+ * @param hostAddress an int corresponding to the IPv4 address in network byte order
*/
public static InetAddress intToInetAddress(int hostAddress) {
- InetAddress inetAddress;
byte[] addressBytes = { (byte)(0xff & hostAddress),
(byte)(0xff & (hostAddress >> 8)),
(byte)(0xff & (hostAddress >> 16)),
(byte)(0xff & (hostAddress >> 24)) };
try {
- inetAddress = InetAddress.getByAddress(addressBytes);
- } catch(UnknownHostException e) {
- return null;
+ return InetAddress.getByAddress(addressBytes);
+ } catch (UnknownHostException e) {
+ throw new AssertionError();
}
-
- return inetAddress;
}
/**
- * Add a default route through the specified gateway.
- * @param interfaceName interface on which the route should be added
- * @param gw the IP address of the gateway to which the route is desired,
- * @return {@code true} on success, {@code false} on failure
+ * 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 boolean addDefaultRoute(String interfaceName, InetAddress gw) {
- String dstStr;
- String gwStr = gw.getHostAddress();
-
- if (gw instanceof Inet4Address) {
- dstStr = "0.0.0.0";
- } else if (gw instanceof Inet6Address) {
- dstStr = "::";
- } else {
- Log.w(TAG, "addDefaultRoute failure: address is neither IPv4 nor IPv6" +
- "(" + gwStr + ")");
- return false;
+ public static int inetAddressToInt(InetAddress inetAddr)
+ throws IllegalArgumentException {
+ byte [] addr = inetAddr.getAddress();
+ if (addr.length != 4) {
+ throw new IllegalArgumentException("Not an IPv4 address");
}
- return addRoute(interfaceName, dstStr, 0, gwStr) == 0;
+ return ((addr[3] & 0xff) << 24) | ((addr[2] & 0xff) << 16) |
+ ((addr[1] & 0xff) << 8) | (addr[0] & 0xff);
}
/**
- * Add a host route.
- * @param interfaceName interface on which the route should be added
- * @param dst the IP address of the host to which the route is desired,
- * this should not be null.
- * @param gw the IP address of the gateway to which the route is desired,
- * if null, indicates a directly-connected route.
- * @return {@code true} on success, {@code false} on failure
+ * 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 boolean addHostRoute(String interfaceName, InetAddress dst,
- InetAddress gw) {
- if (dst == null) {
- Log.w(TAG, "addHostRoute: dst should not be null");
- return false;
+ public static int prefixLengthToNetmaskInt(int prefixLength)
+ throws IllegalArgumentException {
+ if (prefixLength < 0 || prefixLength > 32) {
+ throw new IllegalArgumentException("Invalid prefix length (0 <= prefix <= 32)");
}
-
- int prefixLength;
- String dstStr = dst.getHostAddress();
- String gwStr = (gw != null) ? gw.getHostAddress() : null;
-
- if (dst instanceof Inet4Address) {
- prefixLength = 32;
- } else if (dst instanceof Inet6Address) {
- prefixLength = 128;
- } else {
- Log.w(TAG, "addHostRoute failure: address is neither IPv4 nor IPv6" +
- "(" + dst + ")");
- return false;
- }
- return addRoute(interfaceName, dstStr, prefixLength, gwStr) == 0;
+ int value = 0xffffffff << (32 - prefixLength);
+ return Integer.reverseBytes(value);
}
- public static int v4StringToInt(String str) {
- int result = 0;
- String[] array = str.split("\\.");
- if (array.length != 4) return 0;
+ /**
+ * 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 {
- result = Integer.parseInt(array[3]);
- result = (result << 8) + Integer.parseInt(array[2]);
- result = (result << 8) + Integer.parseInt(array[1]);
- result = (result << 8) + Integer.parseInt(array[0]);
- } catch (NumberFormatException e) {
- return 0;
+ netPart = InetAddress.getByAddress(array);
+ } catch (UnknownHostException e) {
+ throw new RuntimeException("getNetworkPart error - " + e.toString());
}
- return result;
+ return netPart;
}
/**
- * Start the DHCP renew service for wimax,
- * 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 ipInfo if the request succeeds, this object is filled in with
- * the IP address information.
- * @return {@code true} for success, {@code false} for failure
- * {@hide}
+ * Check if IP address type is consistent between two InetAddress.
+ * @return true if both are the same type. False otherwise.
*/
- public native static boolean runDhcpRenew(String interfaceName, DhcpInfo ipInfo);
+ 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("%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);
+ }
+ }
}
diff --git a/core/java/android/net/ProxyProperties.java b/core/java/android/net/ProxyProperties.java
new file mode 100644
index 0000000..44dbec1
--- /dev/null
+++ b/core/java/android/net/ProxyProperties.java
@@ -0,0 +1,216 @@
+/*
+ * 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 android.util.Log;
+
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.UnknownHostException;
+
+/**
+ * A container class for the http proxy info
+ * @hide
+ */
+public class ProxyProperties implements Parcelable {
+
+ private String mHost;
+ private int mPort;
+ private String mExclusionList;
+ private String[] mParsedExclusionList;
+
+ public ProxyProperties(String host, int port, String exclList) {
+ mHost = host;
+ mPort = port;
+ setExclusionList(exclList);
+ }
+
+ private ProxyProperties(String host, int port, String exclList, String[] parsedExclList) {
+ mHost = host;
+ mPort = port;
+ mExclusionList = exclList;
+ mParsedExclusionList = parsedExclList;
+ }
+
+ // copy constructor instead of clone
+ public ProxyProperties(ProxyProperties source) {
+ if (source != null) {
+ mHost = source.getHost();
+ mPort = source.getPort();
+ mExclusionList = source.getExclusionList();
+ mParsedExclusionList = source.mParsedExclusionList;
+ }
+ }
+
+ public InetSocketAddress getSocketAddress() {
+ InetSocketAddress inetSocketAddress = null;
+ try {
+ inetSocketAddress = new InetSocketAddress(mHost, mPort);
+ } catch (IllegalArgumentException e) { }
+ return inetSocketAddress;
+ }
+
+ public String getHost() {
+ return mHost;
+ }
+
+ public int getPort() {
+ return mPort;
+ }
+
+ // comma separated
+ public String getExclusionList() {
+ return mExclusionList;
+ }
+
+ // comma separated
+ private void setExclusionList(String exclusionList) {
+ mExclusionList = exclusionList;
+ if (mExclusionList == null) {
+ mParsedExclusionList = new String[0];
+ } else {
+ String splitExclusionList[] = exclusionList.toLowerCase().split(",");
+ mParsedExclusionList = new String[splitExclusionList.length * 2];
+ for (int i = 0; i < splitExclusionList.length; i++) {
+ String s = splitExclusionList[i].trim();
+ if (s.startsWith(".")) s = s.substring(1);
+ mParsedExclusionList[i*2] = s;
+ mParsedExclusionList[(i*2)+1] = "." + s;
+ }
+ }
+ }
+
+ public boolean isExcluded(String url) {
+ if (TextUtils.isEmpty(url) || mParsedExclusionList == null ||
+ mParsedExclusionList.length == 0) return false;
+
+ Uri u = Uri.parse(url);
+ String urlDomain = u.getHost();
+ if (urlDomain == null) return false;
+ for (int i = 0; i< mParsedExclusionList.length; i+=2) {
+ if (urlDomain.equals(mParsedExclusionList[i]) ||
+ urlDomain.endsWith(mParsedExclusionList[i+1])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ 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 (mHost != null) {
+ sb.append("[");
+ sb.append(mHost);
+ sb.append("] ");
+ sb.append(Integer.toString(mPort));
+ if (mExclusionList != null) {
+ sb.append(" xl=").append(mExclusionList);
+ }
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (!(o instanceof ProxyProperties)) return false;
+ ProxyProperties p = (ProxyProperties)o;
+ if (mExclusionList != null && !mExclusionList.equals(p.getExclusionList())) 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 (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<ProxyProperties> CREATOR =
+ new Creator<ProxyProperties>() {
+ public ProxyProperties createFromParcel(Parcel in) {
+ String host = null;
+ int port = 0;
+ if (in.readByte() == 1) {
+ host = in.readString();
+ port = in.readInt();
+ }
+ String exclList = in.readString();
+ String[] parsedExclList = in.readStringArray();
+ ProxyProperties proxyProperties =
+ new ProxyProperties(host, port, exclList, parsedExclList);
+ return proxyProperties;
+ }
+
+ public ProxyProperties[] newArray(int size) {
+ return new ProxyProperties[size];
+ }
+ };
+}
diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java
new file mode 100644
index 0000000..275f32a
--- /dev/null
+++ b/core/java/android/net/RouteInfo.java
@@ -0,0 +1,257 @@
+/*
+ * 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;
+
+/**
+ * A simple container for route information.
+ *
+ * @hide
+ */
+public class RouteInfo implements Parcelable {
+ /**
+ * The IP destination address for this route.
+ */
+ private final LinkAddress mDestination;
+
+ /**
+ * The gateway address for this route.
+ */
+ private final InetAddress mGateway;
+
+ private final boolean mIsDefault;
+ private final boolean mIsHost;
+
+ public RouteInfo(LinkAddress destination, InetAddress gateway) {
+ 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 RuntimeException("Invalid arguments passed in.");
+ }
+ }
+ if (gateway == null) {
+ if (destination.getAddress() instanceof Inet4Address) {
+ gateway = Inet4Address.ANY;
+ } else {
+ gateway = Inet6Address.ANY;
+ }
+ }
+ mDestination = new LinkAddress(NetworkUtils.getNetworkPart(destination.getAddress(),
+ destination.getNetworkPrefixLength()), destination.getNetworkPrefixLength());
+ mGateway = gateway;
+ mIsDefault = isDefault();
+ mIsHost = isHost();
+ }
+
+ public RouteInfo(InetAddress gateway) {
+ this(null, gateway);
+ }
+
+ public static RouteInfo makeHostRoute(InetAddress host) {
+ return makeHostRoute(host, null);
+ }
+
+ public static RouteInfo makeHostRoute(InetAddress host, InetAddress gateway) {
+ if (host == null) return null;
+
+ if (host instanceof Inet4Address) {
+ return new RouteInfo(new LinkAddress(host, 32), gateway);
+ } else {
+ return new RouteInfo(new LinkAddress(host, 128), gateway);
+ }
+ }
+
+ private boolean isHost() {
+ return (mGateway.equals(Inet4Address.ANY) || mGateway.equals(Inet6Address.ANY));
+ }
+
+ private boolean isDefault() {
+ boolean val = false;
+ if (mGateway != null) {
+ if (mGateway instanceof Inet4Address) {
+ val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
+ } else {
+ val = (mDestination == null || mDestination.getNetworkPrefixLength() == 0);
+ }
+ }
+ return val;
+ }
+
+
+ public LinkAddress getDestination() {
+ return mDestination;
+ }
+
+ public InetAddress getGateway() {
+ return mGateway;
+ }
+
+ public boolean isDefaultRoute() {
+ return mIsDefault;
+ }
+
+ public boolean isHostRoute() {
+ return mIsHost;
+ }
+
+ public String toString() {
+ String val = "";
+ if (mDestination != null) val = mDestination.toString();
+ if (mGateway != null) val += " -> " + mGateway.getHostAddress();
+ return val;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mDestination == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeByteArray(mDestination.getAddress().getAddress());
+ dest.writeInt(mDestination.getNetworkPrefixLength());
+ }
+
+ if (mGateway == null) {
+ dest.writeByte((byte) 0);
+ } else {
+ dest.writeByte((byte) 1);
+ dest.writeByteArray(mGateway.getAddress());
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+
+ if (!(obj instanceof RouteInfo)) return false;
+
+ RouteInfo target = (RouteInfo) obj;
+
+ boolean sameDestination = ( mDestination == null) ?
+ target.getDestination() == null
+ : mDestination.equals(target.getDestination());
+
+ boolean sameAddress = (mGateway == null) ?
+ target.getGateway() == null
+ : mGateway.equals(target.getGateway());
+
+ return sameDestination && sameAddress
+ && mIsDefault == target.mIsDefault;
+ }
+
+ @Override
+ public int hashCode() {
+ return (mDestination == null ? 0 : mDestination.hashCode())
+ + (mGateway == null ? 0 :mGateway.hashCode())
+ + (mIsDefault ? 3 : 7);
+ }
+
+ public static final Creator<RouteInfo> CREATOR =
+ new Creator<RouteInfo>() {
+ 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) {}
+ }
+
+ LinkAddress dest = null;
+
+ if (destAddr != null) {
+ dest = new LinkAddress(destAddr, prefix);
+ }
+
+ return new RouteInfo(dest, gateway);
+ }
+
+ public RouteInfo[] newArray(int size) {
+ return new RouteInfo[size];
+ }
+ };
+
+ private boolean matches(InetAddress destination) {
+ if (destination == null) return false;
+
+ // if the destination is present and the route is default.
+ // return true
+ if (isDefault()) return true;
+
+ // match the route destination and destination with prefix length
+ InetAddress dstNet = NetworkUtils.getNetworkPart(destination,
+ mDestination.getNetworkPrefixLength());
+
+ return mDestination.getAddress().equals(dstNet);
+ }
+
+ /**
+ * Find the route from a Collection of routes that best matches a given address.
+ * May return null if no routes are applicable.
+ * @param routes a Collection of RouteInfos to chose from
+ * @param dest the InetAddress your trying to get to
+ * @return the RouteInfo from the Collection that best fits the given address
+ */
+ public static RouteInfo selectBestRoute(Collection<RouteInfo> routes, InetAddress dest) {
+ if ((routes == null) || (dest == null)) return null;
+
+ RouteInfo bestRoute = null;
+ // pick a longest prefix match under same address type
+ for (RouteInfo route : routes) {
+ if (NetworkUtils.addressTypeMatches(route.mDestination.getAddress(), dest)) {
+ if ((bestRoute != null) &&
+ (bestRoute.mDestination.getNetworkPrefixLength() >=
+ route.mDestination.getNetworkPrefixLength())) {
+ continue;
+ }
+ if (route.matches(dest)) bestRoute = route;
+ }
+ }
+ return bestRoute;
+ }
+}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 4d9bb3b..068fe67 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -21,37 +21,34 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
#include <arpa/inet.h>
+#include <cutils/properties.h>
extern "C" {
int ifc_enable(const char *ifname);
int ifc_disable(const char *ifname);
-int ifc_add_route(const char *ifname, const char *destStr, uint32_t prefixLen, const char *gwStr);
-int ifc_remove_host_routes(const char *ifname);
-int ifc_get_default_route(const char *ifname);
-int ifc_remove_default_route(const char *ifname);
-int ifc_reset_connections(const char *ifname);
-int ifc_configure(const char *ifname, in_addr_t ipaddr, in_addr_t netmask, in_addr_t gateway, in_addr_t dns1, in_addr_t dns2);
+int ifc_reset_connections(const char *ifname, int reset_mask);
int dhcp_do_request(const char *ifname,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
+ const char *ipaddr,
+ const char *gateway,
+ uint32_t *prefixLength,
+ const char *dns1,
+ const char *dns2,
+ const char *server,
uint32_t *lease);
+
+int dhcp_do_request_renew(const char *ifname,
+ const char *ipaddr,
+ const char *gateway,
+ uint32_t *prefixLength,
+ const char *dns1,
+ const char *dns2,
+ const char *server,
+ uint32_t *lease);
+
int dhcp_stop(const char *ifname);
int dhcp_release_lease(const char *ifname);
char *dhcp_get_errmsg();
-
-int dhcp_do_request_renew(const char *ifname,
- in_addr_t *ipaddr,
- in_addr_t *gateway,
- in_addr_t *mask,
- in_addr_t *dns1,
- in_addr_t *dns2,
- in_addr_t *server,
- uint32_t *lease);
}
#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
@@ -64,16 +61,15 @@
* to look them up every time.
*/
static struct fieldIds {
- jclass dhcpInfoClass;
+ jclass dhcpInfoInternalClass;
jmethodID constructorId;
jfieldID ipaddress;
- jfieldID gateway;
- jfieldID netmask;
+ jfieldID prefixLength;
jfieldID dns1;
jfieldID dns2;
jfieldID serverAddress;
jfieldID leaseDuration;
-} dhcpInfoFieldIds;
+} dhcpInfoInternalFieldIds;
static jint android_net_utils_enableInterface(JNIEnv* env, jobject clazz, jstring ifname)
{
@@ -95,88 +91,92 @@
return (jint)result;
}
-static jint android_net_utils_addRoute(JNIEnv* env, jobject clazz, jstring ifname,
- jstring dst, jint prefixLength, jstring gw)
+static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
+ jstring ifname, jint mask)
{
int result;
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- const char *dstStr = env->GetStringUTFChars(dst, NULL);
- const char *gwStr = NULL;
- if (gw != NULL) {
- gwStr = env->GetStringUTFChars(gw, NULL);
+
+ LOGD("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 info, 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 server[PROPERTY_VALUE_MAX];
+ uint32_t lease;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ if (nameStr == NULL) return (jboolean)false;
+
+ if (renew) {
+ result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
+ dns1, dns2, server, &lease);
+ } else {
+ result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
+ dns1, dns2, server, &lease);
}
- result = ::ifc_add_route(nameStr, dstStr, prefixLength, gwStr);
+
env->ReleaseStringUTFChars(ifname, nameStr);
- env->ReleaseStringUTFChars(dst, dstStr);
- if (gw != NULL) {
- env->ReleaseStringUTFChars(gw, gwStr);
+ if (result == 0 && dhcpInfoInternalFieldIds.dhcpInfoInternalClass != NULL) {
+ env->SetObjectField(info, dhcpInfoInternalFieldIds.ipaddress, env->NewStringUTF(ipaddr));
+
+ // set the gateway
+ jclass cls = env->FindClass("java/net/InetAddress");
+ jmethodID method = env->GetStaticMethodID(cls, "getByName",
+ "(Ljava/lang/String;)Ljava/net/InetAddress;");
+ jvalue args[1];
+ args[0].l = env->NewStringUTF(gateway);
+ jobject inetAddressObject = env->CallStaticObjectMethodA(cls, method, args);
+
+ if (!env->ExceptionOccurred()) {
+ cls = env->FindClass("android/net/RouteInfo");
+ method = env->GetMethodID(cls, "<init>", "(Ljava/net/InetAddress;)V");
+ args[0].l = inetAddressObject;
+ jobject routeInfoObject = env->NewObjectA(cls, method, args);
+
+ cls = env->FindClass("android/net/DhcpInfoInternal");
+ method = env->GetMethodID(cls, "addRoute", "(Landroid/net/RouteInfo;)V");
+ args[0].l = routeInfoObject;
+ env->CallVoidMethodA(info, method, args);
+ } else {
+ // if we have an exception (host not found perhaps), just don't add the route
+ env->ExceptionClear();
+ }
+
+ env->SetIntField(info, dhcpInfoInternalFieldIds.prefixLength, prefixLength);
+ env->SetObjectField(info, dhcpInfoInternalFieldIds.dns1, env->NewStringUTF(dns1));
+ env->SetObjectField(info, dhcpInfoInternalFieldIds.dns2, env->NewStringUTF(dns2));
+ env->SetObjectField(info, dhcpInfoInternalFieldIds.serverAddress,
+ env->NewStringUTF(server));
+ env->SetIntField(info, dhcpInfoInternalFieldIds.leaseDuration, lease);
}
- return (jint)result;
-}
-
-static jint android_net_utils_removeHostRoutes(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_remove_host_routes(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
-}
-
-static jint android_net_utils_getDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_get_default_route(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
-}
-
-static jint android_net_utils_removeDefaultRoute(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_remove_default_route(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
-}
-
-static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, jstring ifname)
-{
- int result;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_reset_connections(nameStr);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jint)result;
+ return (jboolean)(result == 0);
}
static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
{
- int result;
- in_addr_t ipaddr, gateway, mask, dns1, dns2, server;
- uint32_t lease;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::dhcp_do_request(nameStr, &ipaddr, &gateway, &mask,
- &dns1, &dns2, &server, &lease);
- env->ReleaseStringUTFChars(ifname, nameStr);
- if (result == 0 && dhcpInfoFieldIds.dhcpInfoClass != NULL) {
- env->SetIntField(info, dhcpInfoFieldIds.ipaddress, ipaddr);
- env->SetIntField(info, dhcpInfoFieldIds.gateway, gateway);
- env->SetIntField(info, dhcpInfoFieldIds.netmask, mask);
- env->SetIntField(info, dhcpInfoFieldIds.dns1, dns1);
- env->SetIntField(info, dhcpInfoFieldIds.dns2, dns2);
- env->SetIntField(info, dhcpInfoFieldIds.serverAddress, server);
- env->SetIntField(info, dhcpInfoFieldIds.leaseDuration, lease);
- }
- return (jboolean)(result == 0);
+ 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;
@@ -202,46 +202,6 @@
return env->NewStringUTF(::dhcp_get_errmsg());
}
-static jboolean android_net_utils_configureInterface(JNIEnv* env,
- jobject clazz,
- jstring ifname,
- jint ipaddr,
- jint mask,
- jint gateway,
- jint dns1,
- jint dns2)
-{
- int result;
- uint32_t lease;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::ifc_configure(nameStr, ipaddr, mask, gateway, dns1, dns2);
- env->ReleaseStringUTFChars(ifname, nameStr);
- return (jboolean)(result == 0);
-}
-
-static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
-{
- int result = -1;
- in_addr_t ipaddr, gateway, mask, dns1, dns2, server;
- uint32_t lease;
-
- const char *nameStr = env->GetStringUTFChars(ifname, NULL);
- result = ::dhcp_do_request_renew(nameStr, &ipaddr, &gateway, &mask,
- &dns1, &dns2, &server, &lease);
- env->ReleaseStringUTFChars(ifname, nameStr);
- if (result == 0 && dhcpInfoFieldIds.dhcpInfoClass != NULL) {
- env->SetIntField(info, dhcpInfoFieldIds.ipaddress, ipaddr);
- env->SetIntField(info, dhcpInfoFieldIds.gateway, gateway);
- env->SetIntField(info, dhcpInfoFieldIds.netmask, mask);
- env->SetIntField(info, dhcpInfoFieldIds.dns1, dns1);
- env->SetIntField(info, dhcpInfoFieldIds.dns2, dns2);
- env->SetIntField(info, dhcpInfoFieldIds.serverAddress, server);
- env->SetIntField(info, dhcpInfoFieldIds.leaseDuration, lease);
- }
-
- return (jboolean)(result == 0);
-}
// ----------------------------------------------------------------------------
/*
@@ -252,18 +212,12 @@
{ "enableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_enableInterface },
{ "disableInterface", "(Ljava/lang/String;)I", (void *)android_net_utils_disableInterface },
- { "addRoute", "(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;)I",
- (void *)android_net_utils_addRoute },
- { "removeHostRoutes", "(Ljava/lang/String;)I", (void *)android_net_utils_removeHostRoutes },
- { "getDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_getDefaultRoute },
- { "removeDefaultRoute", "(Ljava/lang/String;)I", (void *)android_net_utils_removeDefaultRoute },
- { "resetConnections", "(Ljava/lang/String;)I", (void *)android_net_utils_resetConnections },
- { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcp },
+ { "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
+ { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcp },
+ { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfoInternal;)Z", (void *)android_net_utils_runDhcpRenew },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
{ "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
- { "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
- { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcpRenew}
};
int register_android_net_NetworkUtils(JNIEnv* env)
@@ -271,16 +225,15 @@
jclass netutils = env->FindClass(NETUTILS_PKG_NAME);
LOG_FATAL_IF(netutils == NULL, "Unable to find class " NETUTILS_PKG_NAME);
- dhcpInfoFieldIds.dhcpInfoClass = env->FindClass("android/net/DhcpInfo");
- if (dhcpInfoFieldIds.dhcpInfoClass != NULL) {
- dhcpInfoFieldIds.constructorId = env->GetMethodID(dhcpInfoFieldIds.dhcpInfoClass, "<init>", "()V");
- dhcpInfoFieldIds.ipaddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "ipAddress", "I");
- dhcpInfoFieldIds.gateway = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "gateway", "I");
- dhcpInfoFieldIds.netmask = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "netmask", "I");
- dhcpInfoFieldIds.dns1 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns1", "I");
- dhcpInfoFieldIds.dns2 = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "dns2", "I");
- dhcpInfoFieldIds.serverAddress = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "serverAddress", "I");
- dhcpInfoFieldIds.leaseDuration = env->GetFieldID(dhcpInfoFieldIds.dhcpInfoClass, "leaseDuration", "I");
+ dhcpInfoInternalFieldIds.dhcpInfoInternalClass = env->FindClass("android/net/DhcpInfoInternal");
+ if (dhcpInfoInternalFieldIds.dhcpInfoInternalClass != NULL) {
+ dhcpInfoInternalFieldIds.constructorId = env->GetMethodID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "<init>", "()V");
+ dhcpInfoInternalFieldIds.ipaddress = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "ipAddress", "Ljava/lang/String;");
+ dhcpInfoInternalFieldIds.prefixLength = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "prefixLength", "I");
+ dhcpInfoInternalFieldIds.dns1 = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "dns1", "Ljava/lang/String;");
+ dhcpInfoInternalFieldIds.dns2 = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "dns2", "Ljava/lang/String;");
+ dhcpInfoInternalFieldIds.serverAddress = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "serverAddress", "Ljava/lang/String;");
+ dhcpInfoInternalFieldIds.leaseDuration = env->GetFieldID(dhcpInfoInternalFieldIds.dhcpInfoInternalClass, "leaseDuration", "I");
}
return AndroidRuntime::registerNativeMethods(env,
diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
new file mode 100644
index 0000000..e3b6b5f
--- /dev/null
+++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.net.InetAddress;
+
+public class LinkPropertiesTest extends TestCase {
+ private static String ADDRV4 = "75.208.6.1";
+ private static String ADDRV6 = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
+ private static String DNS1 = "75.208.7.1";
+ private static String DNS2 = "69.78.7.1";
+ private static String GATEWAY1 = "75.208.8.1";
+ private static String GATEWAY2 = "69.78.8.1";
+ private static String NAME = "qmi0";
+
+ @SmallTest
+ public void testEqualsNull() {
+ LinkProperties source = new LinkProperties();
+ LinkProperties target = new LinkProperties();
+
+ assertFalse(source == target);
+ assertTrue(source.equals(target));
+ assertTrue(source.hashCode() == target.hashCode());
+ }
+
+ @SmallTest
+ public void testEqualsSameOrder() {
+ try {
+ LinkProperties source = new LinkProperties();
+ source.setInterfaceName(NAME);
+ // set 2 link addresses
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ // set 2 dnses
+ source.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ source.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ // set 2 gateways
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+
+ LinkProperties target = new LinkProperties();
+
+ // All fields are same
+ target.setInterfaceName(NAME);
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+
+ assertTrue(source.equals(target));
+ assertTrue(source.hashCode() == target.hashCode());
+
+ target.clear();
+ // change Interface Name
+ target.setInterfaceName("qmi1");
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+ 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(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+ assertFalse(source.equals(target));
+
+ target.clear();
+ target.setInterfaceName(NAME);
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ // change dnses
+ target.addDns(NetworkUtils.numericToInetAddress("75.208.7.2"));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+ assertFalse(source.equals(target));
+
+ target.clear();
+ target.setInterfaceName(NAME);
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ // change gateway
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress("75.208.8.2")));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+ 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(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ // set 2 dnses
+ source.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ source.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ // set 2 gateways
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+ source.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+
+ LinkProperties target = new LinkProperties();
+ // Exchange order
+ target.setInterfaceName(NAME);
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS2));
+ target.addDns(NetworkUtils.numericToInetAddress(DNS1));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY2)));
+ target.addRoute(new RouteInfo(NetworkUtils.numericToInetAddress(GATEWAY1)));
+
+ assertTrue(source.equals(target));
+ assertTrue(source.hashCode() == target.hashCode());
+ } catch (Exception e) {
+ fail();
+ }
+ }
+
+ @SmallTest
+ public void testEqualsDuplicated() {
+ try {
+ LinkProperties source = new LinkProperties();
+ // set 3 link addresses, eg, [A, A, B]
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ source.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+
+ LinkProperties target = new LinkProperties();
+ // set 3 link addresses, eg, [A, B, B]
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV4), 32));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+ target.addLinkAddress(new LinkAddress(
+ NetworkUtils.numericToInetAddress(ADDRV6), 128));
+
+ assertTrue(source.equals(target));
+ assertTrue(source.hashCode() == target.hashCode());
+ } catch (Exception e) {
+ fail();
+ }
+ }
+
+}
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 6cd3e9e..335d3fe 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -16,29 +16,37 @@
package com.android.server;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.content.Context;
+import android.bluetooth.BluetoothTetheringDataTracker;
import android.content.ContentResolver;
-import android.content.ContextWrapper;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
+import android.database.ContentObserver;
import android.net.ConnectivityManager;
+import android.net.DummyDataStateTracker;
+import android.net.EthernetDataTracker;
import android.net.IConnectivityManager;
+import android.net.LinkAddress;
+import android.net.LinkProperties;
+import android.net.LinkProperties.CompareResult;
import android.net.MobileDataStateTracker;
+import android.net.NetworkConfig;
import android.net.NetworkInfo;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
+import android.net.Proxy;
+import android.net.ProxyProperties;
+import android.net.RouteInfo;
+import android.net.vpn.VpnManager;
import android.net.wifi.WifiStateTracker;
-import android.net.wimax.WimaxManagerConstants;
import android.os.Binder;
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.INetworkManagementService;
+import android.os.PowerManager;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
@@ -46,29 +54,31 @@
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
+
import com.android.internal.telephony.Phone;
import com.android.server.connectivity.Tethering;
-import dalvik.system.DexClassLoader;
+
import java.io.FileDescriptor;
+import java.io.FileWriter;
+import java.io.IOException;
import java.io.PrintWriter;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.InvocationTargetException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
+import java.net.Inet4Address;
+import java.net.UnknownHostException;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.GregorianCalendar;
import java.util.List;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-
/**
* @hide
*/
public class ConnectivityService extends IConnectivityManager.Stub {
- private static final boolean DBG = false;
+ private static final boolean DBG = true;
+ private static final boolean VDBG = true;
private static final String TAG = "ConnectivityService";
// how long to wait before switching back to a radio's default network
@@ -77,6 +87,9 @@
private static final String NETWORK_RESTORE_DELAY_PROP_NAME =
"android.telephony.apn-restore";
+ // 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 boolean mTetheringConfigValid = false;
@@ -89,11 +102,18 @@
private NetworkStateTracker mNetTrackers[];
/**
+ * 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[];
+ private WifiWatchdogService mWifiWatchdogService;
+
// priority order of the nettrackers
// (excluding dynamically set mNetworkPreference)
// TODO - move mNetworkTypePreference into this
@@ -113,6 +133,8 @@
private boolean mTestMode;
private static ConnectivityService sServiceInstance;
+ private AtomicBoolean mBackgroundDataEnabled = new AtomicBoolean(true);
+
private INetworkManagementService mNetd;
private static final int ENABLED = 1;
@@ -173,41 +195,60 @@
private static final int EVENT_SET_MOBILE_DATA =
MAX_NETWORK_STATE_TRACKER_EVENT + 7;
+ /**
+ * used internally to clear a wakelock when transitioning
+ * from one net to another
+ */
+ private static final int EVENT_CLEAR_NET_TRANSITION_WAKELOCK =
+ MAX_NETWORK_STATE_TRACKER_EVENT + 8;
+
+ /**
+ * used internally to reload global proxy settings
+ */
+ private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY =
+ MAX_NETWORK_STATE_TRACKER_EVENT + 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 =
+ MAX_NETWORK_STATE_TRACKER_EVENT + 10;
+
private Handler mHandler;
// list of DeathRecipients used to make sure features are turned off when
// a process dies
- private List mFeatureUsers;
+ private List<FeatureUser> mFeatureUsers;
private boolean mSystemReady;
private Intent mInitialBroadcast;
+ private PowerManager.WakeLock mNetTransitionWakeLock;
+ private String mNetTransitionWakeLockCausedBy = "";
+ private int mNetTransitionWakeLockSerialNumber;
+ private int mNetTransitionWakeLockTimeout;
+
+ private InetAddress mDefaultDns;
+
+ // 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
+ private Collection<RouteInfo> mAddedRoutes = new ArrayList<RouteInfo>();
+
// used in DBG mode to track inet condition reports
private static final int INET_CONDITION_LOG_MAX_SIZE = 15;
private ArrayList mInetLog;
- private static class NetworkAttributes {
- /**
- * Class for holding settings read from resources.
- */
- public String mName;
- public int mType;
- public int mRadio;
- public int mPriority;
- public NetworkInfo.State mLastState;
- public NetworkAttributes(String init) {
- String fragments[] = init.split(",");
- mName = fragments[0].toLowerCase();
- mType = Integer.parseInt(fragments[1]);
- mRadio = Integer.parseInt(fragments[2]);
- mPriority = Integer.parseInt(fragments[3]);
- mLastState = NetworkInfo.State.UNKNOWN;
- }
- public boolean isDefault() {
- return (mType == mRadio);
- }
- }
- NetworkAttributes[] mNetAttributes;
+ // track the current default http proxy - tell the world if we get a new one (real change)
+ private ProxyProperties mDefaultProxy = null;
+ // track the global proxy.
+ private ProxyProperties mGlobalProxy = null;
+ private final Object mGlobalProxyLock = new Object();
+
+ private SettingsObserver mSettingsObserver;
+
+ NetworkConfig[] mNetConfigs;
int mNetworksDefined;
private static class RadioAttributes {
@@ -221,69 +262,64 @@
}
RadioAttributes[] mRadioAttributes;
- private static class ConnectivityThread extends Thread {
- private Context mContext;
+ // the set of network types that can only be enabled by system/sig apps
+ List mProtectedNetworks;
- private ConnectivityThread(Context context) {
- super("ConnectivityThread");
- mContext = context;
+ public static synchronized ConnectivityService getInstance(Context context) {
+ if (sServiceInstance == null) {
+ sServiceInstance = new ConnectivityService(context);
}
-
- @Override
- public void run() {
- Looper.prepare();
- synchronized (this) {
- sServiceInstance = new ConnectivityService(mContext);
- notifyAll();
- }
- Looper.loop();
- }
-
- public static ConnectivityService getServiceInstance(Context context) {
- ConnectivityThread thread = new ConnectivityThread(context);
- thread.start();
-
- synchronized (thread) {
- while (sServiceInstance == null) {
- try {
- // Wait until sServiceInstance has been initialized.
- thread.wait();
- } catch (InterruptedException ignore) {
- Slog.e(TAG,
- "Unexpected InterruptedException while waiting"+
- " for ConnectivityService thread");
- }
- }
- }
-
- return sServiceInstance;
- }
- }
-
- public static ConnectivityService getInstance(Context context) {
- return ConnectivityThread.getServiceInstance(context);
+ return sServiceInstance;
}
private ConnectivityService(Context context) {
- if (DBG) Slog.v(TAG, "ConnectivityService starting up");
+ if (DBG) log("ConnectivityService starting up");
+
+ HandlerThread handlerThread = new HandlerThread("ConnectivityServiceThread");
+ handlerThread.start();
+ mHandler = new MyHandler(handlerThread.getLooper());
+
+ mBackgroundDataEnabled.set(Settings.Secure.getInt(context.getContentResolver(),
+ Settings.Secure.BACKGROUND_DATA, 1) == 1);
// setup our unique device name
- 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);
+ 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.Secure.getString(context.getContentResolver(),
+ Settings.Secure.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 = context;
+
+ PowerManager powerManager = (PowerManager)mContext.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];
- mHandler = new MyHandler();
+ mCurrentLinkProperties = new LinkProperties[ConnectivityManager.MAX_NETWORK_TYPE+1];
mNetworkPreference = getPersistedNetworkPreference();
mRadioAttributes = new RadioAttributes[ConnectivityManager.MAX_RADIO_TYPE+1];
- mNetAttributes = new NetworkAttributes[ConnectivityManager.MAX_NETWORK_TYPE+1];
+ mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1];
// Load device network attributes from resources
String[] raStrings = context.getResources().getStringArray(
@@ -291,11 +327,11 @@
for (String raString : raStrings) {
RadioAttributes r = new RadioAttributes(raString);
if (r.mType > ConnectivityManager.MAX_RADIO_TYPE) {
- Slog.e(TAG, "Error in radioAttributes - ignoring attempt to define type " + r.mType);
+ loge("Error in radioAttributes - ignoring attempt to define type " + r.mType);
continue;
}
if (mRadioAttributes[r.mType] != null) {
- Slog.e(TAG, "Error in radioAttributes - ignoring attempt to redefine type " +
+ loge("Error in radioAttributes - ignoring attempt to redefine type " +
r.mType);
continue;
}
@@ -306,29 +342,40 @@
com.android.internal.R.array.networkAttributes);
for (String naString : naStrings) {
try {
- NetworkAttributes n = new NetworkAttributes(naString);
- if (n.mType > ConnectivityManager.MAX_NETWORK_TYPE) {
- Slog.e(TAG, "Error in networkAttributes - ignoring attempt to define type " +
- n.mType);
+ NetworkConfig n = new NetworkConfig(naString);
+ if (n.type > ConnectivityManager.MAX_NETWORK_TYPE) {
+ loge("Error in networkAttributes - ignoring attempt to define type " +
+ n.type);
continue;
}
- if (mNetAttributes[n.mType] != null) {
- Slog.e(TAG, "Error in networkAttributes - ignoring attempt to redefine type " +
- n.mType);
+ if (mNetConfigs[n.type] != null) {
+ loge("Error in networkAttributes - ignoring attempt to redefine type " +
+ n.type);
continue;
}
- if (mRadioAttributes[n.mRadio] == null) {
- Slog.e(TAG, "Error in networkAttributes - ignoring attempt to use undefined " +
- "radio " + n.mRadio + " in network type " + n.mType);
+ if (mRadioAttributes[n.radio] == null) {
+ loge("Error in networkAttributes - ignoring attempt to use undefined " +
+ "radio " + n.radio + " in network type " + n.type);
continue;
}
- mNetAttributes[n.mType] = n;
+ mNetConfigs[n.type] = n;
mNetworksDefined++;
} catch(Exception e) {
// ignore it - leave the entry null
}
}
+ mProtectedNetworks = new ArrayList<Integer>();
+ 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];
{
@@ -336,16 +383,16 @@
int currentLowest = 0;
int nextLowest = 0;
while (insertionPoint > -1) {
- for (NetworkAttributes na : mNetAttributes) {
+ for (NetworkConfig na : mNetConfigs) {
if (na == null) continue;
- if (na.mPriority < currentLowest) continue;
- if (na.mPriority > currentLowest) {
- if (na.mPriority < nextLowest || nextLowest == 0) {
- nextLowest = na.mPriority;
+ if (na.priority < currentLowest) continue;
+ if (na.priority > currentLowest) {
+ if (na.priority < nextLowest || nextLowest == 0) {
+ nextLowest = na.priority;
}
continue;
}
- mPriorityList[insertionPoint--] = na.mType;
+ mPriorityList[insertionPoint--] = na.type;
}
currentLowest = nextLowest;
nextLowest = 0;
@@ -357,7 +404,7 @@
mNetRequestersPids[i] = new ArrayList();
}
- mFeatureUsers = new ArrayList();
+ mFeatureUsers = new ArrayList<FeatureUser>();
mNumDnsEntries = 0;
@@ -370,146 +417,65 @@
* the number of different network types is not going
* to change very often.
*/
- boolean noMobileData = !getMobileDataEnabled();
for (int netType : mPriorityList) {
- switch (mNetAttributes[netType].mRadio) {
+ switch (mNetConfigs[netType].radio) {
case ConnectivityManager.TYPE_WIFI:
- if (DBG) Slog.v(TAG, "Starting Wifi Service.");
- WifiStateTracker wst = new WifiStateTracker(context, mHandler);
- WifiService wifiService = new WifiService(context, wst);
+ if (DBG) log("Starting Wifi Service.");
+ WifiStateTracker wst = new WifiStateTracker();
+ WifiService wifiService = new WifiService(context);
ServiceManager.addService(Context.WIFI_SERVICE, wifiService);
- wifiService.startWifi();
+ wifiService.checkAndStartWifi();
mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst;
- wst.startMonitoring();
+ wst.startMonitoring(context, mHandler);
+
+ //TODO: as part of WWS refactor, create only when needed
+ mWifiWatchdogService = new WifiWatchdogService(context);
break;
case ConnectivityManager.TYPE_MOBILE:
- mNetTrackers[netType] = new MobileDataStateTracker(context, mHandler,
- netType, mNetAttributes[netType].mName);
- mNetTrackers[netType].startMonitoring();
- if (noMobileData) {
- if (DBG) Slog.d(TAG, "tearing down Mobile networks due to setting");
- mNetTrackers[netType].teardown();
- }
+ mNetTrackers[netType] = new MobileDataStateTracker(netType,
+ mNetConfigs[netType].name);
+ mNetTrackers[netType].startMonitoring(context, mHandler);
break;
- case ConnectivityManager.TYPE_WIMAX:
- NetworkStateTracker nst = makeWimaxStateTracker();
- if (nst != null) {
- nst.startMonitoring();
- }
- mNetTrackers[netType] = nst;
- if (noMobileData) {
- if (DBG) Slog.d(TAG, "tearing down WiMAX networks due to setting");
- mNetTrackers[netType].teardown();
- }
+ case ConnectivityManager.TYPE_DUMMY:
+ mNetTrackers[netType] = new DummyDataStateTracker(netType,
+ mNetConfigs[netType].name);
+ mNetTrackers[netType].startMonitoring(context, mHandler);
+ break;
+ case ConnectivityManager.TYPE_BLUETOOTH:
+ mNetTrackers[netType] = BluetoothTetheringDataTracker.getInstance();
+ mNetTrackers[netType].startMonitoring(context, mHandler);
+ break;
+ case ConnectivityManager.TYPE_ETHERNET:
+ mNetTrackers[netType] = EthernetDataTracker.getInstance();
+ mNetTrackers[netType].startMonitoring(context, mHandler);
break;
default:
- Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
- mNetAttributes[netType].mRadio);
+ loge("Trying to create a DataStateTracker for an unknown radio type " +
+ mNetConfigs[netType].radio);
continue;
}
+ mCurrentLinkProperties[netType] = null;
}
mTethering = new Tethering(mContext, mHandler.getLooper());
- mTetheringConfigValid = (((mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] != null) ||
- !mTethering.isDunRequired()) &&
- (mTethering.getTetherableUsbRegexs().length != 0 ||
- mTethering.getTetherableWifiRegexs().length != 0) &&
- mTethering.getUpstreamIfaceRegexs().length != 0);
+ mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
+ mTethering.getTetherableWifiRegexs().length != 0 ||
+ mTethering.getTetherableBluetoothRegexs().length != 0) &&
+ mTethering.getUpstreamIfaceTypes().length != 0);
if (DBG) {
mInetLog = new ArrayList();
}
+
+ mSettingsObserver = new SettingsObserver(mHandler, EVENT_APPLY_GLOBAL_HTTP_PROXY);
+ mSettingsObserver.observe(mContext);
+
+ loadGlobalProxy();
+
+ VpnManager.startVpnService(context);
}
- private NetworkStateTracker makeWimaxStateTracker() {
- //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 = mContext.getResources().getBoolean(
- com.android.internal.R.bool.config_wimaxEnabled);
-
- if (isWimaxEnabled) {
- try {
- wimaxJarLocation = mContext.getResources().getString(
- com.android.internal.R.string.config_wimaxServiceJarLocation);
- wimaxLibLocation = mContext.getResources().getString(
- com.android.internal.R.string.config_wimaxNativeLibLocation);
- wimaxManagerClassName = mContext.getResources().getString(
- com.android.internal.R.string.config_wimaxManagerClassname);
- wimaxServiceClassName = mContext.getResources().getString(
- com.android.internal.R.string.config_wimaxServiceClassname);
- wimaxStateTrackerClassName = mContext.getResources().getString(
- com.android.internal.R.string.config_wimaxStateTrackerClassname);
-
- wimaxClassLoader = new DexClassLoader(wimaxJarLocation,
- new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
- wimaxLibLocation,ClassLoader.getSystemClassLoader());
-
- try {
- wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName);
- wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName);
- wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName);
- } catch (ClassNotFoundException ex) {
- ex.printStackTrace();
- return null;
- }
- } catch(Resources.NotFoundException ex) {
- Slog.e(TAG, "Wimax Resources does not exist!!! ");
- return null;
- }
-
- try {
- Slog.v(TAG, "Starting Wimax Service... ");
-
- Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
- (new Class[] {Context.class,Handler.class});
- wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,mHandler);
-
- Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
- (new Class[] {Context.class,wimaxStateTrackerClass});
- wmxSrvConst.setAccessible(true);
- IBinder svcInvoker = (IBinder) wmxSrvConst.newInstance(mContext,wimaxStateTracker);
- wmxSrvConst.setAccessible(false);
-
- ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
-
- } catch(ClassCastException ex) {
- ex.printStackTrace();
- return null;
- } catch (NoSuchMethodException ex) {
- ex.printStackTrace();
- return null;
- } catch (InstantiationException ex) {
- ex.printStackTrace();
- return null;
- } catch(IllegalAccessException ex) {
- ex.printStackTrace();
- return null;
- } catch(InvocationTargetException ex) {
- ex.printStackTrace();
- return null;
- } catch(Exception ex) {
- ex.printStackTrace();
- return null;
- }
- } else {
- Slog.e(TAG, "Wimax is not enabled or not added to the network attributes!!! ");
- return null;
- }
-
- return wimaxStateTracker;
- }
/**
* Sets the preferred network.
@@ -532,8 +498,8 @@
private void handleSetNetworkPreference(int preference) {
if (ConnectivityManager.isNetworkTypeValid(preference) &&
- mNetAttributes[preference] != null &&
- mNetAttributes[preference].isDefault()) {
+ mNetConfigs[preference] != null &&
+ mNetConfigs[preference].isDefault()) {
if (mNetworkPreference != preference) {
final ContentResolver cr = mContext.getContentResolver();
Settings.Secure.putInt(cr, Settings.Secure.NETWORK_PREFERENCE, preference);
@@ -575,8 +541,7 @@
if (t != mNetworkPreference && mNetTrackers[t] != null &&
mNetTrackers[t].getNetworkInfo().isConnected()) {
if (DBG) {
- Slog.d(TAG, "tearing down " +
- mNetTrackers[t].getNetworkInfo() +
+ log("tearing down " + mNetTrackers[t].getNetworkInfo() +
" in enforcePreference");
}
teardown(mNetTrackers[t]);
@@ -601,11 +566,7 @@
* active
*/
public NetworkInfo getActiveNetworkInfo() {
- enforceAccessPermission();
- if (mActiveDefaultNetwork != -1) {
- return mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
- }
- return null;
+ return getNetworkInfo(mActiveDefaultNetwork);
}
public NetworkInfo getNetworkInfo(int networkType) {
@@ -628,6 +589,27 @@
return result;
}
+ /**
+ * 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
+ */
+ public LinkProperties getActiveLinkProperties() {
+ return getLinkProperties(mActiveDefaultNetwork);
+ }
+
+ public LinkProperties getLinkProperties(int networkType) {
+ enforceAccessPermission();
+ if (ConnectivityManager.isNetworkTypeValid(networkType)) {
+ NetworkStateTracker t = mNetTrackers[networkType];
+ if (t != null) return t.getLinkProperties();
+ }
+ return null;
+ }
+
public boolean setRadios(boolean turnOn) {
boolean result = true;
enforceChangePermission();
@@ -682,19 +664,33 @@
}
public void binderDied() {
- Slog.d(TAG, "ConnectivityService FeatureUser binderDied(" +
+ log("ConnectivityService FeatureUser binderDied(" +
mNetworkType + ", " + mFeature + ", " + mBinder + "), created " +
(System.currentTimeMillis() - mCreateTime) + " mSec ago");
stopUsingNetworkFeature(this, false);
}
public void expire() {
- Slog.d(TAG, "ConnectivityService FeatureUser expire(" +
+ 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";
@@ -705,12 +701,11 @@
public int startUsingNetworkFeature(int networkType, String feature,
IBinder binder) {
if (DBG) {
- Slog.d(TAG, "startUsingNetworkFeature for net " + networkType +
- ": " + feature);
+ log("startUsingNetworkFeature for net " + networkType + ": " + feature);
}
enforceChangePermission();
if (!ConnectivityManager.isNetworkTypeValid(networkType) ||
- mNetAttributes[networkType] == null) {
+ mNetConfigs[networkType] == null) {
return Phone.APN_REQUEST_FAILED;
}
@@ -719,33 +714,81 @@
// TODO - move this into the MobileDataStateTracker
int usedNetworkType = networkType;
if(networkType == ConnectivityManager.TYPE_MOBILE) {
- if (!getMobileDataEnabled()) {
- if (DBG) Slog.d(TAG, "requested special network with data disabled - rejected");
- return Phone.APN_TYPE_NOT_AVAILABLE;
- }
- 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)) {
- usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
- } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
- usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ usedNetworkType = convertFeatureToNetworkType(feature);
+ if (usedNetworkType < 0) {
+ Slog.e(TAG, "Can't match any netTracker!");
+ usedNetworkType = networkType;
}
}
+
+ if (mProtectedNetworks.contains(usedNetworkType)) {
+ enforceConnectivityInternalPermission();
+ }
+
NetworkStateTracker network = mNetTrackers[usedNetworkType];
if (network != null) {
+ Integer currentPid = new Integer(getCallingPid());
if (usedNetworkType != networkType) {
- Integer currentPid = new Integer(getCallingPid());
-
NetworkStateTracker radio = mNetTrackers[networkType];
NetworkInfo ni = network.getNetworkInfo();
if (ni.isAvailable() == false) {
- if (DBG) Slog.d(TAG, "special network not available");
- return Phone.APN_TYPE_NOT_AVAILABLE;
+ if (DBG) log("special network not available");
+ if (!TextUtils.equals(feature,Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
+ return Phone.APN_TYPE_NOT_AVAILABLE;
+ } else {
+ // else make the attempt anyway - probably giving REQUEST_STARTED below
+ }
}
+ 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) {
+ // add the pid-specific dns
+ handleDnsConfigurationChange(networkType);
+ if (DBG) log("special network already active");
+ return Phone.APN_ALREADY_ACTIVE;
+ }
+ if (DBG) log("special network already connecting");
+ return Phone.APN_REQUEST_STARTED;
+ }
+
+ // check if the radio in play can make another contact
+ // assume if cannot for now
+
+ if (DBG) log("reconnecting to special network");
+ network.reconnect();
+ return Phone.APN_REQUEST_STARTED;
+ } else {
+ // need to remember this unsupported request so we respond appropriately on stop
synchronized(this) {
mFeatureUsers.add(f);
if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) {
@@ -753,37 +796,7 @@
mNetRequestersPids[usedNetworkType].add(currentPid);
}
}
- mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK,
- f), getRestoreDefaultNetworkDelay());
-
-
- if ((ni.isConnectedOrConnecting() == true) &&
- !network.isTeardownRequested()) {
- if (ni.isConnected() == true) {
- // add the pid-specific dns
- handleDnsConfigurationChange(networkType);
- if (DBG) Slog.d(TAG, "special network already active");
- return Phone.APN_ALREADY_ACTIVE;
- }
- if (DBG) Slog.d(TAG, "special network already connecting");
- return Phone.APN_REQUEST_STARTED;
- }
-
- // check if the radio in play can make another contact
- // assume if cannot for now
-
- if (DBG) Slog.d(TAG, "reconnecting to special network");
- network.reconnect();
- return Phone.APN_REQUEST_STARTED;
- } else {
- synchronized(this) {
- mFeatureUsers.add(f);
- }
- mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_RESTORE_DEFAULT_NETWORK,
- f), getRestoreDefaultNetworkDelay());
-
- return network.startUsingNetworkFeature(feature,
- getCallingPid(), getCallingUid());
+ return -1;
}
}
return Phone.APN_TYPE_NOT_AVAILABLE;
@@ -800,11 +813,9 @@
boolean found = false;
synchronized(this) {
- for (int i = 0; i < mFeatureUsers.size() ; i++) {
- u = (FeatureUser)mFeatureUsers.get(i);
- if (uid == u.mUid && pid == u.mPid &&
- networkType == u.mNetworkType &&
- TextUtils.equals(feature, u.mFeature)) {
+ for (FeatureUser x : mFeatureUsers) {
+ if (x.isSameUser(pid, uid, networkType, feature)) {
+ u = x;
found = true;
break;
}
@@ -815,7 +826,7 @@
return stopUsingNetworkFeature(u, true);
} else {
// none found!
- if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature - not a live request");
+ if (DBG) log("ignoring stopUsingNetworkFeature - not a live request");
return 1;
}
}
@@ -830,7 +841,7 @@
boolean callTeardown = false; // used to carry our decision outside of sync block
if (DBG) {
- Slog.d(TAG, "stopUsingNetworkFeature for net " + networkType +
+ log("stopUsingNetworkFeature for net " + networkType +
": " + feature);
}
@@ -843,7 +854,7 @@
synchronized(this) {
// check if this process still has an outstanding start request
if (!mFeatureUsers.contains(u)) {
- if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests");
+ if (DBG) log("ignoring - this process has no outstanding requests");
return 1;
}
u.unlinkDeathRecipient();
@@ -856,12 +867,9 @@
// 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 (int i = 0; i < mFeatureUsers.size() ; i++) {
- FeatureUser x = (FeatureUser)mFeatureUsers.get(i);
- if (x.mUid == u.mUid && x.mPid == u.mPid &&
- x.mNetworkType == u.mNetworkType &&
- TextUtils.equals(x.mFeature, u.mFeature)) {
- if (DBG) Slog.d(TAG, "ignoring stopUsingNetworkFeature as dup is found");
+ for (FeatureUser x : mFeatureUsers) {
+ if (x.isSameUser(u)) {
+ if (DBG) log("ignoring stopUsingNetworkFeature as dup is found");
return 1;
}
}
@@ -870,19 +878,14 @@
// TODO - move to MobileDataStateTracker
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)) {
- usedNetworkType = ConnectivityManager.TYPE_MOBILE_DUN;
- } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
- usedNetworkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ usedNetworkType = convertFeatureToNetworkType(feature);
+ if (usedNetworkType < 0) {
+ usedNetworkType = networkType;
}
}
tracker = mNetTrackers[usedNetworkType];
if (tracker == null) {
- if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType);
+ if (DBG) log("ignoring - no known tracker for net type " + usedNetworkType);
return -1;
}
if (usedNetworkType != networkType) {
@@ -890,20 +893,21 @@
mNetRequestersPids[usedNetworkType].remove(currentPid);
reassessPidDns(pid, true);
if (mNetRequestersPids[usedNetworkType].size() != 0) {
- if (DBG) Slog.d(TAG, "not tearing down special network - " +
+ if (DBG) log("not tearing down special network - " +
"others still using it");
return 1;
}
callTeardown = true;
+ } else {
+ if (DBG) log("not a known feature - dropping");
}
}
- if (DBG) Slog.d(TAG, "Doing network teardown");
+ if (DBG) log("Doing network teardown");
if (callTeardown) {
tracker.teardown();
return 1;
} else {
- // do it the old fashioned way
- return tracker.stopUsingNetworkFeature(feature, pid, uid);
+ return -1;
}
}
@@ -939,6 +943,10 @@
*/
public boolean requestRouteToHostAddress(int networkType, byte[] hostAddress) {
enforceChangePermission();
+ if (mProtectedNetworks.contains(networkType)) {
+ enforceConnectivityInternalPermission();
+ }
+
if (!ConnectivityManager.isNetworkTypeValid(networkType)) {
return false;
}
@@ -947,26 +955,110 @@
if (tracker == null || !tracker.getNetworkInfo().isConnected() ||
tracker.isTeardownRequested()) {
if (DBG) {
- Slog.d(TAG, "requestRouteToHostAddress on down network " +
+ log("requestRouteToHostAddress on down network " +
"(" + networkType + ") - dropped");
}
return false;
}
-
try {
- InetAddress inetAddress = InetAddress.getByAddress(hostAddress);
- return tracker.requestRouteToHost(inetAddress);
- } catch (UnknownHostException e) {
+ InetAddress addr = InetAddress.getByAddress(hostAddress);
+ LinkProperties lp = tracker.getLinkProperties();
+ return addRouteToAddress(lp, addr);
+ } catch (UnknownHostException e) {}
+ return false;
+ }
+
+ private boolean addRoute(LinkProperties p, RouteInfo r) {
+ return modifyRoute(p.getInterfaceName(), p, r, 0, true);
+ }
+
+ private boolean removeRoute(LinkProperties p, RouteInfo r) {
+ return modifyRoute(p.getInterfaceName(), p, r, 0, false);
+ }
+
+ private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
+ return modifyRouteToAddress(lp, addr, true);
+ }
+
+ private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
+ return modifyRouteToAddress(lp, addr, false);
+ }
+
+ private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd) {
+ RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr);
+ if (bestRoute == null) {
+ bestRoute = RouteInfo.makeHostRoute(addr);
+ } else {
+ if (bestRoute.getGateway().equals(addr)) {
+ // if there is no better route, add the implied hostroute for our gateway
+ bestRoute = RouteInfo.makeHostRoute(addr);
+ } else {
+ // if we will connect to this through another route, add a direct route
+ // to it's gateway
+ bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway());
+ }
+ }
+ return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd);
+ }
+
+ private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
+ boolean doAdd) {
+ if ((ifaceName == null) || (lp == null) || (r == null)) return false;
+
+ if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
+ loge("Error adding route - too much recursion");
return false;
}
+
+ if (r.isHostRoute() == false) {
+ RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), 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());
+ } 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());
+ }
+ modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd);
+ }
+ }
+ if (doAdd) {
+ if (DBG) log("Adding " + r + " for interface " + ifaceName);
+ mAddedRoutes.add(r);
+ try {
+ mNetd.addRoute(ifaceName, r);
+ } catch (Exception e) {
+ // never crash - catch them all
+ 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
+ mAddedRoutes.remove(r);
+ if (mAddedRoutes.contains(r) == false) {
+ if (DBG) log("Removing " + r + " for interface " + ifaceName);
+ try {
+ mNetd.removeRoute(ifaceName, r);
+ } catch (Exception e) {
+ // never crash - catch them all
+ loge("Exception trying to remove a route: " + e);
+ return false;
+ }
+ } else {
+ if (DBG) log("not removing " + r + " as it's still in use");
+ }
+ }
+ return true;
}
/**
* @see ConnectivityManager#getBackgroundDataSetting()
*/
public boolean getBackgroundDataSetting() {
- return Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.BACKGROUND_DATA, 1) == 1;
+ return mBackgroundDataEnabled.get();
}
/**
@@ -977,88 +1069,70 @@
android.Manifest.permission.CHANGE_BACKGROUND_DATA_SETTING,
"ConnectivityService");
+ mBackgroundDataEnabled.set(allowBackgroundDataUsage);
+
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_BACKGROUND_DATA,
(allowBackgroundDataUsage ? ENABLED : DISABLED), 0));
}
private void handleSetBackgroundData(boolean enabled) {
- if (enabled != getBackgroundDataSetting()) {
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0);
- Intent broadcast = new Intent(
- ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
- mContext.sendBroadcast(broadcast);
- }
+ Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.BACKGROUND_DATA, enabled ? 1 : 0);
+ Intent broadcast = new Intent(
+ ConnectivityManager.ACTION_BACKGROUND_DATA_SETTING_CHANGED);
+ mContext.sendBroadcast(broadcast);
}
/**
* @see ConnectivityManager#getMobileDataEnabled()
*/
public boolean getMobileDataEnabled() {
+ // TODO: This detail should probably be in DataConnectionTracker's
+ // which is where we store the value and maybe make this
+ // asynchronous.
enforceAccessPermission();
boolean retVal = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.MOBILE_DATA, 1) == 1;
- if (DBG) Slog.d(TAG, "getMobileDataEnabled returning " + retVal);
+ if (DBG) log("getMobileDataEnabled returning " + retVal);
return retVal;
}
+ 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);
+ }
+ }
+
/**
* @see ConnectivityManager#setMobileDataEnabled(boolean)
*/
public void setMobileDataEnabled(boolean enabled) {
enforceChangePermission();
- if (DBG) Slog.d(TAG, "setMobileDataEnabled(" + enabled + ")");
+ if (DBG) log("setMobileDataEnabled(" + enabled + ")");
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_MOBILE_DATA,
- (enabled ? ENABLED : DISABLED), 0));
+ (enabled ? ENABLED : DISABLED), 0));
}
private void handleSetMobileData(boolean enabled) {
- if (getMobileDataEnabled() == enabled) return;
-
- Settings.Secure.putInt(mContext.getContentResolver(),
- Settings.Secure.MOBILE_DATA, enabled ? 1 : 0);
-
- if (enabled) {
- if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
- if (DBG) {
- Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_MOBILE]);
- }
- mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
+ if (mNetTrackers[ConnectivityManager.TYPE_MOBILE] != null) {
+ if (DBG) {
+ Slog.d(TAG, mNetTrackers[ConnectivityManager.TYPE_MOBILE].toString() + enabled);
}
- if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
- if (DBG) {
- Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_WIMAX]);
- }
- mNetTrackers[ConnectivityManager.TYPE_WIMAX].reconnect();
- }
- } else {
- for (NetworkStateTracker nt : mNetTrackers) {
- if (nt == null) continue;
- int netType = nt.getNetworkInfo().getType();
- if (mNetAttributes[netType].mRadio == ConnectivityManager.TYPE_MOBILE) {
- if (DBG) Slog.d(TAG, "tearing down " + nt);
- nt.teardown();
- }
- }
- if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
- mNetTrackers[ConnectivityManager.TYPE_WIMAX].teardown();
- }
+ mNetTrackers[ConnectivityManager.TYPE_MOBILE].setDataEnable(enabled);
}
}
- private int getNumConnectedNetworks() {
- int numConnectedNets = 0;
-
- for (NetworkStateTracker nt : mNetTrackers) {
- if (nt != null && nt.getNetworkInfo().isConnected() &&
- !nt.isTeardownRequested()) {
- ++numConnectedNets;
- }
- }
- return numConnectedNets;
- }
-
private void enforceAccessPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.ACCESS_NETWORK_STATE,
@@ -1084,6 +1158,12 @@
"ConnectivityService");
}
+ private void enforceConnectivityInternalPermission() {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ "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
@@ -1102,7 +1182,7 @@
* getting the disconnect for a network that we explicitly disabled
* in accordance with network preference policies.
*/
- if (!mNetAttributes[prevNetType].isDefault()) {
+ if (!mNetConfigs[prevNetType].isDefault()) {
List pids = mNetRequestersPids[prevNetType];
for (int i = 0; i<pids.size(); i++) {
Integer pid = (Integer)pids.get(i);
@@ -1127,7 +1207,7 @@
info.getExtraInfo());
}
- if (mNetAttributes[prevNetType].isDefault()) {
+ if (mNetConfigs[prevNetType].isDefault()) {
tryFailover(prevNetType);
if (mActiveDefaultNetwork != -1) {
NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
@@ -1138,8 +1218,30 @@
}
}
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
- handleConnectivityChange(prevNetType);
+ handleConnectivityChange(prevNetType, doReset);
sendStickyBroadcast(intent);
/*
@@ -1153,38 +1255,46 @@
private void tryFailover(int prevNetType) {
/*
- * If this is a default network, check if other defaults are available
- * or active
+ * 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 (mNetAttributes[prevNetType].isDefault()) {
+ if (mNetConfigs[prevNetType].isDefault()) {
if (mActiveDefaultNetwork == prevNetType) {
mActiveDefaultNetwork = -1;
}
- boolean noMobileData = !getMobileDataEnabled();
+ // 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 (mNetAttributes[checkType] == null) continue;
- if (mNetAttributes[checkType].isDefault() == false) continue;
- if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
- noMobileData) {
- Slog.e(TAG, "not failing over to mobile type " + checkType +
- " because Mobile Data Disabled");
- continue;
- }
- if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_WIMAX &&
- noMobileData) {
- Slog.e(TAG, "not failing over to mobile type " + checkType +
- " because Mobile Data Disabled");
- continue;
- }
+ if (mNetConfigs[checkType] == null) continue;
+ if (!mNetConfigs[checkType].isDefault()) 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) Slog.d(TAG, "Attempting to switch to " + checkInfo.getTypeName());
+ if (DBG) log("Attempting to switch to " + checkInfo.getTypeName());
}
}
}
@@ -1231,7 +1341,7 @@
} else {
reasonText = " (" + reason + ").";
}
- Slog.e(TAG, "Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
+ loge("Attempt to connect to " + info.getTypeName() + " failed" + reasonText);
Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION);
intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info);
@@ -1249,7 +1359,7 @@
info.setFailover(false);
}
- if (mNetAttributes[info.getType()].isDefault()) {
+ if (mNetConfigs[info.getType()].isDefault()) {
tryFailover(info.getType());
if (mActiveDefaultNetwork != -1) {
NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
@@ -1292,6 +1402,8 @@
mInitialBroadcast = null;
}
}
+ // load the global proxy at startup
+ mHandler.sendMessage(mHandler.obtainMessage(EVENT_APPLY_GLOBAL_HTTP_PROXY));
}
private void handleConnect(NetworkInfo info) {
@@ -1303,32 +1415,43 @@
// if this is a default net and other default is running
// kill the one not preferred
- if (mNetAttributes[type].isDefault()) {
+ if (mNetConfigs[type].isDefault()) {
if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) {
if ((type != mNetworkPreference &&
- mNetAttributes[mActiveDefaultNetwork].mPriority >
- mNetAttributes[type].mPriority) ||
+ mNetConfigs[mActiveDefaultNetwork].priority >
+ mNetConfigs[type].priority) ||
mNetworkPreference == mActiveDefaultNetwork) {
// don't accept this one
- if (DBG) Slog.v(TAG, "Not broadcasting CONNECT_ACTION " +
+ if (DBG) {
+ log("Not broadcasting CONNECT_ACTION " +
"to torn down network " + info.getTypeName());
+ }
teardown(thisNet);
return;
} else {
// tear down the other
NetworkStateTracker otherNet =
mNetTrackers[mActiveDefaultNetwork];
- if (DBG) Slog.v(TAG, "Policy requires " +
- otherNet.getNetworkInfo().getTypeName() +
+ if (DBG) {
+ log("Policy requires " + otherNet.getNetworkInfo().getTypeName() +
" teardown");
+ }
if (!teardown(otherNet)) {
- Slog.e(TAG, "Network declined teardown request");
+ loge("Network declined teardown request");
teardown(thisNet);
return;
}
- if (isFailover) {
- otherNet.releaseWakeLock();
- }
+ }
+ }
+ 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 = type;
@@ -1342,91 +1465,258 @@
//reportNetworkCondition(mActiveDefaultNetwork, 100);
}
thisNet.setTeardownRequested(false);
- thisNet.updateNetworkSettings();
- handleConnectivityChange(type);
+ updateNetworkSettings(thisNet);
+ handleConnectivityChange(type, false);
sendConnectedBroadcast(info);
}
- private void handleScanResultsAvailable(NetworkInfo info) {
- int networkType = info.getType();
- if (networkType != ConnectivityManager.TYPE_WIFI) {
- if (DBG) Slog.v(TAG, "Got ScanResultsAvailable for " +
- info.getTypeName() + " network. Don't know how to handle.");
- }
-
- mNetTrackers[networkType].interpretScanResultsAvailable();
- }
-
- private void handleNotificationChange(boolean visible, int id,
- Notification notification) {
- NotificationManager notificationManager = (NotificationManager) mContext
- .getSystemService(Context.NOTIFICATION_SERVICE);
-
- if (visible) {
- notificationManager.notify(id, notification);
- } else {
- notificationManager.cancel(id);
- }
- }
-
/**
- * After a change in the connectivity state of any network, We're mainly
- * concerned with making sure that the list of DNS servers is setupup
+ * 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.
*/
- private void handleConnectivityChange(int netType) {
+ private void handleConnectivityChange(int netType, boolean doReset) {
+ int resetMask = doReset ? NetworkUtils.RESET_ALL_ADDRESSES : 0;
+
/*
* If a non-default network is enabled, add the host routes that
* will allow it's DNS servers to be accessed.
*/
handleDnsConfigurationChange(netType);
+ LinkProperties curLp = mCurrentLinkProperties[netType];
+ LinkProperties newLp = null;
+
if (mNetTrackers[netType].getNetworkInfo().isConnected()) {
- if (mNetAttributes[netType].isDefault()) {
- mNetTrackers[netType].addDefaultRoute();
- } else {
- // many radios add a default route even when we don't want one.
- // remove the default interface unless we need it for our active network
- if (mActiveDefaultNetwork != -1) {
- String defaultIface = mNetTrackers[mActiveDefaultNetwork].getInterfaceName();
- if (defaultIface != null &&
- !defaultIface.equals(mNetTrackers[netType].getInterfaceName())) {
- mNetTrackers[netType].removeDefaultRoute();
+ 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<LinkAddress> 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 (DBG) {
+ log("handleConnectivityChange: address are the same reset per doReset" +
+ " linkProperty[" + netType + "]:" +
+ " resetMask=" + resetMask);
+ }
}
+ } else {
+ resetMask = NetworkUtils.RESET_ALL_ADDRESSES;
+ log("handleConnectivityChange: interface not not equivalent reset both" +
+ " linkProperty[" + netType + "]:" +
+ " resetMask=" + resetMask);
}
- mNetTrackers[netType].addPrivateDnsRoutes();
+ }
+ if (mNetConfigs[netType].isDefault()) {
+ handleApplyDefaultProxy(netType);
}
} else {
- if (mNetAttributes[netType].isDefault()) {
- mNetTrackers[netType].removeDefaultRoute();
- } else {
- mNetTrackers[netType].removePrivateDnsRoutes();
+ if (VDBG) {
+ log("handleConnectivityChange: changed linkProperty[" + netType + "]:" +
+ " doReset=" + doReset + " resetMask=" + resetMask +
+ "\n curLp=" + curLp +
+ "\n newLp= null");
+ }
+ }
+ mCurrentLinkProperties[netType] = newLp;
+ updateRoutes(newLp, curLp, mNetConfigs[netType].isDefault());
+
+ if (doReset || resetMask != 0) {
+ LinkProperties linkProperties = mNetTrackers[netType].getLinkProperties();
+ if (linkProperties != null) {
+ String iface = linkProperties.getInterfaceName();
+ if (TextUtils.isEmpty(iface) == false) {
+ if (DBG) log("resetConnections(" + iface + ", " + resetMask + ")");
+ NetworkUtils.resetConnections(iface, resetMask);
+ }
+ }
+ }
+
+ // 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(),
+ Phone.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
+ */
+ private void updateRoutes(LinkProperties newLp, LinkProperties curLp, boolean isLinkDefault) {
+ Collection<RouteInfo> routesToAdd = null;
+ CompareResult<InetAddress> dnsDiff = new CompareResult<InetAddress>();
+ CompareResult<RouteInfo> routeDiff = new CompareResult<RouteInfo>();
+ if (curLp != null) {
+ // check for the delta between the current set and the new
+ routeDiff = curLp.compareRoutes(newLp);
+ dnsDiff = curLp.compareDnses(newLp);
+ } else if (newLp != null) {
+ routeDiff.added = newLp.getRoutes();
+ dnsDiff.added = newLp.getDnses();
+ }
+
+ for (RouteInfo r : routeDiff.removed) {
+ if (isLinkDefault || ! r.isDefaultRoute()) {
+ removeRoute(curLp, r);
+ }
+ }
+
+ for (RouteInfo r : routeDiff.added) {
+ if (isLinkDefault || ! r.isDefaultRoute()) {
+ addRoute(newLp, r);
+ }
+ }
+
+ if (!isLinkDefault) {
+ // handle DNS routes
+ if (routeDiff.removed.size() == 0 && routeDiff.added.size() == 0) {
+ // no change in routes, check for change in dns themselves
+ for (InetAddress oldDns : dnsDiff.removed) {
+ removeRouteToAddress(curLp, oldDns);
+ }
+ for (InetAddress newDns : dnsDiff.added) {
+ addRouteToAddress(newLp, newDns);
+ }
+ } else {
+ // routes changed - remove all old dns entries and add new
+ if (curLp != null) {
+ for (InetAddress oldDns : curLp.getDnses()) {
+ removeRouteToAddress(curLp, oldDns);
+ }
+ }
+ if (newLp != null) {
+ for (InetAddress newDns : newLp.getDnses()) {
+ addRouteToAddress(newLp, newDns);
+ }
+ }
+ }
+ }
+ }
+
+
+ /**
+ * Reads the network specific TCP buffer sizes from SystemProperties
+ * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system
+ * wide use
+ */
+ public void updateNetworkSettings(NetworkStateTracker nt) {
+ String key = nt.getTcpBufferSizesPropName();
+ String bufferSizes = SystemProperties.get(key);
+
+ if (bufferSizes.length() == 0) {
+ loge(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 (DBG) {
+ log("Setting TCP values: [" + bufferSizes
+ + "] which comes from [" + key + "]");
+ }
+ setBufferSize(bufferSizes);
+ }
+ }
+
+ /**
+ * 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_";
+ stringToFile(prefix + "rmem_min", values[0]);
+ stringToFile(prefix + "rmem_def", values[1]);
+ stringToFile(prefix + "rmem_max", values[2]);
+ stringToFile(prefix + "wmem_min", values[3]);
+ stringToFile(prefix + "wmem_def", values[4]);
+ stringToFile(prefix + "wmem_max", values[5]);
+ } else {
+ loge("Invalid buffersize string: " + bufferSizes);
+ }
+ } catch (IOException e) {
+ loge("Can't set tcp buffer sizes:" + e);
+ }
+ }
+
+ /**
+ * Writes string to file. Basically same as "echo -n $string > $filename"
+ *
+ * @param filename
+ * @param string
+ * @throws IOException
+ */
+ private void stringToFile(String filename, String string) throws IOException {
+ FileWriter out = new FileWriter(filename);
+ try {
+ out.write(string);
+ } finally {
+ out.close();
+ }
+ }
+
+
+ /**
* Adjust the per-process dns entries (net.dns<x>.<pid>) based
* on the highest priority active net which this process requested.
* If there aren't any, clear it out
*/
private void reassessPidDns(int myPid, boolean doBump)
{
- if (DBG) Slog.d(TAG, "reassessPidDns for pid " + myPid);
+ if (DBG) log("reassessPidDns for pid " + myPid);
for(int i : mPriorityList) {
- if (mNetAttributes[i].isDefault()) {
+ if (mNetConfigs[i].isDefault()) {
continue;
}
NetworkStateTracker nt = mNetTrackers[i];
if (nt.getNetworkInfo().isConnected() &&
!nt.isTeardownRequested()) {
+ LinkProperties p = nt.getLinkProperties();
+ if (p == null) continue;
List pids = mNetRequestersPids[i];
for (int j=0; j<pids.size(); j++) {
Integer pid = (Integer)pids.get(j);
if (pid.intValue() == myPid) {
- String[] dnsList = nt.getNameServers();
- writePidDns(dnsList, myPid);
+ Collection<InetAddress> dnses = p.getDnses();
+ writePidDns(dnses, myPid);
if (doBump) {
bumpDns();
}
@@ -1448,13 +1738,18 @@
}
}
- private void writePidDns(String[] dnsList, int pid) {
+ // return true if results in a change
+ private boolean writePidDns(Collection <InetAddress> dnses, int pid) {
int j = 1;
- for (String dns : dnsList) {
- if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
- SystemProperties.set("net.dns" + j++ + "." + pid, dns);
+ boolean changed = false;
+ for (InetAddress dns : dnses) {
+ String dnsString = dns.getHostAddress();
+ if (changed || !dnsString.equals(SystemProperties.get("net.dns" + j + "." + pid))) {
+ changed = true;
+ SystemProperties.set("net.dns" + j++ + "." + pid, dns.getHostAddress());
}
}
+ return changed;
}
private void bumpDns() {
@@ -1470,27 +1765,57 @@
} catch (NumberFormatException e) {}
}
SystemProperties.set("net.dnschange", "" + (n+1));
+ /*
+ * 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);
+ mContext.sendBroadcast(intent);
}
private void handleDnsConfigurationChange(int netType) {
// add default net's dns entries
NetworkStateTracker nt = mNetTrackers[netType];
if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) {
- String[] dnsList = nt.getNameServers();
+ LinkProperties p = nt.getLinkProperties();
+ if (p == null) return;
+ Collection<InetAddress> dnses = p.getDnses();
try {
- mNetd.setDnsServersForInterface(Integer.toString(netType), dnsList);
+ mNetd.setDnsServersForInterface(Integer.toString(netType),
+ NetworkUtils.makeStrings(dnses));
} catch (Exception e) {
Slog.e(TAG, "exception setting dns servers: " + e);
}
- if (mNetAttributes[netType].isDefault()) {
+ boolean changed = false;
+ if (mNetConfigs[netType].isDefault()) {
int j = 1;
- for (String dns : dnsList) {
- if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) {
+ if (dnses.size() == 0 && mDefaultDns != null) {
+ String dnsString = mDefaultDns.getHostAddress();
+ if (!dnsString.equals(SystemProperties.get("net.dns1"))) {
if (DBG) {
- Slog.d(TAG, "adding dns " + dns + " for " +
+ log("no dns provided - using " + dnsString);
+ }
+ changed = true;
+ SystemProperties.set("net.dns1", dnsString);
+ }
+ j++;
+ } else {
+ for (InetAddress dns : dnses) {
+ String dnsString = dns.getHostAddress();
+ if (!changed && dnsString.equals(SystemProperties.get("net.dns" + j))) {
+ j++;
+ continue;
+ }
+ if (DBG) {
+ log("adding dns " + dns + " for " +
nt.getNetworkInfo().getTypeName());
}
- SystemProperties.set("net.dns" + j++, dns);
+ changed = true;
+ SystemProperties.set("net.dns" + j++, dnsString);
}
}
try {
@@ -1498,8 +1823,11 @@
} catch (Exception e) {
Slog.e(TAG, "exception setting default dns interface: " + e);}
for (int k=j ; k<mNumDnsEntries; k++) {
- if (DBG) Slog.d(TAG, "erasing net.dns" + k);
- SystemProperties.set("net.dns" + k, "");
+ if (changed || !TextUtils.isEmpty(SystemProperties.get("net.dns" + k))) {
+ if (DBG) log("erasing net.dns" + k);
+ changed = true;
+ SystemProperties.set("net.dns" + k, "");
+ }
}
mNumDnsEntries = j;
} else {
@@ -1507,14 +1835,14 @@
List pids = mNetRequestersPids[netType];
for (int y=0; y< pids.size(); y++) {
Integer pid = (Integer)pids.get(y);
- writePidDns(dnsList, pid.intValue());
+ changed = writePidDns(dnses, pid.intValue());
}
}
+ if (changed) bumpDns();
}
- bumpDns();
}
- private int getRestoreDefaultNetworkDelay() {
+ private int getRestoreDefaultNetworkDelay(int networkType) {
String restoreDefaultNetworkDelayStr = SystemProperties.get(
NETWORK_RESTORE_DELAY_PROP_NAME);
if(restoreDefaultNetworkDelayStr != null &&
@@ -1524,7 +1852,14 @@
} catch (NumberFormatException e) {
}
}
- return RESTORE_DEFAULT_NETWORK_DELAY;
+ // 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
@@ -1566,6 +1901,13 @@
}
pw.println();
+ 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) {
@@ -1579,6 +1921,10 @@
// must be stateless - things change under us.
private class MyHandler extends Handler {
+ public MyHandler(Looper looper) {
+ super(looper);
+ }
+
@Override
public void handleMessage(Message msg) {
NetworkInfo info;
@@ -1587,25 +1933,8 @@
info = (NetworkInfo) msg.obj;
int type = info.getType();
NetworkInfo.State state = info.getState();
- // only do this optimization for wifi. It going into scan mode for location
- // services generates alot of noise. Meanwhile the mms apn won't send out
- // subsequent notifications when on default cellular because it never
- // disconnects.. so only do this to wifi notifications. Fixed better when the
- // APN notifications are standardized.
- if (mNetAttributes[type].mLastState == state &&
- mNetAttributes[type].mRadio == ConnectivityManager.TYPE_WIFI) {
- if (DBG) {
- // TODO - remove this after we validate the dropping doesn't break
- // anything
- Slog.d(TAG, "Dropping ConnectivityChange for " +
- info.getTypeName() + ": " +
- state + "/" + info.getDetailedState());
- }
- return;
- }
- mNetAttributes[type].mLastState = state;
- if (DBG) Slog.d(TAG, "ConnectivityChange for " +
+ if (DBG) log("ConnectivityChange for " +
info.getTypeName() + ": " +
state + "/" + info.getDetailedState());
@@ -1640,29 +1969,25 @@
handleConnect(info);
}
break;
-
- case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE:
- info = (NetworkInfo) msg.obj;
- handleScanResultsAvailable(info);
- break;
-
- case NetworkStateTracker.EVENT_NOTIFICATION_CHANGED:
- handleNotificationChange(msg.arg1 == 1, msg.arg2,
- (Notification) msg.obj);
- break;
-
case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED:
info = (NetworkInfo) msg.obj;
- type = info.getType();
- handleDnsConfigurationChange(type);
+ // TODO: Temporary allowing network configuration
+ // change not resetting sockets.
+ // @see bug/4455071
+ handleConnectivityChange(info.getType(), false);
break;
-
- case NetworkStateTracker.EVENT_ROAMING_CHANGED:
- // fill me in
- break;
-
- case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED:
- // fill me in
+ 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;
@@ -1700,6 +2025,17 @@
handleSetMobileData(enabled);
break;
}
+ case EVENT_APPLY_GLOBAL_HTTP_PROXY:
+ {
+ handleDeprecatedGlobalHttpProxy();
+ break;
+ }
+ case EVENT_SET_DEPENDENCY_MET:
+ {
+ boolean met = (msg.arg1 == ENABLED);
+ handleSetDependencyMet(msg.arg2, met);
+ break;
+ }
}
}
}
@@ -1756,6 +2092,15 @@
}
}
+ public String[] getTetherableBluetoothRegexs() {
+ enforceTetherAccessPermission();
+ if (isTetheringSupported()) {
+ return mTethering.getTetherableBluetoothRegexs();
+ } else {
+ return new String[0];
+ }
+ }
+
// TODO - move iface listing, queries, etc to new module
// javadoc from interface
public String[] getTetherableIfaces() {
@@ -1784,9 +2129,28 @@
return tetherEnabledInSettings && mTetheringConfigValid;
}
+ // 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 (DBG) Slog.d(TAG, "reportNetworkCondition(" + networkType + ", " + percentage + ")");
+ if (DBG) log("reportNetworkCondition(" + networkType + ", " + percentage + ")");
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.STATUS_BAR,
"ConnectivityService");
@@ -1808,22 +2172,22 @@
private void handleInetConditionChange(int netType, int condition) {
if (DBG) {
- Slog.d(TAG, "Inet connectivity change, net=" +
+ log("Inet connectivity change, net=" +
netType + ", condition=" + condition +
",mActiveDefaultNetwork=" + mActiveDefaultNetwork);
}
if (mActiveDefaultNetwork == -1) {
- if (DBG) Slog.d(TAG, "no active default network - aborting");
+ if (DBG) log("no active default network - aborting");
return;
}
if (mActiveDefaultNetwork != netType) {
- if (DBG) Slog.d(TAG, "given net not default - aborting");
+ if (DBG) log("given net not default - aborting");
return;
}
mDefaultInetCondition = condition;
int delay;
if (mInetConditionChangeInFlight == false) {
- if (DBG) Slog.d(TAG, "starting a change hold");
+ if (DBG) log("starting a change hold");
// setup a new hold to debounce this
if (mDefaultInetCondition > 50) {
delay = Settings.Secure.getInt(mContext.getContentResolver(),
@@ -1838,37 +2202,190 @@
} else {
// we've set the new condition, when this hold ends that will get
// picked up
- if (DBG) Slog.d(TAG, "currently in hold - not setting new end evt");
+ if (DBG) log("currently in hold - not setting new end evt");
}
}
private void handleInetConditionHoldEnd(int netType, int sequence) {
if (DBG) {
- Slog.d(TAG, "Inet hold end, net=" + netType +
+ log("Inet hold end, net=" + netType +
", condition =" + mDefaultInetCondition +
", published condition =" + mDefaultInetConditionPublished);
}
mInetConditionChangeInFlight = false;
if (mActiveDefaultNetwork == -1) {
- if (DBG) Slog.d(TAG, "no active default network - aborting");
+ if (DBG) log("no active default network - aborting");
return;
}
if (mDefaultConnectionSequence != sequence) {
- if (DBG) Slog.d(TAG, "event hold for obsolete network - aborting");
+ if (DBG) log("event hold for obsolete network - aborting");
return;
}
if (mDefaultInetConditionPublished == mDefaultInetCondition) {
- if (DBG) Slog.d(TAG, "no change in condition - aborting");
+ if (DBG) log("no change in condition - aborting");
return;
}
NetworkInfo networkInfo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
if (networkInfo.isConnected() == false) {
- if (DBG) Slog.d(TAG, "default network not connected - aborting");
+ if (DBG) log("default network not connected - aborting");
return;
}
mDefaultInetConditionPublished = mDefaultInetCondition;
sendInetConditionBroadcast(networkInfo);
return;
}
+
+ public synchronized ProxyProperties getProxy() {
+ if (mGlobalProxy != null) return mGlobalProxy;
+ if (mDefaultProxy != null) return mDefaultProxy;
+ return null;
+ }
+
+ public void setGlobalProxy(ProxyProperties proxyProperties) {
+ enforceChangePermission();
+ synchronized (mGlobalProxyLock) {
+ 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 = "";
+ if (proxyProperties != null && !TextUtils.isEmpty(proxyProperties.getHost())) {
+ mGlobalProxy = new ProxyProperties(proxyProperties);
+ host = mGlobalProxy.getHost();
+ port = mGlobalProxy.getPort();
+ exclList = mGlobalProxy.getExclusionList();
+ } else {
+ mGlobalProxy = null;
+ }
+ ContentResolver res = mContext.getContentResolver();
+ Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST, host);
+ Settings.Secure.putInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, port);
+ Settings.Secure.putString(res, Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST,
+ exclList);
+ }
+
+ if (mGlobalProxy == null) {
+ proxyProperties = mDefaultProxy;
+ }
+ sendProxyBroadcast(proxyProperties);
+ }
+
+ private void loadGlobalProxy() {
+ ContentResolver res = mContext.getContentResolver();
+ String host = Settings.Secure.getString(res, Settings.Secure.GLOBAL_HTTP_PROXY_HOST);
+ int port = Settings.Secure.getInt(res, Settings.Secure.GLOBAL_HTTP_PROXY_PORT, 0);
+ String exclList = Settings.Secure.getString(res,
+ Settings.Secure.GLOBAL_HTTP_PROXY_EXCLUSION_LIST);
+ if (!TextUtils.isEmpty(host)) {
+ ProxyProperties proxyProperties = new ProxyProperties(host, port, exclList);
+ synchronized (mGlobalProxyLock) {
+ mGlobalProxy = proxyProperties;
+ }
+ }
+ }
+
+ public ProxyProperties getGlobalProxy() {
+ synchronized (mGlobalProxyLock) {
+ return mGlobalProxy;
+ }
+ }
+
+ private void handleApplyDefaultProxy(int type) {
+ // check if new default - push it out to all VM if so
+ ProxyProperties proxy = mNetTrackers[type].getLinkProperties().getHttpProxy();
+ synchronized (this) {
+ if (mDefaultProxy != null && mDefaultProxy.equals(proxy)) return;
+ if (mDefaultProxy == proxy) return;
+ if (!TextUtils.isEmpty(proxy.getHost())) {
+ mDefaultProxy = proxy;
+ } else {
+ mDefaultProxy = null;
+ }
+ }
+ if (DBG) log("changing default proxy to " + proxy);
+ if ((proxy == null && mGlobalProxy == null) || proxy.equals(mGlobalProxy)) return;
+ if (mGlobalProxy != null) return;
+ sendProxyBroadcast(proxy);
+ }
+
+ private void handleDeprecatedGlobalHttpProxy() {
+ String proxy = Settings.Secure.getString(mContext.getContentResolver(),
+ Settings.Secure.HTTP_PROXY);
+ if (!TextUtils.isEmpty(proxy)) {
+ String data[] = proxy.split(":");
+ String proxyHost = data[0];
+ int proxyPort = 8080;
+ if (data.length > 1) {
+ try {
+ proxyPort = Integer.parseInt(data[1]);
+ } catch (NumberFormatException e) {
+ return;
+ }
+ }
+ ProxyProperties p = new ProxyProperties(data[0], proxyPort, "");
+ setGlobalProxy(p);
+ }
+ }
+
+ private void sendProxyBroadcast(ProxyProperties proxy) {
+ if (proxy == null) proxy = new ProxyProperties("", 0, "");
+ 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);
+ mContext.sendStickyBroadcast(intent);
+ }
+
+ 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.Secure.getUriFor(
+ Settings.Secure.HTTP_PROXY), false, this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ mHandler.obtainMessage(mWhat).sendToTarget();
+ }
+ }
+
+ private void log(String s) {
+ Slog.d(TAG, s);
+ }
+
+ private void loge(String s) {
+ Slog.e(TAG, s);
+ }
+ int convertFeatureToNetworkType(String feature){
+ int networkType = -1;
+ if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) {
+ networkType = ConnectivityManager.TYPE_MOBILE_MMS;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) {
+ networkType = ConnectivityManager.TYPE_MOBILE_SUPL;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN) ||
+ TextUtils.equals(feature, Phone.FEATURE_ENABLE_DUN_ALWAYS)) {
+ networkType = ConnectivityManager.TYPE_MOBILE_DUN;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_HIPRI)) {
+ networkType = ConnectivityManager.TYPE_MOBILE_HIPRI;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_FOTA)) {
+ networkType = ConnectivityManager.TYPE_MOBILE_FOTA;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_IMS)) {
+ networkType = ConnectivityManager.TYPE_MOBILE_IMS;
+ } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_CBS)) {
+ networkType = ConnectivityManager.TYPE_MOBILE_CBS;
+ }
+ return networkType;
+ }
}