diff options
34 files changed, 1248 insertions, 648 deletions
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 1429bc1..a127df0 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -18,6 +18,7 @@ package android.net; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; +import android.os.Binder; import android.os.RemoteException; /** @@ -114,15 +115,64 @@ public class ConnectivityManager public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"; - public static final int TYPE_MOBILE = 0; - public static final int TYPE_WIFI = 1; + /** + * The Default Mobile data connection. When active, all data traffic + * will use this connection by default. Should not coexist with other + * default connections. + */ + 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. + */ + public static final int TYPE_WIFI = 1; + /** + * An MMS-specific Mobile data connection. This connection may be the + * same as {@link #TYPEMOBILE} but it may be different. This is used + * by applications needing to talk to the carrier's Multimedia Messaging + * Service servers. It may coexist with default data connections. + * {@hide} + */ + public static final int TYPE_MOBILE_MMS = 2; + /** + * A SUPL-specific Mobile data connection. This connection may be the + * same as {@link #TYPEMOBILE} but it may be different. This is used + * by applications needing to talk to the carrier's Secure User Plane + * Location servers for help locating the device. It may coexist with + * default data connections. + * {@hide} + */ + public static final int TYPE_MOBILE_SUPL = 3; + /** + * A DUN-specific Mobile data connection. This connection may be the + * same as {@link #TYPEMOBILE} but it may be different. This is used + * by applicaitons performing a Dial Up Networking bridge so that + * the carrier is aware of DUN traffic. It may coexist with default data + * connections. + * {@hide} + */ + public static final int TYPE_MOBILE_DUN = 4; + /** + * A High Priority Mobile data connection. This connection is typically + * the same as {@link #TYPEMOBILE} but the routing setup is different. + * Only requesting processes will have access to the Mobile DNS servers + * and only IP's explicitly requested via {@link #requestRouteToHost} + * will route over this interface. + *{@hide} + */ + public static final int TYPE_MOBILE_HIPRI = 5; + /** {@hide} */ + public static final int MAX_RADIO_TYPE = TYPE_WIFI; + /** {@hide} */ + public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_HIPRI; public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; private IConnectivityManager mService; static public boolean isNetworkTypeValid(int networkType) { - return networkType == TYPE_WIFI || networkType == TYPE_MOBILE; + return networkType >= 0 && networkType <= MAX_NETWORK_TYPE; } public void setNetworkPreference(int preference) { @@ -195,7 +245,8 @@ public class ConnectivityManager */ public int startUsingNetworkFeature(int networkType, String feature) { try { - return mService.startUsingNetworkFeature(networkType, feature); + return mService.startUsingNetworkFeature(networkType, feature, + new Binder()); } catch (RemoteException e) { return -1; } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index de68598..9f59cce 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -17,6 +17,7 @@ package android.net; import android.net.NetworkInfo; +import android.os.IBinder; /** * Interface that answers queries about, and allows changing, the @@ -39,7 +40,8 @@ interface IConnectivityManager boolean setRadio(int networkType, boolean turnOn); - int startUsingNetworkFeature(int networkType, in String feature); + int startUsingNetworkFeature(int networkType, in String feature, + in IBinder binder); int stopUsingNetworkFeature(int networkType, in String feature); diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index 1064fb6..6b00900 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -32,9 +32,6 @@ import android.telephony.TelephonyManager; import android.util.Log; import android.text.TextUtils; -import java.util.List; -import java.util.ArrayList; - /** * Track the state of mobile data connectivity. This is done by * receiving broadcast intents from the Phone process whenever @@ -45,36 +42,47 @@ import java.util.ArrayList; public class MobileDataStateTracker extends NetworkStateTracker { private static final String TAG = "MobileDataStateTracker"; - private static final boolean DBG = false; + private static final boolean DBG = true; private Phone.DataState mMobileDataState; private ITelephony mPhoneService; - private static final String[] sDnsPropNames = { - "net.rmnet0.dns1", - "net.rmnet0.dns2", - "net.eth0.dns1", - "net.eth0.dns2", - "net.eth0.dns3", - "net.eth0.dns4", - "net.gprs.dns1", - "net.gprs.dns2" - }; - private List<String> mDnsServers; - private String mInterfaceName; - private int mDefaultGatewayAddr; - private int mLastCallingPid = -1; + + private String mApnType; + private boolean mEnabled; + private boolean mTeardownRequested; /** * Create a new MobileDataStateTracker * @param context the application context of the caller * @param target a message handler for getting callbacks about state changes + * @param netType the ConnectivityManager network type + * @param apnType the Phone apnType + * @param tag the name of this network */ - public MobileDataStateTracker(Context context, Handler target) { - super(context, target, ConnectivityManager.TYPE_MOBILE, - TelephonyManager.getDefault().getNetworkType(), "MOBILE", - TelephonyManager.getDefault().getNetworkTypeName()); + public MobileDataStateTracker(Context context, Handler target, + int netType, String apnType, String tag) { + super(context, target, netType, + TelephonyManager.getDefault().getNetworkType(), tag, + TelephonyManager.getDefault().getNetworkTypeName()); + mApnType = apnType; mPhoneService = null; - mDnsServers = new ArrayList<String>(); + mTeardownRequested = false; + if(netType == ConnectivityManager.TYPE_MOBILE) { + mEnabled = true; + } else { + mEnabled = false; + } + + mDnsPropNames = new String[] { + "net.rmnet0.dns1", + "net.rmnet0.dns2", + "net.eth0.dns1", + "net.eth0.dns2", + "net.eth0.dns3", + "net.eth0.dns4", + "net.gprs.dns1", + "net.gprs.dns2"}; + } /** @@ -93,31 +101,70 @@ public class MobileDataStateTracker extends NetworkStateTracker { mMobileDataState = Phone.DataState.DISCONNECTED; } - private static Phone.DataState getMobileDataState(Intent intent) { + private Phone.DataState getMobileDataState(Intent intent) { String str = intent.getStringExtra(Phone.STATE_KEY); - if (str != null) - return Enum.valueOf(Phone.DataState.class, str); - else - return Phone.DataState.DISCONNECTED; + if (str != null) { + String apnTypeList = + intent.getStringExtra(Phone.DATA_APN_TYPES_KEY); + if (isApnTypeIncluded(apnTypeList)) { + return Enum.valueOf(Phone.DataState.class, str); + } + } + return Phone.DataState.DISCONNECTED; + } + + private boolean isApnTypeIncluded(String typeList) { + /* comma seperated list - split and check */ + if (typeList == null) + return false; + + String[] list = typeList.split(","); + for(int i=0; i< list.length; i++) { + if (TextUtils.equals(list[i], mApnType) || + TextUtils.equals(list[i], Phone.APN_TYPE_ALL)) { + return true; + } + } + return false; } private class MobileDataStateReceiver extends BroadcastReceiver { public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { + if (intent.getAction().equals(TelephonyIntents. + ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { Phone.DataState state = getMobileDataState(intent); - String reason = intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); + String reason = + intent.getStringExtra(Phone.STATE_CHANGE_REASON_KEY); String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); - boolean unavailable = intent.getBooleanExtra(Phone.NETWORK_UNAVAILABLE_KEY, false); - if (DBG) Log.d(TAG, "Received " + intent.getAction() + - " broadcast - state = " + state - + ", unavailable = " + unavailable - + ", reason = " + (reason == null ? "(unspecified)" : reason)); + + String apnTypeList = + intent.getStringExtra(Phone.DATA_APN_TYPES_KEY); + + boolean unavailable = intent.getBooleanExtra( + Phone.NETWORK_UNAVAILABLE_KEY, false); + if (DBG) Log.d(TAG, mApnType + " Received " + + intent.getAction() + " broadcast - state = " + + state + ", unavailable = " + unavailable + + ", reason = " + + (reason == null ? "(unspecified)" : reason)); + + if ((!isApnTypeIncluded(apnTypeList)) || mEnabled == false) { + if (DBG) Log.e(TAG, " dropped - mEnabled = "+mEnabled); + return; + } + + mNetworkInfo.setIsAvailable(!unavailable); if (mMobileDataState != state) { mMobileDataState = state; switch (state) { case DISCONNECTED: + if(mTeardownRequested) { + mEnabled = false; + mTeardownRequested = false; + } + setDetailedState(DetailedState.DISCONNECTED, reason, apnName); if (mInterfaceName != null) { NetworkUtils.resetConnections(mInterfaceName); @@ -136,12 +183,12 @@ public class MobileDataStateTracker extends NetworkStateTracker { if (mInterfaceName == null) { Log.d(TAG, "CONNECTED event did not supply interface name."); } - setupDnsProperties(); setDetailedState(DetailedState.CONNECTED, reason, apnName); break; } } } else if (intent.getAction().equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { + mEnabled = false; String reason = intent.getStringExtra(Phone.FAILURE_REASON_KEY); String apnName = intent.getStringExtra(Phone.DATA_APN_KEY); if (DBG) Log.d(TAG, "Received " + intent.getAction() + " broadcast" + @@ -154,40 +201,6 @@ public class MobileDataStateTracker extends NetworkStateTracker { } } - /** - * Make sure that route(s) exist to the carrier DNS server(s). - */ - public void addPrivateRoutes() { - if (mInterfaceName != null) { - for (String addrString : mDnsServers) { - int addr = NetworkUtils.lookupHost(addrString); - if (addr != -1) { - NetworkUtils.addHostRoute(mInterfaceName, addr); - } - } - } - } - - public void removePrivateRoutes() { - if(mInterfaceName != null) { - NetworkUtils.removeHostRoutes(mInterfaceName); - } - } - - public void removeDefaultRoute() { - if(mInterfaceName != null) { - mDefaultGatewayAddr = NetworkUtils.getDefaultRoute(mInterfaceName); - NetworkUtils.removeDefaultRoute(mInterfaceName); - } - } - - public void restoreDefaultRoute() { - // 0 is not a valid address for a gateway - if (mInterfaceName != null && mDefaultGatewayAddr != 0) { - NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr); - } - } - private void getPhoneService(boolean forceRefresh) { if ((mPhoneService == null) || forceRefresh) { mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); @@ -219,15 +232,6 @@ public class MobileDataStateTracker extends NetworkStateTracker { } /** - * Return the IP addresses of the DNS servers available for the mobile data - * network interface. - * @return a list of DNS addresses, with no holes. - */ - public String[] getNameServers() { - return getNameServerList(sDnsPropNames); - } - - /** * {@inheritDoc} * The mobile data network subtype indicates what generation network technology is in effect, * e.g., GPRS, EDGE, UMTS, etc. @@ -273,54 +277,19 @@ public class MobileDataStateTracker extends NetworkStateTracker { */ @Override public boolean teardown() { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - Log.w(TAG, - "Ignoring mobile data teardown request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.disableDataConnectivity(); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - Log.w(TAG, "Failed to tear down mobile data connectivity"); - return false; + mTeardownRequested = true; + return (setEnableApn(mApnType, false) != Phone.APN_REQUEST_FAILED); } /** * Re-enable mobile data connectivity after a {@link #teardown()}. */ public boolean reconnect() { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - Log.w(TAG, - "Ignoring mobile data connect request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.enableDataConnectivity(); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - Log.w(TAG, "Failed to set up mobile data connectivity"); - return false; + mEnabled = true; + mTeardownRequested = false; + mEnabled = (setEnableApn(mApnType, true) != + Phone.APN_REQUEST_FAILED); + return mEnabled; } /** @@ -374,14 +343,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { * </ul> */ public int startUsingNetworkFeature(String feature, int callingPid, int callingUid) { - if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { - mLastCallingPid = callingPid; - return setEnableApn(Phone.APN_TYPE_MMS, true); - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { - return setEnableApn(Phone.APN_TYPE_SUPL, true); - } else { - return -1; - } + return -1; } /** @@ -397,13 +359,7 @@ public class MobileDataStateTracker extends NetworkStateTracker { * the value {@code -1} always indicates failure. */ public int stopUsingNetworkFeature(String feature, int callingPid, int callingUid) { - if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_MMS)) { - return setEnableApn(Phone.APN_TYPE_MMS, false); - } else if (TextUtils.equals(feature, Phone.FEATURE_ENABLE_SUPL)) { - return setEnableApn(Phone.APN_TYPE_SUPL, false); - } else { - return -1; - } + return -1; } /** @@ -433,43 +389,6 @@ public class MobileDataStateTracker extends NetworkStateTracker { return sb.toString(); } - private void setupDnsProperties() { - mDnsServers.clear(); - // Set up per-process DNS server list on behalf of the MMS process - int i = 1; - if (mInterfaceName != null) { - for (String propName : sDnsPropNames) { - if (propName.indexOf(mInterfaceName) != -1) { - String propVal = SystemProperties.get(propName); - if (propVal != null && propVal.length() != 0 && !propVal.equals("0.0.0.0")) { - mDnsServers.add(propVal); - if (mLastCallingPid != -1) { - SystemProperties.set("net.dns" + i + "." + mLastCallingPid, propVal); - } - ++i; - } - } - } - } - if (i == 1) { - Log.d(TAG, "DNS server addresses are not known."); - } else if (mLastCallingPid != -1) { - /* - * Bump the property that tells the name resolver library - * to reread the DNS server list from the properties. - */ - String propVal = SystemProperties.get("net.dnschange"); - if (propVal.length() != 0) { - try { - int n = Integer.parseInt(propVal); - SystemProperties.set("net.dnschange", "" + (n+1)); - } catch (NumberFormatException e) { - } - } - } - mLastCallingPid = -1; - } - /** * Internal method supporting the ENABLE_MMS feature. * @param apnType the type of APN to be enabled or disabled (e.g., mms) diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index 37087ac..418f511 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -27,6 +27,7 @@ import android.text.TextUtils; import android.util.Config; import android.util.Log; + /** * Each subclass of this class keeps track of the state of connectivity * of a network interface. All state information for a network should @@ -40,11 +41,16 @@ public abstract class NetworkStateTracker extends Handler { protected NetworkInfo mNetworkInfo; protected Context mContext; protected Handler mTarget; + protected String mInterfaceName; + protected String[] mDnsPropNames; + private boolean mPrivateDnsRouteSet; + protected int mDefaultGatewayAddr; + private boolean mDefaultRouteSet; private boolean mTeardownRequested; - private static boolean DBG = Config.LOGV; + private static boolean DBG = Config.LOGV; private static final String TAG = "NetworkStateTracker"; - + public static final int EVENT_STATE_CHANGED = 1; public static final int EVENT_SCAN_RESULTS_AVAILABLE = 2; /** @@ -56,6 +62,7 @@ public abstract class NetworkStateTracker extends Handler { public static final int EVENT_CONFIGURATION_CHANGED = 4; public static final int EVENT_ROAMING_CHANGED = 5; public static final int EVENT_NETWORK_SUBTYPE_CHANGED = 6; + public static final int EVENT_RESTORE_DEFAULT_NETWORK = 7; public NetworkStateTracker(Context context, Handler target, @@ -67,6 +74,7 @@ public abstract class NetworkStateTracker extends Handler { mContext = context; mTarget = target; mTeardownRequested = false; + this.mNetworkInfo = new NetworkInfo(networkType, subType, typeName, subtypeName); } @@ -75,19 +83,21 @@ public abstract class NetworkStateTracker extends Handler { } /** - * Return the list of DNS servers associated with this network. - * @return a list of the IP addresses of the DNS servers available - * for the network. - */ - public abstract String[] getNameServers(); - - /** * Return the system properties name associated with the tcp buffer sizes * for this network. */ public abstract String getTcpBufferSizesPropName(); /** + * Return the IP addresses of the DNS servers available for the mobile data + * network interface. + * @return a list of DNS addresses, with no holes. + */ + public String[] getNameServers() { + return getNameServerList(mDnsPropNames); + } + + /** * Return the IP addresses of the DNS servers available for this * network interface. * @param propertyNames the names of the system properties whose values @@ -112,6 +122,50 @@ public abstract class NetworkStateTracker extends Handler { return dnsAddresses; } + public void addPrivateDnsRoutes() { + if (DBG) Log.d(TAG, "addPrivateDnsRoutes for " + this + + "(" + mInterfaceName + ")"); + if (mInterfaceName != null && !mPrivateDnsRouteSet) { + for (String addrString : getNameServers()) { + int addr = NetworkUtils.lookupHost(addrString); + if (addr != -1) { + NetworkUtils.addHostRoute(mInterfaceName, addr); + } + } + mPrivateDnsRouteSet = true; + } + } + + public void removePrivateDnsRoutes() { + if (DBG) Log.d(TAG, "removePrivateDnsRoutes for " + this + + "(" + mInterfaceName + ")"); + // TODO - we should do this explicitly but the NetUtils api doesnt + // support this yet - must remove all. No worse than before + if (mInterfaceName != null && mPrivateDnsRouteSet) { + NetworkUtils.removeHostRoutes(mInterfaceName); + mPrivateDnsRouteSet = false; + } + } + + public void addDefaultRoute() { + if (DBG) Log.d(TAG, "addDefaultRoute for " + this + "(" + + mInterfaceName + "), GatewayAddr=" + mDefaultGatewayAddr); + if ((mInterfaceName != null) && (mDefaultGatewayAddr != 0) && + mDefaultRouteSet == false) { + NetworkUtils.setDefaultRoute(mInterfaceName, mDefaultGatewayAddr); + mDefaultRouteSet = true; + } + } + + public void removeDefaultRoute() { + if (DBG) Log.d(TAG, "removeDefaultRoute for " + this + "(" + + mInterfaceName + ")"); + if (mInterfaceName != null && mDefaultRouteSet == true) { + NetworkUtils.removeDefaultRoute(mInterfaceName); + mDefaultRouteSet = false; + } + } + /** * Reads the network specific TCP buffer sizes from SystemProperties * net.tcp.buffersize.[default|wifi|umts|edge|gprs] and set them for system @@ -209,6 +263,7 @@ public abstract class NetworkStateTracker extends Handler { * @param extraInfo optional {@code String} providing extra information about the state change */ public void setDetailedState(NetworkInfo.DetailedState state, String reason, String extraInfo) { + if (DBG) Log.d(TAG, "setDetailed state, old ="+mNetworkInfo.getDetailedState()+" and new state="+state); if (state != mNetworkInfo.getDetailedState()) { boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING); String lastReason = mNetworkInfo.getReason(); diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java index e420c27..172e9ac 100644 --- a/core/java/android/text/method/QwertyKeyListener.java +++ b/core/java/android/text/method/QwertyKeyListener.java @@ -434,7 +434,7 @@ public class QwertyKeyListener extends BaseKeyListener { PICKER_SETS.put('y', "\u00FD\u00FF"); PICKER_SETS.put('z', "\u017A\u017C\u017E"); PICKER_SETS.put(KeyCharacterMap.PICKER_DIALOG_INPUT, - "\u2026\u00A5\u2022\u00AE\u00A9\u00B1"); + "\u2026\u00A5\u2022\u00AE\u00A9\u00B1[]{}\\"); }; private boolean showCharacterPicker(View view, Editable content, char c, diff --git a/core/java/com/android/internal/widget/ContactHeaderWidget.java b/core/java/com/android/internal/widget/ContactHeaderWidget.java index 85f7ae8..30349b3 100644 --- a/core/java/com/android/internal/widget/ContactHeaderWidget.java +++ b/core/java/com/android/internal/widget/ContactHeaderWidget.java @@ -27,6 +27,7 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Handler; import android.os.Message; @@ -251,6 +252,20 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList } /** + * Manually set the presence. + */ + public void setPresence(int presence) { + mPresenceView.setImageResource(Presence.getPresenceIconResourceId(presence)); + } + + /** + * Manually set the contact uri + */ + public void setContactUri(Uri uri) { + mContactUri = uri; + } + + /** * Manually set the photo to display in the header. This doesn't change the * underlying {@link Contacts}, only the UI state. */ @@ -364,18 +379,6 @@ public class ContactHeaderWidget extends FrameLayout implements View.OnClickList } /** - * @deprecated use {@link #setDisplayName(CharSequence, CharSequence)} and - * {@link #setSocialSnippet(CharSequence)} instead. - */ - @Deprecated - public void bindStatic(String main, String secondary) { - mDisplayNameView.setText(main); - mStatusView.setText(secondary); - mStarredView.setVisibility(View.GONE); - mPhotoView.setImageBitmap(loadPlaceholderPhoto(null)); - } - - /** * Bind the contact details provided by the given {@link Cursor}. */ protected void bindContactInfo(Cursor c) { diff --git a/core/res/res/layout/contact_header_name.xml b/core/res/res/layout/contact_header_name.xml index 77751c3..9039702 100644 --- a/core/res/res/layout/contact_header_name.xml +++ b/core/res/res/layout/contact_header_name.xml @@ -19,7 +19,7 @@ android:id="@+id/name" android:layout_width="fill_parent" android:layout_height="wrap_content" - android:textAppearance="?android:attr/textAppearanceLargeInverse" + android:textAppearance="?android:attr/textAppearanceMediumInverse" android:textColor="@android:color/secondary_text_light" android:singleLine="true" android:ellipsize="end" diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index f655b27..92c776c 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -38,4 +38,23 @@ <!-- Flag indicating whether Last Name comes before First Name. This becomes true in Japan, for example.--> <bool name="config_lastname_comes_before_firstname">false</bool> + + <!-- This string array should be overridden by the device to present a list of network attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardward --> + <!-- An Array of "[type-name],[associated radio-name],[priority] --> + <string-array translatable="false" name="networkAttributes"> + <item>"default,wifi,0"</item> + <item>"default,mobile,0"</item> + <item>"mms,mobile,1"</item> + <item>"supl,mobile,1"</item> + <item>"dun,mobile,1"</item> + <item>"hipri,mobile,2"</item> + </string-array> + + <!-- This string array should be overridden by the device to present a list of radio attributes. This is used by the connectivity manager to decide which networks can coexist based on the hardware --> + <!-- An Array of "[radio-name],[priority] --> + <!-- [# simultaneous connection types]" --> + <string-array translatable="false" name="radioAttributes"> + <item>"wifi,1,1"</item> + <item>"mobile,0,1"</item> + </string-array> </resources> diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index 31bfc57..b98a48a 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -142,10 +142,10 @@ public class RenderScript { native void nScriptSetClearDepth(int script, float depth); native void nScriptSetClearStencil(int script, int stencil); native void nScriptSetTimeZone(int script, byte[] timeZone); + native void nScriptSetType(int type, String name, int slot); + native void nScriptSetRoot(boolean isRoot); native void nScriptCBegin(); - native void nScriptCAddType(int type); - native void nScriptCSetRoot(boolean isRoot); native void nScriptCSetScript(byte[] script, int offset, int length); native int nScriptCCreate(); native void nScriptCAddDefineI32(String name, int value); diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java index 42c58ce..47479d8 100644 --- a/graphics/java/android/renderscript/Script.java +++ b/graphics/java/android/renderscript/Script.java @@ -20,6 +20,8 @@ package android.renderscript; * @hide **/ public class Script extends BaseObj { + public static final int MAX_SLOT = 16; + boolean mIsRoot; Type[] mTypes; @@ -64,39 +66,36 @@ public class Script extends BaseObj { RenderScript mRS; boolean mIsRoot = false; Type[] mTypes; - int mTypeCount; + String[] mNames; Builder(RenderScript rs) { mRS = rs; - mTypes = new Type[4]; - mTypeCount = 0; + mTypes = new Type[MAX_SLOT]; + mNames = new String[MAX_SLOT]; } - public void addType(Type t) { - if(mTypeCount >= mTypes.length) { - Type[] nt = new Type[mTypeCount * 2]; - for(int ct=0; ct < mTypeCount; ct++) { - nt[ct] = mTypes[ct]; - } - mTypes = nt; - } - mTypes[mTypeCount] = t; - mTypeCount++; + public void setType(Type t, int slot) { + mTypes[slot] = t; + mNames[slot] = null; + } + + public void setType(Type t, String name, int slot) { + mTypes[slot] = t; + mNames[slot] = name; } void transferCreate() { - mRS.nScriptCSetRoot(mIsRoot); - for(int ct=0; ct < mTypeCount; ct++) { - mRS.nScriptCAddType(mTypes[ct].mID); + mRS.nScriptSetRoot(mIsRoot); + for(int ct=0; ct < mTypes.length; ct++) { + if(mTypes[ct] != null) { + mRS.nScriptSetType(mTypes[ct].mID, mNames[ct], ct); + } } } void transferObject(Script s) { s.mIsRoot = mIsRoot; - s.mTypes = new Type[mTypeCount]; - for(int ct=0; ct < mTypeCount; ct++) { - s.mTypes[ct] = mTypes[ct]; - } + s.mTypes = mTypes; } public void setRoot(boolean r) { diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java index d35d482..afb0e60 100644 --- a/graphics/java/android/renderscript/Type.java +++ b/graphics/java/android/renderscript/Type.java @@ -56,7 +56,7 @@ public class Type extends BaseObj { mRS.nTypeDestroy(mID); } - public static Type createFromClass(RenderScript rs, Class c, int size, String scriptName) { + public static Type createFromClass(RenderScript rs, Class c, int size) { Element e = Element.createFromClass(rs, c); Builder b = new Builder(rs, e); b.add(Dimension.X, size); @@ -91,10 +91,16 @@ public class Type extends BaseObj { rs.nTypeSetupFields(t, arTypes, arBits, fields); } t.mJavaClass = c; + return t; + } + + public static Type createFromClass(RenderScript rs, Class c, int size, String scriptName) { + Type t = createFromClass(rs, c, size); t.setName(scriptName); return t; } + public static class Builder { RenderScript mRS; Entry[] mEntries; diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index ef0cf68..5780e02 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -824,30 +824,37 @@ nScriptSetTimeZone(JNIEnv *_env, jobject _this, jint script, jbyteArray timeZone } } -// ----------------------------------- - static void -nScriptCBegin(JNIEnv *_env, jobject _this) +nScriptSetType(JNIEnv *_env, jobject _this, jint type, jstring _str, jint slot) { RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptCBegin, con(%p)", con); - rsScriptCBegin(); + LOG_API("nScriptCAddType, con(%p), type(%p), slot(%i)", con, (RsType)type, slot); + const char* n = NULL; + if (_str) { + n = _env->GetStringUTFChars(_str, NULL); + } + rsScriptSetType((RsType)type, slot, n); + if (n) { + _env->ReleaseStringUTFChars(_str, n); + } } static void -nScriptCAddType(JNIEnv *_env, jobject _this, jint type) +nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot) { RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptCAddType, con(%p), type(%p)", con, (RsType)type); - rsScriptCAddType((RsType)type); + LOG_API("nScriptCSetRoot, con(%p), isRoot(%i)", con, isRoot); + rsScriptSetRoot(isRoot); } +// ----------------------------------- + static void -nScriptCSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot) +nScriptCBegin(JNIEnv *_env, jobject _this) { RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptCSetRoot, con(%p), isRoot(%i)", con, isRoot); - rsScriptCSetRoot(isRoot); + LOG_API("nScriptCBegin, con(%p)", con); + rsScriptCBegin(); } static void @@ -1374,10 +1381,10 @@ static JNINativeMethod methods[] = { {"nScriptSetClearDepth", "(IF)V", (void*)nScriptSetClearDepth }, {"nScriptSetClearStencil", "(II)V", (void*)nScriptSetClearStencil }, {"nScriptSetTimeZone", "(I[B)V", (void*)nScriptSetTimeZone }, +{"nScriptSetType", "(ILjava/lang/String;I)V", (void*)nScriptSetType }, +{"nScriptSetRoot", "(Z)V", (void*)nScriptSetRoot }, {"nScriptCBegin", "()V", (void*)nScriptCBegin }, -{"nScriptCAddType", "(I)V", (void*)nScriptCAddType }, -{"nScriptCSetRoot", "(Z)V", (void*)nScriptCSetRoot }, {"nScriptCSetScript", "([BII)V", (void*)nScriptCSetScript }, {"nScriptCCreate", "()I", (void*)nScriptCCreate }, {"nScriptCAddDefineI32", "(Ljava/lang/String;I)V", (void*)nScriptCAddDefineI32 }, diff --git a/libs/rs/java/Film/res/raw/filmstrip.c b/libs/rs/java/Film/res/raw/filmstrip.c index 4e7c37a..255d908 100644 --- a/libs/rs/java/Film/res/raw/filmstrip.c +++ b/libs/rs/java/Film/res/raw/filmstrip.c @@ -22,8 +22,8 @@ int main(int index) { float mat1[16]; - float trans = loadF(1, POS_TRANSLATE); - float rot = loadF(1, POS_ROTATE); + float trans = Pos_translate; + float rot = Pos_rotate; matrixLoadScale(mat1, 2.f, 2.f, 2.f); matrixTranslate(mat1, 0.f, 0.f, trans); matrixRotate(mat1, 90.f, 0.f, 0.f, 1.f); @@ -39,7 +39,7 @@ int main(int index) bindProgramFragment(NAMED_PFImages); bindProgramVertex(NAMED_PVImages); - float focusPos = loadF(1, POS_FOCUS); + float focusPos = Pos_focus; int focusID = 0; int lastFocusID = loadI32(2, STATE_LAST_FOCUS); int imgCount = 13; @@ -65,7 +65,7 @@ int main(int index) */ storeI32(2, STATE_LAST_FOCUS, focusID); - int triangleOffsetsCount = loadI32(2, STATE_TRIANGLE_OFFSET_COUNT); + int triangleOffsetsCount = Pos_triangleOffsetCount; int imgId = 0; for (imgId=1; imgId <= imgCount; imgId++) { diff --git a/libs/rs/java/Film/src/com/android/film/FilmRS.java b/libs/rs/java/Film/src/com/android/film/FilmRS.java index 74f88c4..e6cd52d 100644 --- a/libs/rs/java/Film/src/com/android/film/FilmRS.java +++ b/libs/rs/java/Film/src/com/android/film/FilmRS.java @@ -23,25 +23,18 @@ import android.content.res.Resources; import android.graphics.Bitmap; import android.util.Log; -import android.renderscript.Matrix; -import android.renderscript.ProgramVertex; -import android.renderscript.RenderScript; -import android.renderscript.Element; -import android.renderscript.Allocation; -import android.renderscript.Dimension; -import android.renderscript.ScriptC; -import android.renderscript.Script; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.Sampler; -import android.renderscript.Light; +import android.renderscript.*; public class FilmRS { - private final int POS_TRANSLATE = 0; - private final int POS_ROTATE = 1; - private final int POS_FOCUS = 2; + class StripPosition { + public float translate; + public float rotate; + public float focus; + public int triangleOffsetCount; + } + StripPosition mPos = new StripPosition(); + - private final int STATE_TRIANGLE_OFFSET_COUNT = 0; private final int STATE_LAST_FOCUS = 1; public FilmRS() { @@ -63,10 +56,11 @@ public class FilmRS { } float anim = ((float)x-50) / 270.f; - mBufferPos[POS_TRANSLATE] = 2f * anim + 0.5f; // translation - mBufferPos[POS_ROTATE] = (anim * 40); // rotation - mBufferPos[POS_FOCUS] = ((float)y) / 16.f - 10.f; // focusPos - mAllocPos.data(mBufferPos); + mPos.translate = 2f * anim + 0.5f; // translation + mPos.rotate = (anim * 40); // rotation + mPos.focus = ((float)y) / 16.f - 10.f; // focusPos + mPos.triangleOffsetCount = mFSM.mTriangleOffsetsCount; + mAllocPos.data(mPos); } @@ -84,6 +78,7 @@ public class FilmRS { private ProgramVertex mPVBackground; private ProgramVertex mPVImages; private ProgramVertex.MatrixAllocation mPVA; + private Type mStripPositionType; private Allocation mImages[]; private Allocation mAllocIDs; @@ -204,10 +199,7 @@ public class FilmRS { mBufferState = new int[10]; mAllocState = Allocation.createSized(mRS, Element.USER_FLOAT, mBufferState.length); - - mBufferState[STATE_TRIANGLE_OFFSET_COUNT] = mFSM.mTriangleOffsetsCount; mBufferState[STATE_LAST_FOCUS] = -1; - mAllocState.data(mBufferState); } @@ -227,14 +219,16 @@ public class FilmRS { Log.e("rs", "Done loading named"); + mStripPositionType = Type.createFromClass(mRS, StripPosition.class, 1); + ScriptC.Builder sb = new ScriptC.Builder(mRS); sb.setScript(mRes, R.raw.filmstrip); sb.setRoot(true); + sb.setType(mStripPositionType, "Pos", 1); mScriptStrip = sb.create(); mScriptStrip.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); - mAllocPos = Allocation.createSized(mRS, - Element.USER_FLOAT, mBufferPos.length); + mAllocPos = Allocation.createTyped(mRS, mStripPositionType); loadImages(); initState(); diff --git a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java index 3e680e3..da4eeb4 100644 --- a/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java +++ b/libs/rs/java/Fountain/src/com/android/fountain/FountainRS.java @@ -118,7 +118,7 @@ public class FountainRS { ScriptC.Builder sb = new ScriptC.Builder(mRS); sb.setScript(mRes, R.raw.fountain); sb.setRoot(true); - sb.addType(mSDType); + sb.setType(mSDType, 0); mScript = sb.create(); mScript.setClearColor(0.0f, 0.0f, 0.0f, 1.0f); diff --git a/libs/rs/rs.spec b/libs/rs/rs.spec index d4fbf6b..105142b 100644 --- a/libs/rs/rs.spec +++ b/libs/rs/rs.spec @@ -312,14 +312,18 @@ ScriptSetClearStencil { param uint32_t stencil } -ScriptCAddType { +ScriptSetType { param RsType type + param uint32_t slot + param const char * name } -ScriptCSetRoot { +ScriptSetRoot { param bool isRoot } + + ScriptCSetScript { param void * codePtr } diff --git a/libs/rs/rsComponent.cpp b/libs/rs/rsComponent.cpp index 831580b..b88710c 100644 --- a/libs/rs/rsComponent.cpp +++ b/libs/rs/rsComponent.cpp @@ -42,6 +42,26 @@ Component::Component( } } +const char * Component::getCType() const +{ + switch(mType) { + case FLOAT: + return "float"; + case SIGNED: + case UNSIGNED: + switch(mBits) { + case 32: + return "int"; + case 16: + return "short"; + case 8: + return "char"; + } + break; + } + return NULL; +} + Component::~Component() { } diff --git a/libs/rs/rsComponent.h b/libs/rs/rsComponent.h index 5ee95c7..6342f1b 100644 --- a/libs/rs/rsComponent.h +++ b/libs/rs/rsComponent.h @@ -53,6 +53,7 @@ public: uint32_t getBits() const {return mBits;} uint32_t getGLType() const; + const char * getCType() const; const char * getComponentName() const {return mName.string();} diff --git a/libs/rs/rsScript.cpp b/libs/rs/rsScript.cpp index 6ce9f61..75c994b 100644 --- a/libs/rs/rsScript.cpp +++ b/libs/rs/rsScript.cpp @@ -76,6 +76,25 @@ void rsi_ScriptSetClearStencil(Context * rsc, RsScript vs, uint32_t v) s->mEnviroment.mClearStencil = v; } +void rsi_ScriptSetType(Context * rsc, RsType vt, uint32_t slot, const char *name) +{ + ScriptCState *ss = &rsc->mScriptC; + const Type *t = static_cast<const Type *>(vt); + ss->mConstantBufferTypes[slot].set(t); + if (name) { + ss->mSlotNames[slot].setTo(name); + } else { + ss->mSlotNames[slot].setTo(""); + } +} + +void rsi_ScriptSetRoot(Context * rsc, bool isRoot) +{ + ScriptCState *ss = &rsc->mScriptC; + ss->mEnviroment.mIsRoot = isRoot; +} + + } } diff --git a/libs/rs/rsScript.h b/libs/rs/rsScript.h index 6983ef4..dc66763 100644 --- a/libs/rs/rsScript.h +++ b/libs/rs/rsScript.h @@ -56,11 +56,11 @@ public: }; Enviroment_t mEnviroment; - const Type * mConstantBufferTypes; uint32_t mCounstantBufferCount; ObjectBaseRef<Allocation> mSlots[MAX_SCRIPT_BANKS]; - ObjectBaseRef<Type> mTypes[MAX_SCRIPT_BANKS]; + ObjectBaseRef<const Type> mTypes[MAX_SCRIPT_BANKS]; + String8 mSlotNames[MAX_SCRIPT_BANKS]; virtual bool run(Context *, uint32_t launchID) = 0; }; diff --git a/libs/rs/rsScriptC.cpp b/libs/rs/rsScriptC.cpp index 652283d..ced2516 100644 --- a/libs/rs/rsScriptC.cpp +++ b/libs/rs/rsScriptC.cpp @@ -90,9 +90,9 @@ void ScriptCState::clear() { memset(&mProgram, 0, sizeof(mProgram)); - mConstantTypeCount = 0; for (uint32_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) { mConstantBufferTypes[ct].clear(); + mSlotNames[ct].setTo(""); } memset(&mEnviroment, 0, sizeof(mEnviroment)); @@ -248,24 +248,56 @@ void ScriptCState::appendVarDefines(String8 *str) void ScriptCState::appendTypes(String8 *str) { char buf[256]; + String8 tmp; - for (size_t ct=0; ct < mConstantTypeCount; ct++) { + for (size_t ct=0; ct < MAX_SCRIPT_BANKS; ct++) { const Type *t = mConstantBufferTypes[ct].get(); - const Element *e = t->getElement(); - - if (!t->getName()) { + if (!t) { continue; } - for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) { - const Component *c = e->getComponent(ct2); - str->append("#define OFFSETOF_"); - str->append(t->getName()); - str->append("_"); - str->append(c->getComponentName()); - sprintf(buf, " %i\n", ct2); - str->append(buf); + const Element *e = t->getElement(); + + if (t->getName()) { + for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) { + const Component *c = e->getComponent(ct2); + tmp.setTo("#define OFFSETOF_"); + tmp.append(t->getName()); + tmp.append("_"); + tmp.append(c->getComponentName()); + sprintf(buf, " %i\n", ct2); + tmp.append(buf); + LOGD(tmp); + str->append(tmp); + } } + if (mSlotNames[ct].length() > 0) { + for (size_t ct2=0; ct2 < e->getComponentCount(); ct2++) { + const Component *c = e->getComponent(ct2); + tmp.setTo("#define "); + tmp.append(mSlotNames[ct]); + tmp.append("_"); + tmp.append(c->getComponentName()); + switch (c->getType()) { + case Component::FLOAT: + tmp.append(" loadF("); + break; + case Component::SIGNED: + sprintf(buf, " loadI%i(", c->getBits()); + tmp.append(buf); + break; + case Component::UNSIGNED: + sprintf(buf, " loadU%i(", c->getBits()); + tmp.append(buf); + break; + } + sprintf(buf, "%i, %i)\n", ct, ct2); + tmp.append(buf); + + LOGD(tmp); + str->append(tmp); + } + } } } @@ -280,27 +312,12 @@ void rsi_ScriptCBegin(Context * rsc) ss->clear(); } -void rsi_ScriptCAddType(Context * rsc, RsType vt) -{ - ScriptCState *ss = &rsc->mScriptC; - const Type *t = static_cast<const Type *>(vt); - - ss->mConstantBufferTypes[ss->mConstantTypeCount].set(t); - ss->mConstantTypeCount ++; -} - void rsi_ScriptCSetScript(Context * rsc, void *vp) { ScriptCState *ss = &rsc->mScriptC; ss->mProgram.mScript = reinterpret_cast<ScriptC::RunScript_t>(vp); } -void rsi_ScriptCSetRoot(Context * rsc, bool isRoot) -{ - ScriptCState *ss = &rsc->mScriptC; - ss->mEnviroment.mIsRoot = isRoot; -} - void rsi_ScriptCSetText(Context *rsc, const char *text, uint32_t len) { ScriptCState *ss = &rsc->mScriptC; @@ -321,8 +338,12 @@ RsScript rsi_ScriptCCreate(Context * rsc) ss->mAccScript = NULL; s->mEnviroment = ss->mEnviroment; s->mProgram = ss->mProgram; - ss->clear(); + for (int ct=0; ct < MAX_SCRIPT_BANKS; ct++) { + s->mTypes[ct].set(ss->mConstantBufferTypes[ct].get()); + s->mSlotNames[ct] = ss->mSlotNames[ct]; + } + ss->clear(); return s; } diff --git a/libs/rs/rsScriptC.h b/libs/rs/rsScriptC.h index 60a6fba..32a9079 100644 --- a/libs/rs/rsScriptC.h +++ b/libs/rs/rsScriptC.h @@ -69,7 +69,7 @@ public: Script::Enviroment_t mEnviroment; ObjectBaseRef<const Type> mConstantBufferTypes[MAX_SCRIPT_BANKS]; - uint32_t mConstantTypeCount; + String8 mSlotNames[MAX_SCRIPT_BANKS]; void clear(); void runCompiler(Context *rsc); diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java index 62b839d..1c60058 100644 --- a/services/java/com/android/server/ConnectivityService.java +++ b/services/java/com/android/server/ConnectivityService.java @@ -30,48 +30,130 @@ import android.net.NetworkStateTracker; import android.net.wifi.WifiStateTracker; import android.os.Binder; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.os.Message; +import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.provider.Settings; +import android.text.TextUtils; import android.util.EventLog; import android.util.Log; +import com.android.internal.telephony.Phone; + import java.io.FileDescriptor; import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; /** * @hide */ public class ConnectivityService extends IConnectivityManager.Stub { - private static final boolean DBG = false; + private static final boolean DBG = true; private static final String TAG = "ConnectivityService"; // Event log tags (must be in sync with event-log-tags) private static final int EVENTLOG_CONNECTIVITY_STATE_CHANGED = 50020; + // how long to wait before switching back to a radio's default network + private static final int RESTORE_DEFAULT_NETWORK_DELAY = 1 * 60 * 1000; + // system property that can override the above value + private static final String NETWORK_RESTORE_DELAY_PROP_NAME = + "android.telephony.apn-restore"; + /** * Sometimes we want to refer to the individual network state * trackers separately, and sometimes we just want to treat them * abstractly. */ private NetworkStateTracker mNetTrackers[]; - private WifiStateTracker mWifiStateTracker; - private MobileDataStateTracker mMobileDataStateTracker; + + /** + * 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 + private int[] mPriorityList; + private Context mContext; private int mNetworkPreference; - private NetworkStateTracker mActiveNetwork; + private int mActiveDefaultNetwork = -1; private int mNumDnsEntries; - private static int sDnsChangeCounter; private boolean mTestMode; private static ConnectivityService sServiceInstance; + private Handler mHandler; + + // list of DeathRecipients used to make sure features are turned off when + // a process dies + private List mFeatureUsers; + + private class NetworkAttributes { + /** + * Class for holding settings read from resources. + */ + public String mName; + public int mType; + public int mRadio; + public int mPriority; + public NetworkAttributes(String init) { + String fragments[] = init.split(","); + mName = fragments[0].toLowerCase(); + if (fragments[1].toLowerCase().equals("wifi")) { + mRadio = ConnectivityManager.TYPE_WIFI; + } else { + mRadio = ConnectivityManager.TYPE_MOBILE; + } + if (mName.equals("default")) { + mType = mRadio; + } else if (mName.equals("mms")) { + mType = ConnectivityManager.TYPE_MOBILE_MMS; + } else if (mName.equals("supl")) { + mType = ConnectivityManager.TYPE_MOBILE_SUPL; + } else if (mName.equals("dun")) { + mType = ConnectivityManager.TYPE_MOBILE_DUN; + } else if (mName.equals("hipri")) { + mType = ConnectivityManager.TYPE_MOBILE_HIPRI; + } + mPriority = Integer.parseInt(fragments[2]); + } + public boolean isDefault() { + return (mType == mRadio); + } + } + NetworkAttributes[] mNetAttributes; + + private class RadioAttributes { + public String mName; + public int mPriority; + public int mSimultaneity; + public int mType; + public RadioAttributes(String init) { + String fragments[] = init.split(","); + mName = fragments[0].toLowerCase(); + mPriority = Integer.parseInt(fragments[1]); + mSimultaneity = Integer.parseInt(fragments[2]); + if (mName.equals("wifi")) { + mType = ConnectivityManager.TYPE_WIFI; + } else { + mType = ConnectivityManager.TYPE_MOBILE; + } + } + } + RadioAttributes[] mRadioAttributes; + private static class ConnectivityThread extends Thread { private Context mContext; @@ -118,11 +200,54 @@ public class ConnectivityService extends IConnectivityManager.Stub { private ConnectivityService(Context context) { if (DBG) Log.v(TAG, "ConnectivityService starting up"); mContext = context; - mNetTrackers = new NetworkStateTracker[2]; - Handler handler = new MyHandler(); + mNetTrackers = new NetworkStateTracker[ + ConnectivityManager.MAX_NETWORK_TYPE+1]; + mHandler = new MyHandler(); mNetworkPreference = getPersistedNetworkPreference(); + // Load device network attributes from resources + mNetAttributes = new NetworkAttributes[ + ConnectivityManager.MAX_NETWORK_TYPE+1]; + mRadioAttributes = new RadioAttributes[ + ConnectivityManager.MAX_RADIO_TYPE+1]; + String[] naStrings = context.getResources().getStringArray( + com.android.internal.R.array.networkAttributes); + // TODO - what if the setting has gaps/unknown types? + for (String a : naStrings) { + NetworkAttributes n = new NetworkAttributes(a); + mNetAttributes[n.mType] = n; + } + String[] raStrings = context.getResources().getStringArray( + com.android.internal.R.array.radioAttributes); + for (String a : raStrings) { + RadioAttributes r = new RadioAttributes(a); + mRadioAttributes[r.mType] = r; + } + + // high priority first + mPriorityList = new int[naStrings.length]; + { + int priority = 0; //lowest + int nextPos = naStrings.length-1; + while (nextPos>-1) { + for (int i = 0; i < mNetAttributes.length; i++) { + if(mNetAttributes[i].mPriority == priority) { + mPriorityList[nextPos--] = i; + } + } + priority++; + } + } + + mNetRequestersPids = + new ArrayList[ConnectivityManager.MAX_NETWORK_TYPE+1]; + for (int i=0; i<=ConnectivityManager.MAX_NETWORK_TYPE; i++) { + mNetRequestersPids[i] = new ArrayList(); + } + + mFeatureUsers = new ArrayList(); + /* * Create the network state trackers for Wi-Fi and mobile * data. Maybe this could be done with a factory class, @@ -131,15 +256,36 @@ public class ConnectivityService extends IConnectivityManager.Stub { * to change very often. */ if (DBG) Log.v(TAG, "Starting Wifi Service."); - mWifiStateTracker = new WifiStateTracker(context, handler); - WifiService wifiService = new WifiService(context, mWifiStateTracker); + WifiStateTracker wst = new WifiStateTracker(context, mHandler); + WifiService wifiService = new WifiService(context, wst); ServiceManager.addService(Context.WIFI_SERVICE, wifiService); - mNetTrackers[ConnectivityManager.TYPE_WIFI] = mWifiStateTracker; + mNetTrackers[ConnectivityManager.TYPE_WIFI] = wst; + + mNetTrackers[ConnectivityManager.TYPE_MOBILE] = + new MobileDataStateTracker(context, mHandler, + ConnectivityManager.TYPE_MOBILE, Phone.APN_TYPE_DEFAULT, + "MOBILE"); + + mNetTrackers[ConnectivityManager.TYPE_MOBILE_MMS] = + new MobileDataStateTracker(context, mHandler, + ConnectivityManager.TYPE_MOBILE_MMS, Phone.APN_TYPE_MMS, + "MOBILE_MMS"); - mMobileDataStateTracker = new MobileDataStateTracker(context, handler); - mNetTrackers[ConnectivityManager.TYPE_MOBILE] = mMobileDataStateTracker; + mNetTrackers[ConnectivityManager.TYPE_MOBILE_SUPL] = + new MobileDataStateTracker(context, mHandler, + ConnectivityManager.TYPE_MOBILE_SUPL, Phone.APN_TYPE_SUPL, + "MOBILE_SUPL"); + + mNetTrackers[ConnectivityManager.TYPE_MOBILE_DUN] = + new MobileDataStateTracker(context, mHandler, + ConnectivityManager.TYPE_MOBILE_DUN, Phone.APN_TYPE_DUN, + "MOBILE_DUN"); + + mNetTrackers[ConnectivityManager.TYPE_MOBILE_HIPRI] = + new MobileDataStateTracker(context, mHandler, + ConnectivityManager.TYPE_MOBILE_HIPRI, Phone.APN_TYPE_HIPRI, + "MOBILE_HIPRI"); - mActiveNetwork = null; mNumDnsEntries = 0; mTestMode = SystemProperties.get("cm.test.mode").equals("true") @@ -149,8 +295,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { t.startMonitoring(); // Constructing this starts it too - mWifiWatchdogService = new WifiWatchdogService(context, - mWifiStateTracker); + mWifiWatchdogService = new WifiWatchdogService(context, wst); } /** @@ -159,7 +304,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ public synchronized void setNetworkPreference(int preference) { enforceChangePermission(); - if (ConnectivityManager.isNetworkTypeValid(preference)) { + if (ConnectivityManager.isNetworkTypeValid(preference) && + mNetAttributes[preference].isDefault()) { if (mNetworkPreference != preference) { persistNetworkPreference(preference); mNetworkPreference = preference; @@ -199,23 +345,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { * (see {@link #handleDisconnect(NetworkInfo)}). */ private void enforcePreference() { - if (mActiveNetwork == null) + if (mNetTrackers[mNetworkPreference].getNetworkInfo().isConnected()) return; - for (NetworkStateTracker t : mNetTrackers) { - if (t == mActiveNetwork) { - int netType = t.getNetworkInfo().getType(); - int otherNetType = ((netType == ConnectivityManager.TYPE_WIFI) ? - ConnectivityManager.TYPE_MOBILE : - ConnectivityManager.TYPE_WIFI); - - if (t.getNetworkInfo().getType() != mNetworkPreference) { - NetworkStateTracker otherTracker = - mNetTrackers[otherNetType]; - if (otherTracker.isAvailable()) { - teardown(t); - } - } + if (!mNetTrackers[mNetworkPreference].isAvailable()) + return; + + for (int t=0; t <= ConnectivityManager.MAX_RADIO_TYPE; t++) { + if (t != mNetworkPreference && + mNetTrackers[t].getNetworkInfo().isConnected()) { + teardown(mNetTrackers[t]); } } } @@ -238,9 +377,16 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ public NetworkInfo getActiveNetworkInfo() { enforceAccessPermission(); - for (NetworkStateTracker t : mNetTrackers) { + for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) { + if (!mNetAttributes[type].isDefault()) { + continue; + } + NetworkStateTracker t = mNetTrackers[type]; NetworkInfo info = t.getNetworkInfo(); if (info.isConnected()) { + if (DBG && type != mActiveDefaultNetwork) Log.e(TAG, + "connected default network is not " + + "mActiveDefaultNetwork!"); return info; } } @@ -285,30 +431,189 @@ public class ConnectivityService extends IConnectivityManager.Stub { return tracker != null && tracker.setRadio(turnOn); } - public int startUsingNetworkFeature(int networkType, String feature) { + private class FeatureUser implements IBinder.DeathRecipient { + int mNetworkType; + String mFeature; + IBinder mBinder; + int mPid; + int mUid; + + FeatureUser(int type, String feature, IBinder binder) { + super(); + mNetworkType = type; + mFeature = feature; + mBinder = binder; + mPid = getCallingPid(); + mUid = getCallingUid(); + try { + mBinder.linkToDeath(this, 0); + } catch (RemoteException e) { + binderDied(); + } + } + + void unlinkDeathRecipient() { + mBinder.unlinkToDeath(this, 0); + } + + public void binderDied() { + Log.d(TAG, "ConnectivityService FeatureUser binderDied(" + + mNetworkType + ", " + mFeature + ", " + mBinder); + stopUsingNetworkFeature(mNetworkType, mFeature, mPid, mUid); + } + + } + + public int startUsingNetworkFeature(int networkType, String feature, + IBinder binder) { + if (DBG) { + Log.d(TAG, "startUsingNetworkFeature for net " + networkType + + ": " + feature); + } enforceChangePermission(); if (!ConnectivityManager.isNetworkTypeValid(networkType)) { - return -1; + return Phone.APN_REQUEST_FAILED; } - NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - return tracker.startUsingNetworkFeature(feature, getCallingPid(), - getCallingUid()); + + synchronized (mFeatureUsers) { + mFeatureUsers.add(new FeatureUser(networkType, feature, binder)); + } + + // TODO - move this into the 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; + } + } + NetworkStateTracker network = mNetTrackers[usedNetworkType]; + if (network != null) { + if (usedNetworkType != networkType) { + Integer currentPid = new Integer(getCallingPid()); + + NetworkStateTracker radio = mNetTrackers[networkType]; + NetworkInfo ni = network.getNetworkInfo(); + + if (ni.isAvailable() == false) { + if (DBG) Log.d(TAG, "special network not available"); + return Phone.APN_TYPE_NOT_AVAILABLE; + } + + if (!mNetRequestersPids[usedNetworkType].contains(currentPid)) { + // this gets used for per-pid dns when connected + mNetRequestersPids[usedNetworkType].add(currentPid); + } + + if (ni.isConnectedOrConnecting() == true) { + if (ni.isConnected() == true) { + // add the pid-specific dns + handleDnsConfigurationChange(); + if (DBG) Log.d(TAG, "special network already active"); + return Phone.APN_ALREADY_ACTIVE; + } + if (DBG) Log.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 + + // since we have to drop the default on this radio, setup + // an automatic event to switch back + if(mHandler.hasMessages(NetworkStateTracker. + EVENT_RESTORE_DEFAULT_NETWORK, radio) || + radio.getNetworkInfo().isConnectedOrConnecting()) { + mHandler.removeMessages(NetworkStateTracker. + EVENT_RESTORE_DEFAULT_NETWORK, + radio); + mHandler.sendMessageDelayed(mHandler.obtainMessage( + NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK, + radio), getRestoreDefaultNetworkDelay()); + } + if (DBG) Log.d(TAG, "reconnecting to special network"); + network.reconnect(); + return Phone.APN_REQUEST_STARTED; + } else { + return network.startUsingNetworkFeature(feature, + getCallingPid(), getCallingUid()); + } } - return -1; + return Phone.APN_TYPE_NOT_AVAILABLE; } public int stopUsingNetworkFeature(int networkType, String feature) { + return stopUsingNetworkFeature(networkType, feature, getCallingPid(), + getCallingUid()); + } + + private int stopUsingNetworkFeature(int networkType, String feature, + int pid, int uid) { + if (DBG) { + Log.d(TAG, "stopUsingNetworkFeature for net " + networkType + + ": " + feature); + } enforceChangePermission(); if (!ConnectivityManager.isNetworkTypeValid(networkType)) { return -1; } - NetworkStateTracker tracker = mNetTrackers[networkType]; - if (tracker != null) { - return tracker.stopUsingNetworkFeature(feature, getCallingPid(), - getCallingUid()); + + synchronized (mFeatureUsers) { + for (int i=0; i < mFeatureUsers.size(); i++) { + FeatureUser u = (FeatureUser)mFeatureUsers.get(i); + if (uid == u.mUid && pid == u.mPid && + networkType == u.mNetworkType && + TextUtils.equals(feature, u.mFeature)) { + u.unlinkDeathRecipient(); + mFeatureUsers.remove(i); + break; + } + } + } + + // 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; + } + } + NetworkStateTracker tracker = mNetTrackers[usedNetworkType]; + if(usedNetworkType != networkType) { + Integer currentPid = new Integer(pid); + if (mNetRequestersPids[usedNetworkType].remove(currentPid)) { + reassessPidDns(pid, true); + } + if (mNetRequestersPids[usedNetworkType].size() != 0) { + if (DBG) Log.d(TAG, "not tearing down special network - " + + "others still using it"); + return 1; + } + + tracker.teardown(); + NetworkStateTracker radio = mNetTrackers[networkType]; + // Check if we want to revert to the default + if (mHandler.hasMessages(NetworkStateTracker. + EVENT_RESTORE_DEFAULT_NETWORK, radio)) { + mHandler.removeMessages(NetworkStateTracker. + EVENT_RESTORE_DEFAULT_NETWORK, radio); + radio.reconnect(); + } + return 1; + } else { + return tracker.stopUsingNetworkFeature(feature, pid, uid); } - return -1; } /** @@ -337,7 +642,8 @@ public class ConnectivityService extends IConnectivityManager.Stub { if (getNumConnectedNetworks() > 1) { return tracker.requestRouteToHost(hostAddress); } else { - return tracker.getNetworkInfo().getType() == networkType; + return (mNetAttributes[networkType].isDefault() && + tracker.getNetworkInfo().isConnected()); } } @@ -402,45 +708,26 @@ public class ConnectivityService extends IConnectivityManager.Stub { private void handleDisconnect(NetworkInfo info) { if (DBG) Log.v(TAG, "Handle DISCONNECT for " + info.getTypeName()); + int prevNetType = info.getType(); - mNetTrackers[info.getType()].setTeardownRequested(false); + mNetTrackers[prevNetType].setTeardownRequested(false); /* * If the disconnected network is not the active one, then don't report * this as a loss of connectivity. What probably happened is that we're * getting the disconnect for a network that we explicitly disabled * in accordance with network preference policies. */ - if (mActiveNetwork == null || - info.getType() != mActiveNetwork.getNetworkInfo().getType()) - return; - - NetworkStateTracker newNet; - if (info.getType() == ConnectivityManager.TYPE_MOBILE) { - newNet = mWifiStateTracker; - } else /* info().getType() == TYPE_WIFI */ { - newNet = mMobileDataStateTracker; - } - - /** - * See if the other network is available to fail over to. - * If is not available, we enable it anyway, so that it - * will be able to connect when it does become available, - * but we report a total loss of connectivity rather than - * report that we are attempting to fail over. - */ - NetworkInfo switchTo = null; - if (newNet.isAvailable()) { - mActiveNetwork = newNet; - switchTo = newNet.getNetworkInfo(); - switchTo.setFailover(true); - if (!switchTo.isConnectedOrConnecting()) { - newNet.reconnect(); + if (!mNetAttributes[prevNetType].isDefault()) { + List pids = mNetRequestersPids[prevNetType]; + for (int i = 0; i<pids.size(); i++) { + Integer pid = (Integer)pids.get(i); + // will remove them because the net's no longer connected + // need to do this now as only now do we know the pids and + // can properly null things that are no longer referenced. + reassessPidDns(pid.intValue(), false); } - } else { - newNet.reconnect(); } - boolean otherNetworkConnected = false; Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); if (info.isFailover()) { @@ -454,33 +741,92 @@ public class ConnectivityService extends IConnectivityManager.Stub { intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, info.getExtraInfo()); } - if (switchTo != null) { - otherNetworkConnected = switchTo.isConnected(); - if (DBG) { - if (otherNetworkConnected) { - Log.v(TAG, "Switching to already connected " + - switchTo.getTypeName()); + + /* + * If this is a default network, check if other defaults are available + * or active + */ + NetworkStateTracker newNet = null; + if (mNetAttributes[prevNetType].isDefault()) { + if (DBG) Log.d(TAG, "disconnecting a default network"); + if (mActiveDefaultNetwork == prevNetType) { + mActiveDefaultNetwork = -1; + } + + int newType = -1; + int newPriority = -1; + for (int checkType=0; checkType <= + ConnectivityManager.MAX_NETWORK_TYPE; checkType++) { + if (checkType == prevNetType) { + continue; + } + if (mNetAttributes[checkType].isDefault()) { + /* TODO - if we have multiple nets we could use + * we may want to put more thought into which we choose + */ + if (checkType == mNetworkPreference) { + newType = checkType; + break; + } + if (mRadioAttributes[mNetAttributes[checkType].mRadio]. + mPriority > newPriority) { + newType = checkType; + newPriority = mRadioAttributes[mNetAttributes[newType]. + mRadio].mPriority; + } + } + } + + if (newType != -1) { + newNet = mNetTrackers[newType]; + /** + * See if the other network is available to fail over to. + * If is not available, we enable it anyway, so that it + * will be able to connect when it does become available, + * but we report a total loss of connectivity rather than + * report that we are attempting to fail over. + */ + if (newNet.isAvailable()) { + NetworkInfo switchTo = newNet.getNetworkInfo(); + switchTo.setFailover(true); + if (!switchTo.isConnectedOrConnecting()) { + newNet.reconnect(); + } + if (DBG) { + if (switchTo.isConnected()) { + Log.v(TAG, "Switching to already connected " + + switchTo.getTypeName()); + } else { + Log.v(TAG, "Attempting to switch to " + + switchTo.getTypeName()); + } + } + intent.putExtra(ConnectivityManager. + EXTRA_OTHER_NETWORK_INFO, switchTo); } else { - Log.v(TAG, "Attempting to switch to " + - switchTo.getTypeName()); + newNet.reconnect(); } + } else { + intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, + true); } - intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, - switchTo); - } else { - intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); } + + // do this before we broadcast the change + handleConnectivityChange(); + if (DBG) Log.v(TAG, "Sending DISCONNECT bcast for " + info.getTypeName() + - (switchTo == null ? "" : " other=" + switchTo.getTypeName())); + (newNet == null || !newNet.isAvailable() ? "" : " other=" + + newNet.getNetworkInfo().getTypeName())); mContext.sendStickyBroadcast(intent); /* * If the failover network is already connected, then immediately send * out a followup broadcast indicating successful failover */ - if (switchTo != null && otherNetworkConnected) - sendConnectedBroadcast(switchTo); + if (newNet != null && newNet.getNetworkInfo().isConnected()) + sendConnectedBroadcast(newNet.getNetworkInfo()); } private void sendConnectedBroadcast(NetworkInfo info) { @@ -506,93 +852,85 @@ public class ConnectivityService extends IConnectivityManager.Stub { */ private void handleConnectionFailure(NetworkInfo info) { mNetTrackers[info.getType()].setTeardownRequested(false); - if (getActiveNetworkInfo() == null) { - String reason = info.getReason(); - String extraInfo = info.getExtraInfo(); - if (DBG) { - String reasonText; - if (reason == null) { - reasonText = "."; - } else { - reasonText = " (" + reason + ")."; - } - Log.v(TAG, "Attempt to connect to " + info.getTypeName() + - " failed" + reasonText); + String reason = info.getReason(); + String extraInfo = info.getExtraInfo(); + + if (DBG) { + String reasonText; + if (reason == null) { + reasonText = "."; + } else { + reasonText = " (" + reason + ")."; } + Log.v(TAG, "Attempt to connect to " + info.getTypeName() + + " failed" + reasonText); + } - Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); - intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + intent.putExtra(ConnectivityManager.EXTRA_NETWORK_INFO, info); + if (getActiveNetworkInfo() == null) { intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true); - if (reason != null) { - intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); - } - if (extraInfo != null) { - intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, - extraInfo); - } - if (info.isFailover()) { - intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); - info.setFailover(false); - } - mContext.sendStickyBroadcast(intent); } + if (reason != null) { + intent.putExtra(ConnectivityManager.EXTRA_REASON, reason); + } + if (extraInfo != null) { + intent.putExtra(ConnectivityManager.EXTRA_EXTRA_INFO, extraInfo); + } + if (info.isFailover()) { + intent.putExtra(ConnectivityManager.EXTRA_IS_FAILOVER, true); + info.setFailover(false); + } + mContext.sendStickyBroadcast(intent); } private void handleConnect(NetworkInfo info) { - if (DBG) Log.v(TAG, "Handle CONNECT for " + info.getTypeName()); + if (DBG) Log.d(TAG, "Handle CONNECT for " + info.getTypeName()); + + int type = info.getType(); // snapshot isFailover, because sendConnectedBroadcast() resets it boolean isFailover = info.isFailover(); - NetworkStateTracker thisNet = mNetTrackers[info.getType()]; - NetworkStateTracker deadnet = null; - NetworkStateTracker otherNet; - if (info.getType() == ConnectivityManager.TYPE_MOBILE) { - otherNet = mWifiStateTracker; - } else /* info().getType() == TYPE_WIFI */ { - otherNet = mMobileDataStateTracker; - } - /* - * Check policy to see whether we are connected to a non-preferred - * network that now needs to be torn down. - */ - NetworkInfo wifiInfo = mWifiStateTracker.getNetworkInfo(); - NetworkInfo mobileInfo = mMobileDataStateTracker.getNetworkInfo(); - if (wifiInfo.isConnected() && mobileInfo.isConnected()) { - if (mNetworkPreference == ConnectivityManager.TYPE_WIFI) - deadnet = mMobileDataStateTracker; - else - deadnet = mWifiStateTracker; - } - - boolean toredown = false; - thisNet.setTeardownRequested(false); - if (!mTestMode && deadnet != null) { - if (DBG) Log.v(TAG, "Policy requires " + - deadnet.getNetworkInfo().getTypeName() + " teardown"); - toredown = teardown(deadnet); - if (DBG && !toredown) { - Log.d(TAG, "Network declined teardown request"); - } - } - - /* - * Note that if toredown is true, deadnet cannot be null, so there is - * no danger of a null pointer exception here.. - */ - if (!toredown || deadnet.getNetworkInfo().getType() != info.getType()) { - mActiveNetwork = thisNet; - if (DBG) Log.v(TAG, "Sending CONNECT bcast for " + - info.getTypeName()); - thisNet.updateNetworkSettings(); - sendConnectedBroadcast(info); - if (isFailover) { - otherNet.releaseWakeLock(); + NetworkStateTracker thisNet = mNetTrackers[type]; + + // if this is a default net and other default is running + // kill the one not preferred + if (mNetAttributes[type].isDefault()) { + if (DBG) Log.d(TAG, "connecting to a default network"); + if (mActiveDefaultNetwork != -1 && mActiveDefaultNetwork != type) { + if ((type != mNetworkPreference && + mNetAttributes[mActiveDefaultNetwork].mPriority > + mNetAttributes[type].mPriority) || + mNetworkPreference == mActiveDefaultNetwork) { + // don't accept this one + if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION " + + "to torn down network " + info.getTypeName()); + teardown(thisNet); + return; + } else { + // tear down the other + NetworkStateTracker otherNet = + mNetTrackers[mActiveDefaultNetwork]; + if (DBG) Log.v(TAG, "Policy requires " + + otherNet.getNetworkInfo().getTypeName() + + " teardown"); + if (!teardown(otherNet)) { + Log.e(TAG, "Network declined teardown request"); + return; + } + if (isFailover) { + otherNet.releaseWakeLock(); + } + } } - } else { - if (DBG) Log.v(TAG, "Not broadcasting CONNECT_ACTION to torn " + - "down network " + info.getTypeName()); + mActiveDefaultNetwork = type; } + thisNet.setTeardownRequested(false); + if (DBG) Log.d(TAG, "Sending CONNECT bcast for " + info.getTypeName()); + thisNet.updateNetworkSettings(); + handleConnectivityChange(); + sendConnectedBroadcast(info); } private void handleScanResultsAvailable(NetworkInfo info) { @@ -626,60 +964,148 @@ public class ConnectivityService extends IConnectivityManager.Stub { * table entries exist. */ private void handleConnectivityChange() { + if (DBG) Log.d(TAG, "handleConnectivityChange"); /* + * If a non-default network is enabled, add the host routes that + * will allow it's DNS servers to be accessed. Only * If both mobile and wifi are enabled, add the host routes that * will allow MMS traffic to pass on the mobile network. But * remove the default route for the mobile network, so that there * will be only one default route, to ensure that all traffic * except MMS will travel via Wi-Fi. */ - int numConnectedNets = handleConfigurationChange(); - if (numConnectedNets > 1) { - mMobileDataStateTracker.addPrivateRoutes(); - mMobileDataStateTracker.removeDefaultRoute(); - } else if (mMobileDataStateTracker.getNetworkInfo().isConnected()) { - mMobileDataStateTracker.removePrivateRoutes(); - mMobileDataStateTracker.restoreDefaultRoute(); + handleDnsConfigurationChange(); + + for (int netType : mPriorityList) { + if (mNetTrackers[netType].getNetworkInfo().isConnected()) { + if (mNetAttributes[netType].isDefault()) { + mNetTrackers[netType].addDefaultRoute(); + } else { + mNetTrackers[netType].addPrivateDnsRoutes(); + } + } else { + if (mNetAttributes[netType].isDefault()) { + mNetTrackers[netType].removeDefaultRoute(); + } else { + mNetTrackers[netType].removePrivateDnsRoutes(); + } + } } } - private int handleConfigurationChange() { + /** + * 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) Log.d(TAG, "reassessPidDns for pid " + myPid); + for(int i : mPriorityList) { + if (mNetAttributes[i].isDefault()) { + continue; + } + NetworkStateTracker nt = mNetTrackers[i]; + if (nt.getNetworkInfo().isConnected() && + !nt.isTeardownRequested()) { + 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); + if (doBump) { + bumpDns(); + } + return; + } + } + } + } + // nothing found - delete + for (int i = 1; ; i++) { + String prop = "net.dns" + i + "." + myPid; + if (SystemProperties.get(prop).length() == 0) { + if (doBump) { + bumpDns(); + } + return; + } + SystemProperties.set(prop, ""); + } + } + + private void writePidDns(String[] dnsList, 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); + } + } + } + + private void bumpDns() { /* - * Set DNS properties. Always put Wi-Fi entries at the front of - * the list if it is active. + * Bump the property that tells the name resolver library to reread + * the DNS server list from the properties. */ - int index = 1; - String lastDns = ""; - int numConnectedNets = 0; - int incrValue = ConnectivityManager.TYPE_MOBILE - - ConnectivityManager.TYPE_WIFI; - int stopValue = ConnectivityManager.TYPE_MOBILE + incrValue; + String propVal = SystemProperties.get("net.dnschange"); + int n = 0; + if (propVal.length() != 0) { + try { + n = Integer.parseInt(propVal); + } catch (NumberFormatException e) {} + } + SystemProperties.set("net.dnschange", "" + (n+1)); + } - for (int netType = ConnectivityManager.TYPE_WIFI; netType != stopValue; - netType += incrValue) { + private void handleDnsConfigurationChange() { + if (DBG) Log.d(TAG, "handleDnsConfig Change"); + // add default net's dns entries + for (int x = mPriorityList.length-1; x>= 0; x--) { + int netType = mPriorityList[x]; NetworkStateTracker nt = mNetTrackers[netType]; - if (nt.getNetworkInfo().isConnected() && + if (DBG) Log.d(TAG, " checking " + nt); + if (nt != null && nt.getNetworkInfo().isConnected() && !nt.isTeardownRequested()) { - ++numConnectedNets; + if (DBG) Log.d(TAG, " connected"); String[] dnsList = nt.getNameServers(); - for (int i = 0; i < dnsList.length && dnsList[i] != null; i++) { - // skip duplicate entries - if (!dnsList[i].equals(lastDns)) { - SystemProperties.set("net.dns" + index++, dnsList[i]); - lastDns = dnsList[i]; + if (mNetAttributes[netType].isDefault()) { + int j = 1; + for (String dns : dnsList) { + if (dns != null && !TextUtils.equals(dns, "0.0.0.0")) { + SystemProperties.set("net.dns" + j++, dns); + } + } + for (int k=j ; k<mNumDnsEntries; k++) { + SystemProperties.set("net.dns" + j, ""); + } + mNumDnsEntries = j; + } else { + // set per-pid dns for attached secondary nets + List pids = mNetRequestersPids[netType]; + for (int y=0; y< pids.size(); y++) { + Integer pid = (Integer)pids.get(y); + writePidDns(dnsList, pid.intValue()); } } } } - // Null out any DNS properties that are no longer used - for (int i = index; i <= mNumDnsEntries; i++) { - SystemProperties.set("net.dns" + i, ""); + + bumpDns(); + } + + private int getRestoreDefaultNetworkDelay() { + String restoreDefaultNetworkDelayStr = SystemProperties.get( + NETWORK_RESTORE_DELAY_PROP_NAME); + if(restoreDefaultNetworkDelayStr != null && + restoreDefaultNetworkDelayStr.length() != 0) { + try { + return Integer.valueOf(restoreDefaultNetworkDelayStr); + } catch (NumberFormatException e) { + } } - mNumDnsEntries = index - 1; - // Notify the name resolver library of the change - SystemProperties.set("net.dnschange", - String.valueOf(sDnsChangeCounter++)); - return numConnectedNets; + return RESTORE_DEFAULT_NETWORK_DELAY; } @Override @@ -692,20 +1118,19 @@ public class ConnectivityService extends IConnectivityManager.Stub { Binder.getCallingUid()); return; } - if (mActiveNetwork == null) { - pw.println("No active network"); - } else { - pw.println("Active network: " + - mActiveNetwork.getNetworkInfo().getTypeName()); - } pw.println(); for (NetworkStateTracker nst : mNetTrackers) { + if (nst.getNetworkInfo().isConnected()) { + pw.println("Active network: " + nst.getNetworkInfo(). + getTypeName()); + } pw.println(nst.getNetworkInfo()); pw.println(nst); pw.println(); } } + // must be stateless - things change under us. private class MyHandler extends Handler { @Override public void handleMessage(Message msg) { @@ -713,7 +1138,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { switch (msg.what) { case NetworkStateTracker.EVENT_STATE_CHANGED: info = (NetworkInfo) msg.obj; - if (DBG) Log.v(TAG, "ConnectivityChange for " + + if (DBG) Log.d(TAG, "ConnectivityChange for " + info.getTypeName() + ": " + info.getState() + "/" + info.getDetailedState()); @@ -748,7 +1173,6 @@ public class ConnectivityService extends IConnectivityManager.Stub { } else if (info.getState() == NetworkInfo.State.CONNECTED) { handleConnect(info); } - handleConnectivityChange(); break; case NetworkStateTracker.EVENT_SCAN_RESULTS_AVAILABLE: @@ -761,7 +1185,7 @@ public class ConnectivityService extends IConnectivityManager.Stub { (Notification) msg.obj); case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: - handleConfigurationChange(); + handleDnsConfigurationChange(); break; case NetworkStateTracker.EVENT_ROAMING_CHANGED: @@ -771,6 +1195,15 @@ public class ConnectivityService extends IConnectivityManager.Stub { case NetworkStateTracker.EVENT_NETWORK_SUBTYPE_CHANGED: // fill me in break; + case NetworkStateTracker.EVENT_RESTORE_DEFAULT_NETWORK: + for (NetworkStateTracker net : mNetTrackers) { + NetworkInfo i = net.getNetworkInfo(); + if (i.isConnected() && + !mNetAttributes[i.getType()].isDefault()) { + teardown(net); + } + } + break; } } } diff --git a/services/java/com/android/server/TelephonyRegistry.java b/services/java/com/android/server/TelephonyRegistry.java index 9f2856c..7379b5d 100644 --- a/services/java/com/android/server/TelephonyRegistry.java +++ b/services/java/com/android/server/TelephonyRegistry.java @@ -88,6 +88,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private String mDataConnectionApn = ""; + private String[] mDataConnectionApnTypes = null; + private String mDataConnectionInterfaceName = ""; private Bundle mCellLocation = new Bundle(); @@ -337,7 +339,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } public void notifyDataConnection(int state, boolean isDataConnectivityPossible, - String reason, String apn, String interfaceName) { + String reason, String apn, String[] apnTypes, String interfaceName) { if (!checkNotifyPermission("notifyDataConnection()" )) { return; } @@ -346,6 +348,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataConnectionPossible = isDataConnectivityPossible; mDataConnectionReason = reason; mDataConnectionApn = apn; + mDataConnectionApnTypes = apnTypes; mDataConnectionInterfaceName = interfaceName; for (int i = mRecords.size() - 1; i >= 0; i--) { Record r = mRecords.get(i); @@ -359,7 +362,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn, - interfaceName); + apnTypes, interfaceName); } public void notifyDataConnectionFailed(String reason) { @@ -517,8 +520,9 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mContext.sendBroadcast(intent, android.Manifest.permission.READ_PHONE_STATE); } - private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible, - String reason, String apn, String interfaceName) { + private void broadcastDataConnectionStateChanged(int state, + boolean isDataConnectivityPossible, + String reason, String apn, String[] apnTypes, String interfaceName) { // Note: not reporting to the battery stats service here, because the // status bar takes care of that after taking into account all of the // required info. @@ -531,6 +535,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, reason); } intent.putExtra(Phone.DATA_APN_KEY, apn); + String types = apnTypes[0]; + for (int i = 1; i < apnTypes.length; i++) { + types = types+","+apnTypes[i]; + } + intent.putExtra(Phone.DATA_APN_TYPES_KEY, types); intent.putExtra(Phone.DATA_IFACE_NAME_KEY, interfaceName); mContext.sendStickyBroadcast(intent); } diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java index d458911..66868a3 100755..100644 --- a/services/java/com/android/server/am/UsageStatsService.java +++ b/services/java/com/android/server/am/UsageStatsService.java @@ -695,7 +695,14 @@ public final class UsageStatsService extends IUsageStats.Stub { if (NC > 0) { for (Map.Entry<String, TimeStats> ent : pus.mLaunchTimes.entrySet()) { sb.append("A:"); - sb.append(ent.getKey()); + String activity = ent.getKey(); + if (activity.startsWith(pkgName)) { + sb.append('*'); + sb.append(activity.substring( + pkgName.length(), activity.length())); + } else { + sb.append(activity); + } TimeStats times = ent.getValue(); sb.append(','); sb.append(times.count); diff --git a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java index d6151c6..00d7c72 100644 --- a/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java +++ b/telephony/java/com/android/internal/telephony/DefaultPhoneNotifier.java @@ -94,8 +94,11 @@ public class DefaultPhoneNotifier implements PhoneNotifier { public void notifyDataConnection(Phone sender, String reason) { try { - mRegistry.notifyDataConnection(convertDataState(sender.getDataConnectionState()), - sender.isDataConnectivityPossible(), reason, sender.getActiveApn(), + mRegistry.notifyDataConnection( + convertDataState(sender.getDataConnectionState()), + sender.isDataConnectivityPossible(), reason, + sender.getActiveApn(), + sender.getActiveApnTypes(), sender.getInterfaceName(null)); } catch (RemoteException ex) { // system process is dead diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 865c6ca..6b42e6b 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -32,7 +32,7 @@ interface ITelephonyRegistry { void notifyCallForwardingChanged(boolean cfi); void notifyDataActivity(int state); void notifyDataConnection(int state, boolean isDataConnectivityPossible, - String reason, String apn, String interfaceName); + String reason, String apn, in String[] apnTypes, String interfaceName); void notifyDataConnectionFailed(String reason); void notifyCellLocation(in Bundle cellLocation); } diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java index 86ea12b..622b47d 100644 --- a/telephony/java/com/android/internal/telephony/Phone.java +++ b/telephony/java/com/android/internal/telephony/Phone.java @@ -99,8 +99,9 @@ public interface Phone { static final String PHONE_NAME_KEY = "phoneName"; static final String FAILURE_REASON_KEY = "reason"; static final String STATE_CHANGE_REASON_KEY = "reason"; - static final String DATA_APN_TYPE_KEY = "apnType"; + static final String DATA_APN_TYPES_KEY = "apnType"; static final String DATA_APN_KEY = "apn"; + static final String DATA_IFACE_NAME_KEY = "iface"; static final String NETWORK_UNAVAILABLE_KEY = "networkUnvailable"; static final String PHONE_IN_ECM_STATE = "phoneinECMState"; @@ -120,10 +121,16 @@ public interface Phone { static final String APN_TYPE_MMS = "mms"; /** APN type for SUPL assisted GPS */ static final String APN_TYPE_SUPL = "supl"; + /** APN type for DUN traffic */ + static final String APN_TYPE_DUN = "dun"; + /** APN type for HiPri traffic */ + static final String APN_TYPE_HIPRI = "hipri"; // "Features" accessible through the connectivity manager static final String FEATURE_ENABLE_MMS = "enableMMS"; static final String FEATURE_ENABLE_SUPL = "enableSUPL"; + static final String FEATURE_ENABLE_DUN = "enableDUN"; + static final String FEATURE_ENABLE_HIPRI = "enableHIPRI"; /** * Return codes for <code>enableApnType()</code> diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java index 3ca39de..dc6f92d 100644 --- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java +++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java @@ -72,7 +72,10 @@ public class ApnSetting { boolean canHandleType(String type) { for (String t : types) { - if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL)) { + // DEFAULT handles all, and HIPRI is handled by DEFAULT + if (t.equals(type) || t.equals(Phone.APN_TYPE_ALL) || + (t.equals(Phone.APN_TYPE_DEFAULT) && + type.equals(Phone.APN_TYPE_HIPRI))) { return true; } } diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java index 8b3529f..bf60bfe 100644 --- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java +++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java @@ -135,12 +135,16 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { /** Currently active PdpConnection */ private PdpConnection mActivePdp; + private static int APN_INVALID_ID = -1; private static int APN_DEFAULT_ID = 0; private static int APN_MMS_ID = 1; private static int APN_SUPL_ID = 2; - private static int APN_NUM_TYPES = 3; + private static int APN_DUN_ID = 3; + private static int APN_HIPRI_ID = 4; + private static int APN_NUM_TYPES = 5; private boolean[] dataEnabled = new boolean[APN_NUM_TYPES]; + private int enabledCount = 0; /** Is packet service restricted by network */ private boolean mIsPsRestricted = false; @@ -213,7 +217,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { GsmDataConnectionTracker(GSMPhone p) { super(p); mGsmPhone = p; - p.mCM.registerForAvailable (this, EVENT_RADIO_AVAILABLE, null); p.mCM.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null); p.mSIMRecords.registerForRecordsLoaded(this, EVENT_RECORDS_LOADED, null); @@ -252,6 +255,9 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { // and 2) whether the RIL will setup the baseband to auto-PS attach. SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(phone.getContext()); dataEnabled[APN_DEFAULT_ID] = !sp.getBoolean(GSMPhone.DATA_DISABLED_ON_BOOT_KEY, false); + if (dataEnabled[APN_DEFAULT_ID]) { + enabledCount++; + } noAutoAttach = !dataEnabled[APN_DEFAULT_ID]; if (!mRetryMgr.configure(SystemProperties.get("ro.gsm.data_retry_config"))) { @@ -332,6 +338,22 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return result; } + protected int apnTypeToId(String type) { + if (TextUtils.equals(type, Phone.APN_TYPE_DEFAULT)) { + return APN_DEFAULT_ID; + } else if (TextUtils.equals(type, Phone.APN_TYPE_MMS)) { + return APN_MMS_ID; + } else if (TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { + return APN_SUPL_ID; + } else if (TextUtils.equals(type, Phone.APN_TYPE_DUN)) { + return APN_DUN_ID; + } else if (TextUtils.equals(type, Phone.APN_TYPE_HIPRI)) { + return APN_HIPRI_ID; + } else { + return APN_INVALID_ID; + } + } + /** * Ensure that we are connected to an APN of the specified type. * @param type the APN type (currently the only valid values @@ -343,25 +365,15 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * the APN has been established. */ protected int enableApnType(String type) { - if (!TextUtils.equals(type, Phone.APN_TYPE_MMS) && - !TextUtils.equals(type, Phone.APN_TYPE_SUPL)) { + int id = apnTypeToId(type); + if (id == APN_INVALID_ID) { return Phone.APN_REQUEST_FAILED; } // If already active, return - Log.d(LOG_TAG, "enableApnType("+type+")"); + if(DBG) Log.d(LOG_TAG, "enableApnType("+type+"), isApnTypeActive = " + + isApnTypeActive(type) + " and state = " + state); if (isApnTypeActive(type)) { - setEnabled(type, true); - removeMessages(EVENT_RESTORE_DEFAULT_APN); - /** - * We're being asked to enable a non-default APN that's already in use. - * This means we should restart the timer that will automatically - * switch back to the default APN and disable the non-default APN - * when it expires. - */ - sendMessageDelayed( - obtainMessage(EVENT_RESTORE_DEFAULT_APN), - getRestoreDefaultApnDelay()); if (state == State.INITING) return Phone.APN_REQUEST_STARTED; else if (state == State.CONNECTED) return Phone.APN_ALREADY_ACTIVE; } @@ -370,7 +382,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return Phone.APN_TYPE_NOT_AVAILABLE; } - setEnabled(type, true); + setEnabled(id, true); mRequestedApnType = type; sendMessage(obtainMessage(EVENT_ENABLE_NEW_APN)); return Phone.APN_REQUEST_STARTED; @@ -385,31 +397,21 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * @return */ protected int disableApnType(String type) { - Log.d(LOG_TAG, "disableApnType("+type+")"); - if ((TextUtils.equals(type, Phone.APN_TYPE_MMS) || - TextUtils.equals(type, Phone.APN_TYPE_SUPL)) - && isEnabled(type)) { - removeMessages(EVENT_RESTORE_DEFAULT_APN); - setEnabled(type, false); + if (DBG) Log.d(LOG_TAG, "disableApnType("+type+")"); + int id = apnTypeToId(type); + if (id == APN_INVALID_ID) { + return Phone.APN_REQUEST_FAILED; + } + if (isEnabled(id)) { + setEnabled(id, false); if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { mRequestedApnType = Phone.APN_TYPE_DEFAULT; if (dataEnabled[APN_DEFAULT_ID]) { return Phone.APN_ALREADY_ACTIVE; } else { - Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); - msg.arg1 = 1; // tearDown is true; - msg.obj = Phone.REASON_DATA_DISABLED; - sendMessage(msg); return Phone.APN_REQUEST_STARTED; } } else { - /* - * Note that if default data is disabled, the following - * has the effect of disabling the MMS APN, and then - * ignoring the request to enable the default APN. - * The net result is that data is completely disabled. - */ - sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN)); return Phone.APN_REQUEST_STARTED; } } else { @@ -455,30 +457,30 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { return false; } - private boolean isEnabled(String apnType) { - if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) { - return dataEnabled[APN_DEFAULT_ID]; - } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) { - return dataEnabled[APN_MMS_ID]; - } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) { - return dataEnabled[APN_SUPL_ID]; - } else { - return false; + private boolean isEnabled(int id) { + if (id != APN_INVALID_ID) { + return dataEnabled[id]; } + return false; } - private void setEnabled(String apnType, boolean enable) { - Log.d(LOG_TAG, "setEnabled(" + apnType + ", " + enable + ')'); - if (TextUtils.equals(apnType, Phone.APN_TYPE_DEFAULT)) { - dataEnabled[APN_DEFAULT_ID] = enable; - } else if (TextUtils.equals(apnType, Phone.APN_TYPE_MMS)) { - dataEnabled[APN_MMS_ID] = enable; - } else if (TextUtils.equals(apnType, Phone.APN_TYPE_SUPL)) { - dataEnabled[APN_SUPL_ID] = enable; + private void setEnabled(int id, boolean enable) { + if (DBG) Log.d(LOG_TAG, "setEnabled(" + id + ", " + enable + ')'); + if (dataEnabled[id] != enable) { + dataEnabled[id] = enable; + + if (enable) { + enabledCount++; + } else { + enabledCount--; + } + + if (enabledCount == 0) { + setPrivateDataEnabled(false); + } else if (enabledCount == 1) { + setPrivateDataEnabled(true); + } } - Log.d(LOG_TAG, "dataEnabled[DEFAULT_APN]=" + dataEnabled[APN_DEFAULT_ID] + - " dataEnabled[MMS_APN]=" + dataEnabled[APN_MMS_ID] + - " dataEnabled[SUPL_APN]=" + dataEnabled[APN_SUPL_ID]); } /** @@ -493,30 +495,20 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * @return {@code true} if the operation succeeded */ public boolean setDataEnabled(boolean enable) { - boolean isEnabled = isEnabled(Phone.APN_TYPE_DEFAULT); - Log.d(LOG_TAG, "setDataEnabled("+enable+") isEnabled=" + isEnabled); - if (!isEnabled && enable) { - setEnabled(Phone.APN_TYPE_DEFAULT, true); - // trySetupData() will be a no-op if we are currently - // connected to the MMS APN + if (DBG) Log.d(LOG_TAG, "setDataEnabled("+enable+")"); + setEnabled(APN_DEFAULT_ID, enable); + return true; + } + + private void setPrivateDataEnabled(boolean enable) { + if (DBG) Log.d(LOG_TAG, "setPrivateDataEnabled("+enable+")"); + if (enable) { sendMessage(obtainMessage(EVENT_TRY_SETUP_DATA)); - return true; - } else if (!enable) { - setEnabled(Phone.APN_TYPE_DEFAULT, false); - // Don't tear down if there is an active APN and it handles MMS or SUPL. - // TODO: This isn't very general. - if ((isApnTypeActive(Phone.APN_TYPE_MMS) && isEnabled(Phone.APN_TYPE_MMS)) || - (isApnTypeActive(Phone.APN_TYPE_SUPL) && isEnabled(Phone.APN_TYPE_SUPL))) { - return false; - } + } else { Message msg = obtainMessage(EVENT_CLEAN_UP_CONNECTION); msg.arg1 = 1; // tearDown is true msg.obj = Phone.REASON_DATA_DISABLED; sendMessage(msg); - return true; - } else { - // isEnabled && enable - return true; } } @@ -536,7 +528,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { * {@code true} otherwise. */ public boolean getAnyDataEnabled() { - return dataEnabled[APN_DEFAULT_ID] || dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]; + return (enabledCount != 0); } /** @@ -618,7 +610,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } if (DBG) { - log ("Setup watingApns : " + apnListToString(waitingApns)); + log ("Setup waitngApns : " + apnListToString(waitingApns)); } return setupData(reason); } else { @@ -629,6 +621,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { " sim=" + mGsmPhone.mSIMRecords.getRecordsLoaded() + " UMTS=" + mGsmPhone.mSST.isConcurrentVoiceAndData() + " phoneState=" + phone.getState() + + " isDataAllowed=" + isDataAllowed() + " dataEnabled=" + getAnyDataEnabled() + " roaming=" + roaming + " dataOnRoamingEnable=" + getDataOnRoamingEnabled() + @@ -1251,15 +1244,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { trySetupData(reason); } - protected void onRestoreDefaultApn() { - if (DBG) Log.d(LOG_TAG, "Restore default APN"); - setEnabled(Phone.APN_TYPE_MMS, false); - mRequestedApnType = Phone.APN_TYPE_DEFAULT; - if (!isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { - cleanUpConnection(true, Phone.REASON_RESTORE_DEFAULT_APN); - } - } - protected void onRoamingOff() { trySetupData(Phone.REASON_ROAMING_OFF); } @@ -1313,22 +1297,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { if (ar.exception == null) { // everything is setup - - /* - * We may have switched away from the default PDP context - * in order to enable a "special" APN (e.g., for MMS - * traffic). Set a timer to switch back and/or disable the - * special APN, so that a negligient application doesn't - * permanently prevent data connectivity. What we are - * protecting against here is not malicious apps, but - * rather an app that inadvertantly fails to reset to the - * default APN, or that dies before doing so. - */ - if (dataEnabled[APN_MMS_ID] || dataEnabled[APN_SUPL_ID]) { - removeMessages(EVENT_RESTORE_DEFAULT_APN); - sendMessageDelayed(obtainMessage(EVENT_RESTORE_DEFAULT_APN), - getRestoreDefaultApnDelay()); - } if (isApnTypeActive(Phone.APN_TYPE_DEFAULT)) { SystemProperties.set("gsm.defaultpdpcontext.active", "true"); if (canSetPreferApn && preferredApn == null) { @@ -1432,18 +1400,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { cleanUpConnection(tearDown, reason); } - private int getRestoreDefaultApnDelay() { - String restoreApnDelayStr = SystemProperties.get(APN_RESTORE_DELAY_PROP_NAME); - - if (restoreApnDelayStr != null && restoreApnDelayStr.length() != 0) { - try { - return Integer.valueOf(restoreApnDelayStr); - } catch (NumberFormatException e) { - } - } - return RESTORE_DEFAULT_APN_DELAY; - } - /** * Based on the sim operator numeric, create a list for all possible pdps * with all apns associated with that pdp @@ -1568,10 +1524,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { private void startDelayedRetry(PdpConnection.FailCause cause, String reason) { notifyNoData(cause); - if (mRequestedApnType != Phone.APN_TYPE_DEFAULT) { - sendMessage(obtainMessage(EVENT_RESTORE_DEFAULT_APN)); - } - else { + if (mRequestedApnType == Phone.APN_TYPE_DEFAULT) { reconnectAfterFail(cause, reason); } } @@ -1626,7 +1579,7 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { } public void handleMessage (Message msg) { - + if (DBG) Log.d(LOG_TAG,"GSMDataConnTrack handleMessage "+msg); switch (msg.what) { case EVENT_RECORDS_LOADED: onRecordsLoaded(); @@ -1636,10 +1589,6 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker { onEnableNewApn(); break; - case EVENT_RESTORE_DEFAULT_APN: - onRestoreDefaultApn(); - break; - case EVENT_GPRS_DETACHED: onGprsDetached(); break; diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java index 7e80370..e060388 100644 --- a/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java +++ b/tests/DumpRenderTree/src/com/android/dumprendertree/TestShellActivity.java @@ -112,6 +112,11 @@ public class TestShellActivity extends Activity implements LayoutTestController mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL); + // Expose window.gc function to JavaScript. JSC build exposes + // this function by default, but V8 requires the flag to turn it on. + // WebView::setJsFlags is noop in JSC build. + mWebView.setJsFlags("--expose_gc"); + mHandler = new AsyncHandler(); Intent intent = getIntent(); diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp index 41ee88b..9d2ed10 100644 --- a/tools/aapt/Resource.cpp +++ b/tools/aapt/Resource.cpp @@ -475,10 +475,8 @@ static bool applyFileOverlay(const sp<AaptAssets>& assets, } } else { // this group doesn't exist (a file that's only in the overlay) - fprintf(stderr, "aapt: error: " - "*** Resource file '%s' exists only in an overlay\n", - overlaySet->keyAt(overlayIndex).string()); - return false; + baseSet->add(overlaySet->keyAt(overlayIndex), + overlaySet->valueAt(overlayIndex)); } } // this overlay didn't have resources for this type diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp index 8dbc12e..95a2384 100644 --- a/tools/aapt/ResourceTable.cpp +++ b/tools/aapt/ResourceTable.cpp @@ -663,6 +663,7 @@ status_t compileResourceFile(Bundle* bundle, const String16 public16("public"); const String16 public_padding16("public-padding"); const String16 private_symbols16("private-symbols"); + const String16 add_resource16("add-resource"); const String16 skip16("skip"); const String16 eat_comment16("eat-comment"); @@ -960,6 +961,36 @@ status_t compileResourceFile(Bundle* bundle, } continue; + } else if (strcmp16(block.getElementName(&len), add_resource16.string()) == 0) { + SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); + + String16 typeName; + ssize_t typeIdx = block.indexOfAttribute(NULL, "type"); + if (typeIdx < 0) { + srcPos.error("A 'type' attribute is required for <add-resource>\n"); + hasErrors = localHasErrors = true; + } + typeName = String16(block.getAttributeStringValue(typeIdx, &len)); + + String16 name; + ssize_t nameIdx = block.indexOfAttribute(NULL, "name"); + if (nameIdx < 0) { + srcPos.error("A 'name' attribute is required for <add-resource>\n"); + hasErrors = localHasErrors = true; + } + name = String16(block.getAttributeStringValue(nameIdx, &len)); + + outTable->canAddEntry(srcPos, myPackage, typeName, name); + + while ((code=block.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) { + if (code == ResXMLTree::END_TAG) { + if (strcmp16(block.getElementName(&len), private_symbols16.string()) == 0) { + break; + } + } + } + continue; + } else if (strcmp16(block.getElementName(&len), declare_styleable16.string()) == 0) { SourcePos srcPos(in->getPrintableSource(), block.getLineNumber()); @@ -1557,9 +1588,21 @@ status_t ResourceTable::startBag(const SourcePos& sourcePos, } #endif if (overlay && !hasBagOrEntry(package, type, name)) { - sourcePos.error("Can't add new bags in an overlay. See '%s'\n", - String8(name).string()); - return UNKNOWN_ERROR; + bool canAdd = false; + sp<Package> p = mPackages.valueFor(package); + if (p != NULL) { + sp<Type> t = p->getTypes().valueFor(type); + if (t != NULL) { + if (t->getCanAddEntries().indexOf(name) >= 0) { + canAdd = true; + } + } + } + if (!canAdd) { + sourcePos.error("Resource does not already exist in overlay at '%s'; use <add-resource> to add.\n", + String8(name).string()); + return UNKNOWN_ERROR; + } } sp<Entry> e = getEntry(package, type, name, sourcePos, overlay, params); if (e == NULL) { @@ -1724,6 +1767,15 @@ bool ResourceTable::appendTypeComment(const String16& package, return false; } +void ResourceTable::canAddEntry(const SourcePos& pos, + const String16& package, const String16& type, const String16& name) +{ + sp<Type> t = getType(package, type, pos); + if (t != NULL) { + t->canAddEntry(name); + } +} + size_t ResourceTable::size() const { return mPackages.size(); } @@ -3215,6 +3267,11 @@ status_t ResourceTable::Type::addPublic(const SourcePos& sourcePos, return NO_ERROR; } +void ResourceTable::Type::canAddEntry(const String16& name) +{ + mCanAddEntries.add(name); +} + sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry, const SourcePos& sourcePos, const ResTable_config* config, @@ -3224,9 +3281,10 @@ sp<ResourceTable::Entry> ResourceTable::Type::getEntry(const String16& entry, int pos = -1; sp<ConfigList> c = mConfigs.valueFor(entry); if (c == NULL) { - if (overlay == true) { - sourcePos.error("Resource %s appears in overlay but not" - " in the base package.\n", String8(entry).string()); + if (overlay == true && mCanAddEntries.indexOf(entry) < 0) { + sourcePos.error("Resource at %s appears in overlay but not" + " in the base package; use <add-resource> to add.\n", + String8(entry).string()); return NULL; } c = new ConfigList(entry, sourcePos); diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h index ec4331a..caa01b3 100644 --- a/tools/aapt/ResourceTable.h +++ b/tools/aapt/ResourceTable.h @@ -132,6 +132,9 @@ public: const String16& name, const String16& comment); + void canAddEntry(const SourcePos& pos, + const String16& package, const String16& type, const String16& name); + size_t size() const; size_t numLocalResources() const; bool hasResources() const; @@ -413,7 +416,9 @@ public: status_t addPublic(const SourcePos& pos, const String16& name, const uint32_t ident); - + + void canAddEntry(const String16& name); + String16 getName() const { return mName; } sp<Entry> getEntry(const String16& entry, const SourcePos& pos, @@ -435,6 +440,8 @@ public: const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; } const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; } + const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; } + const SourcePos& getPos() const { return mPos; } private: String16 mName; @@ -443,6 +450,7 @@ public: SortedVector<ConfigDescription> mUniqueConfigs; DefaultKeyedVector<String16, sp<ConfigList> > mConfigs; Vector<sp<ConfigList> > mOrderedConfigs; + SortedVector<String16> mCanAddEntries; int32_t mPublicIndex; int32_t mIndex; SourcePos mPos; |