diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 4fe418a07c..4215f207ea 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -100,7 +100,7 @@ public class ConnectivityManager { /** * Identical to {@link #CONNECTIVITY_ACTION} broadcast, but sent without any - * historic {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}. + * applicable {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY}. * * @hide */ @@ -427,6 +427,18 @@ public class ConnectivityManager { @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI; + /** + * Default value for {@link Settings.Global#CONNECTIVITY_CHANGE_DELAY} in + * milliseconds. This was introduced because IPv6 routes seem to take a + * moment to settle - trying network activity before the routes are adjusted + * can lead to packets using the wrong interface or having the wrong IP address. + * This delay is a bit crude, but in the future hopefully we will have kernel + * notifications letting us know when it's safe to use the new network. + * + * @hide + */ + public static final int CONNECTIVITY_CHANGE_DELAY_DEFAULT = 3000; + /** * @hide */ diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 0f1ed0af9f..348aa1bb5c 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -797,6 +797,17 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalStateException("No free netIds"); } + private int getConnectivityChangeDelay() { + final ContentResolver cr = mContext.getContentResolver(); + + /** Check system properties for the default value then use secure settings value, if any. */ + int defaultDelay = SystemProperties.getInt( + "conn." + Settings.Global.CONNECTIVITY_CHANGE_DELAY, + ConnectivityManager.CONNECTIVITY_CHANGE_DELAY_DEFAULT); + return Settings.Global.getInt(cr, Settings.Global.CONNECTIVITY_CHANGE_DELAY, + defaultDelay); + } + private boolean teardown(NetworkStateTracker netTracker) { if (netTracker.teardown()) { netTracker.setTeardownRequested(true); @@ -1468,6 +1479,11 @@ public class ConnectivityService extends IConnectivityManager.Stub sendGeneralBroadcast(info, CONNECTIVITY_ACTION); } + private void sendConnectedBroadcastDelayed(NetworkInfo info, int delayMs) { + sendGeneralBroadcast(info, CONNECTIVITY_ACTION_IMMEDIATE); + sendGeneralBroadcastDelayed(info, CONNECTIVITY_ACTION, delayMs); + } + private void sendInetConditionBroadcast(NetworkInfo info) { sendGeneralBroadcast(info, ConnectivityManager.INET_CONDITION_ACTION); } @@ -1499,6 +1515,10 @@ public class ConnectivityService extends IConnectivityManager.Stub sendStickyBroadcast(makeGeneralIntent(info, bcastType)); } + private void sendGeneralBroadcastDelayed(NetworkInfo info, String bcastType, int delayMs) { + sendStickyBroadcastDelayed(makeGeneralIntent(info, bcastType), delayMs); + } + private void sendDataActivityBroadcast(int deviceType, boolean active, long tsNanos) { Intent intent = new Intent(ConnectivityManager.ACTION_DATA_ACTIVITY_CHANGE); intent.putExtra(ConnectivityManager.EXTRA_DEVICE_TYPE, deviceType); @@ -1532,6 +1552,19 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void sendStickyBroadcastDelayed(Intent intent, int delayMs) { + if (delayMs <= 0) { + sendStickyBroadcast(intent); + } else { + if (VDBG) { + log("sendStickyBroadcastDelayed: delayMs=" + delayMs + ", action=" + + intent.getAction()); + } + mHandler.sendMessageDelayed(mHandler.obtainMessage( + EVENT_SEND_STICKY_BROADCAST_INTENT, intent), delayMs); + } + } + void systemReady() { // start network sampling .. Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED); @@ -4268,7 +4301,7 @@ public class ConnectivityService extends IConnectivityManager.Stub info.setType(type); if (connected) { info.setDetailedState(DetailedState.CONNECTED, null, info.getExtraInfo()); - sendConnectedBroadcast(info); + sendConnectedBroadcastDelayed(info, getConnectivityChangeDelay()); } else { info.setDetailedState(DetailedState.DISCONNECTED, null, info.getExtraInfo()); Intent intent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); @@ -4299,9 +4332,10 @@ public class ConnectivityService extends IConnectivityManager.Stub final Intent immediateIntent = new Intent(intent); immediateIntent.setAction(CONNECTIVITY_ACTION_IMMEDIATE); sendStickyBroadcast(immediateIntent); - sendStickyBroadcast(intent); + sendStickyBroadcastDelayed(intent, getConnectivityChangeDelay()); if (newDefaultAgent != null) { - sendConnectedBroadcast(newDefaultAgent.networkInfo); + sendConnectedBroadcastDelayed(newDefaultAgent.networkInfo, + getConnectivityChangeDelay()); } } }