summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apex/sdkextensions/framework/Android.bp58
-rw-r--r--api/module-lib-current.txt4
-rw-r--r--cmds/statsd/src/atoms.proto41
-rw-r--r--core/java/android/timezone/CountryTimeZones.java32
-rw-r--r--core/java/com/android/internal/util/ObjectUtils.java8
-rw-r--r--core/proto/android/server/connectivity/data_stall_event.proto6
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java125
-rw-r--r--services/core/java/com/android/server/connectivity/LingerMonitor.java29
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java34
9 files changed, 248 insertions, 89 deletions
diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp
index 245a96b99148..86f4ab7c1128 100644
--- a/apex/sdkextensions/framework/Android.bp
+++ b/apex/sdkextensions/framework/Android.bp
@@ -44,34 +44,68 @@ java_library {
],
}
+stubs_defaults {
+ name: "framework-sdkextensions-stubs-defaults",
+ srcs: [ ":framework-sdkextensions-sources" ],
+ libs: [ "framework-annotations-lib" ],
+ sdk_version: "system_current",
+}
+
droidstubs {
- name: "framework-sdkextensions-droidstubs-publicapi",
+ name: "framework-sdkextensions-stubs-srcs-publicapi",
defaults: [
- "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-publicapi",
+ "framework-sdkextensions-stubs-defaults",
]
}
droidstubs {
- name: "framework-sdkextensions-droidstubs-systemapi",
+ name: "framework-sdkextensions-stubs-srcs-systemapi",
defaults: [
- "framework-sdkextensions-stubs-defaults",
"framework-module-stubs-defaults-systemapi",
+ "framework-sdkextensions-stubs-defaults",
]
}
-stubs_defaults {
- name: "framework-sdkextensions-stubs-defaults",
- srcs: [
- ":framework-sdkextensions-sources",
- ":framework-annotations",
- ],
- sdk_version: "system_current",
+droidstubs {
+ name: "framework-sdkextensions-api-module_libs_api",
+ defaults: [
+ "framework-module-api-defaults-module_libs_api",
+ "framework-sdkextensions-stubs-defaults",
+ ]
+}
+
+droidstubs {
+ name: "framework-sdkextensions-stubs-srcs-module_libs_api",
+ defaults: [
+ "framework-module-stubs-defaults-module_libs_api",
+ "framework-sdkextensions-stubs-defaults",
+ ]
+}
+
+java_library {
+ name: "framework-sdkextensions-stubs-publicapi",
+ srcs: [":framework-sdkextensions-stubs-srcs-publicapi"],
+ sdk_version: "current",
+ visibility: [
+ "//frameworks/base", // Framework
+ "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
+ ]
}
java_library {
name: "framework-sdkextensions-stubs-systemapi",
- srcs: [":framework-sdkextensions-droidstubs-systemapi"],
+ srcs: [":framework-sdkextensions-stubs-srcs-systemapi"],
+ sdk_version: "system_current",
+ visibility: [
+ "//frameworks/base", // Framework
+ "//frameworks/base/apex/sdkextensions", // sdkextensions SDK
+ ]
+}
+
+java_library {
+ name: "framework-sdkextensions-stubs-module_libs_api",
+ srcs: [":framework-sdkextensions-stubs-srcs-module_libs_api"],
sdk_version: "system_current",
visibility: [
"//frameworks/base", // Framework
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 278a18654e03..8ba204c68460 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -87,8 +87,8 @@ package android.timezone {
method @NonNull public java.util.List<android.timezone.CountryTimeZones.TimeZoneMapping> getEffectiveTimeZoneMappingsAt(long);
method public boolean hasUtcZone(long);
method public boolean isDefaultTimeZoneBoosted();
- method public boolean isForCountryCode(@NonNull String);
method @Nullable public android.timezone.CountryTimeZones.OffsetResult lookupByOffsetWithBias(int, @Nullable Boolean, @Nullable Integer, long, @Nullable android.icu.util.TimeZone);
+ method public boolean matchesCountryCode(@NonNull String);
}
public static final class CountryTimeZones.OffsetResult {
@@ -98,7 +98,7 @@ package android.timezone {
}
public static final class CountryTimeZones.TimeZoneMapping {
- method @Nullable public android.icu.util.TimeZone getTimeZone();
+ method @NonNull public android.icu.util.TimeZone getTimeZone();
method @NonNull public String getTimeZoneId();
}
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index a8ad53c686bc..a50fefbd6500 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -352,6 +352,7 @@ message Atom {
PerfettoUploaded perfetto_uploaded =
229 [(log_from_module) = "perfetto"];
VmsClientConnectionStateChanged vms_client_connection_state_changed = 230;
+ UserspaceRebootReported userspace_reboot_reported = 243;
}
// Pulled events will start at field 10000.
@@ -7076,3 +7077,43 @@ message UpdateEngineSuccessfulUpdateReported {
// The number of reboot of the device during a successful update.
optional int32 reboot_count = 7;
}
+
+/*
+ * Logs userspace reboot outcome and duration.
+ *
+ * Logged from:
+ * frameworks/base/core/java/com/android/server/BootReceiver.java
+ */
+message UserspaceRebootReported {
+ // Possible outcomes of userspace reboot.
+ enum Outcome {
+ // Default value in case platform failed to determine the outcome.
+ OUTCOME_UNKNOWN = 0;
+ // Userspace reboot succeeded (i.e. boot completed without a fall back to hard reboot).
+ SUCCESS = 1;
+ // Userspace reboot shutdown sequence was aborted.
+ FAILED_SHUTDOWN_SEQUENCE_ABORTED = 2;
+ // Remounting userdata into checkpointing mode failed.
+ FAILED_USERDATA_REMOUNT = 3;
+ // Device didn't finish booting before timeout and userspace reboot watchdog issued a hard
+ // reboot.
+ FAILED_USERSPACE_REBOOT_WATCHDOG_TRIGGERED = 4;
+ }
+ // Outcome of userspace reboot. Always set.
+ optional Outcome outcome = 1;
+ // Duration of userspace reboot in case it has a successful outcome.
+ // Duration is measured as time between userspace reboot was initiated and until boot completed
+ // (e.g. sys.boot_completed=1).
+ optional int64 duration_millis = 2;
+ // State of primary user's (user0) credential encryption storage.
+ enum UserEncryptionState {
+ // Default value.
+ USER_ENCRYPTION_STATE_UNKNOWN = 0;
+ // Credential encrypted storage is unlocked.
+ UNLOCKED = 1;
+ // Credential encrypted storage is locked.
+ LOCKED = 2;
+ }
+ // State of primary user's encryption storage at the moment boot completed. Always set.
+ optional UserEncryptionState user_encryption_state = 3;
+}
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index 5875761bb1c9..970acd0a5b3f 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -51,8 +51,10 @@ public final class CountryTimeZones {
}
/**
- * Returns the ID for this mapping. See also {@link #getTimeZone()} which handles when the
- * ID is unrecognized.
+ * Returns the ID for this mapping. The ID is a tzdb time zone identifier like
+ * "America/Los_Angeles" that can be used with methods such as {@link
+ * TimeZone#getFrozenTimeZone(String)}. See {@link #getTimeZone()} which returns a frozen
+ * {@link TimeZone} object.
*/
@NonNull
public String getTimeZoneId() {
@@ -60,10 +62,9 @@ public final class CountryTimeZones {
}
/**
- * Returns a {@link TimeZone} object for this mapping, or {@code null} if the ID is
- * unrecognized.
+ * Returns a frozen {@link TimeZone} object for this mapping.
*/
- @Nullable
+ @NonNull
public TimeZone getTimeZone() {
return mDelegate.getTimeZone();
}
@@ -158,9 +159,10 @@ public final class CountryTimeZones {
}
/**
- * Returns true if the ISO code for the country is a match for the one specified.
+ * Returns true if the ISO code for the country is a case-insensitive match for the one
+ * supplied.
*/
- public boolean isForCountryCode(@NonNull String countryIso) {
+ public boolean matchesCountryCode(@NonNull String countryIso) {
return mDelegate.isForCountryCode(countryIso);
}
@@ -183,15 +185,25 @@ public final class CountryTimeZones {
}
/**
- * Qualifier for a country's default time zone. {@code true} indicates whether the default
- * would be a good choice <em>generally</em> when there's no other information available.
+ * Qualifier for a country's default time zone. {@code true} indicates that the country's
+ * default time zone would be a good choice <em>generally</em> when there's no UTC offset
+ * information available. This will only be {@code true} in countries with multiple zones where
+ * a large majority of the population is covered by only one of them.
*/
public boolean isDefaultTimeZoneBoosted() {
return mDelegate.isDefaultTimeZoneBoosted();
}
/**
- * Returns true if the country has at least one zone that is the same as UTC at the given time.
+ * Returns {@code true} if the country has at least one time zone that uses UTC at the given
+ * time. This is an efficient check when trying to validate received UTC offset information.
+ * For example, there are situations when a detected zero UTC offset cannot be distinguished
+ * from "no information available" or a corrupted signal. This method is useful because checking
+ * offset information for large countries is relatively expensive but it is generally only the
+ * countries close to the prime meridian that use UTC at <em>any</em> time of the year.
+ *
+ * @param whenMillis the time the offset information is for in milliseconds since the beginning
+ * of the Unix epoch
*/
public boolean hasUtcZone(long whenMillis) {
return mDelegate.hasUtcZone(whenMillis);
diff --git a/core/java/com/android/internal/util/ObjectUtils.java b/core/java/com/android/internal/util/ObjectUtils.java
index 59e5a6402fb8..a6b345fadbbe 100644
--- a/core/java/com/android/internal/util/ObjectUtils.java
+++ b/core/java/com/android/internal/util/ObjectUtils.java
@@ -36,4 +36,12 @@ public class ObjectUtils {
return (b != null) ? -1 : 0;
}
}
+
+ /**
+ * Returns its first argument if non-null, and the second otherwise.
+ */
+ @Nullable
+ public static <T> T getOrElse(@Nullable final T object, @Nullable final T otherwise) {
+ return null != object ? object : otherwise;
+ }
}
diff --git a/core/proto/android/server/connectivity/data_stall_event.proto b/core/proto/android/server/connectivity/data_stall_event.proto
index a82326f67d74..23fcf6ebc2cc 100644
--- a/core/proto/android/server/connectivity/data_stall_event.proto
+++ b/core/proto/android/server/connectivity/data_stall_event.proto
@@ -34,7 +34,7 @@ enum ApBand {
AP_BAND_5GHZ = 2;
}
-// Refer to definition in ServiceState.java.
+// Refer to definition in TelephonyManager.java.
enum RadioTech {
RADIO_TECHNOLOGY_UNKNOWN = 0;
RADIO_TECHNOLOGY_GPRS = 1;
@@ -49,8 +49,8 @@ enum RadioTech {
RADIO_TECHNOLOGY_HSUPA = 10;
RADIO_TECHNOLOGY_HSPA = 11;
RADIO_TECHNOLOGY_EVDO_B = 12;
- RADIO_TECHNOLOGY_EHRPD = 13;
- RADIO_TECHNOLOGY_LTE = 14;
+ RADIO_TECHNOLOGY_LTE = 13;
+ RADIO_TECHNOLOGY_EHRPD = 14;
RADIO_TECHNOLOGY_HSPAP = 15;
RADIO_TECHNOLOGY_GSM = 16;
RADIO_TECHNOLOGY_TD_SCDMA = 17;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 4b9925fe597b..0e17b23249ae 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -6197,12 +6197,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void sendUpdatedScoreToFactories(NetworkRequest networkRequest, NetworkAgentInfo nai) {
- int score = 0;
- int serial = 0;
+ private void sendUpdatedScoreToFactories(@NonNull NetworkRequest networkRequest,
+ @Nullable NetworkAgentInfo nai) {
+ final int score;
+ final int serial;
if (nai != null) {
score = nai.getCurrentScore();
serial = nai.factorySerialNumber;
+ } else {
+ score = 0;
+ serial = 0;
}
if (VDBG || DDBG){
log("sending new Min Network Score(" + score + "): " + networkRequest.toString());
@@ -6365,20 +6369,28 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- private void makeDefault(@NonNull final NetworkAgentInfo newNetwork) {
+ private void makeDefault(@Nullable final NetworkAgentInfo newNetwork) {
if (DBG) log("Switching to new default network: " + newNetwork);
+ mDefaultNetworkNai = newNetwork;
+
try {
- mNMS.setDefaultNetId(newNetwork.network.netId);
+ if (null != newNetwork) {
+ mNMS.setDefaultNetId(newNetwork.network.netId);
+ } else {
+ mNMS.clearDefaultNetId();
+ }
} catch (Exception e) {
loge("Exception setting default network :" + e);
}
- mDefaultNetworkNai = newNetwork;
notifyLockdownVpn(newNetwork);
- handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
- updateTcpBufferSizes(newNetwork.linkProperties.getTcpBufferSizes());
- mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+ handleApplyDefaultProxy(null != newNetwork
+ ? newNetwork.linkProperties.getHttpProxy() : null);
+ updateTcpBufferSizes(null != newNetwork
+ ? newNetwork.linkProperties.getTcpBufferSizes() : null);
+ mDnsManager.setDefaultDnsSystemProperties(null != newNetwork
+ ? newNetwork.linkProperties.getDnsServers() : Collections.EMPTY_LIST);
notifyIfacesChangedForNetworkStats();
// Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks.
updateAllVpnsCapabilities();
@@ -6457,6 +6469,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
void addRematchedNetwork(@NonNull final NetworkBgStatePair network) {
mRematchedNetworks.add(network);
}
+
+ // Will return null if this reassignment does not change the network assigned to
+ // the passed request.
+ @Nullable
+ private RequestReassignment getReassignment(@NonNull final NetworkRequestInfo nri) {
+ for (final RequestReassignment event : getRequestReassignments()) {
+ if (nri == event.mRequest) return event;
+ }
+ return null;
+ }
}
private ArrayMap<NetworkRequestInfo, NetworkAgentInfo> computeRequestReassignmentForNetwork(
@@ -6523,8 +6545,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
@NonNull final NetworkAgentInfo newNetwork, final long now) {
ensureRunningOnConnectivityServiceThread();
if (!newNetwork.everConnected) return;
- boolean isNewDefault = false;
- NetworkAgentInfo oldDefaultNetwork = null;
changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork,
newNetwork.isBackgroundNetwork()));
@@ -6541,6 +6561,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
final NetworkRequestInfo nri = entry.getKey();
final NetworkAgentInfo previousSatisfier = nri.mSatisfier;
final NetworkAgentInfo newSatisfier = entry.getValue();
+ changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
+ nri, previousSatisfier, newSatisfier));
if (newSatisfier != null) {
if (VDBG) log("rematch for " + newSatisfier.name());
if (previousSatisfier != null) {
@@ -6553,25 +6575,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (VDBG || DDBG) log(" accepting network in place of null");
}
newSatisfier.unlingerRequest(nri.request);
- nri.mSatisfier = newSatisfier;
if (!newSatisfier.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
}
- changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
- nri, previousSatisfier, newSatisfier));
- // Tell NetworkProviders about the new score, so they can stop
- // trying to connect if they know they cannot match it.
- // TODO - this could get expensive if we have a lot of requests for this
- // network. Think about if there is a way to reduce this. Push
- // netid->request mapping to each provider?
- sendUpdatedScoreToFactories(nri.request, newSatisfier);
- if (isDefaultRequest(nri)) {
- isNewDefault = true;
- oldDefaultNetwork = previousSatisfier;
- if (previousSatisfier != null) {
- mLingerMonitor.noteLingerDefaultNetwork(previousSatisfier, newSatisfier);
- }
- }
} else {
// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
// mark it as no longer satisfying "nri". Because networks are processed by
@@ -6585,35 +6591,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
" request " + nri.request.requestId);
}
newNetwork.removeRequest(nri.request.requestId);
- if (previousSatisfier == newNetwork) {
- nri.mSatisfier = null;
- if (isDefaultRequest(nri)) mDefaultNetworkNai = null;
- sendUpdatedScoreToFactories(nri.request, null);
- } else {
- Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
- newNetwork.name() +
- " without updating mSatisfier or providers!");
- }
- // TODO: Technically, sending CALLBACK_LOST here is
- // incorrect if there is a replacement network currently
- // connected that can satisfy nri, which is a request
- // (not a listen). However, the only capability that can both
- // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
- // so this code is only incorrect for a network that loses
- // the TRUSTED capability, which is a rare case.
- callCallbackForRequest(nri, newNetwork, ConnectivityManager.CALLBACK_LOST, 0);
}
- }
-
- if (isNewDefault) {
- updateDataActivityTracking(newNetwork, oldDefaultNetwork);
- // Notify system services that this network is up.
- makeDefault(newNetwork);
- // Log 0 -> X and Y -> X default network transitions, where X is the new default.
- mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
- now, newNetwork, oldDefaultNetwork);
- // Have a new default network, release the transition wakelock in
- scheduleReleaseNetworkTransitionWakelock();
+ nri.mSatisfier = newSatisfier;
}
}
@@ -6641,14 +6620,48 @@ public class ConnectivityService extends IConnectivityManager.Stub
rematchNetworkAndRequests(changes, nai, now);
}
- final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+ final NetworkRequestInfo defaultRequestInfo = mNetworkRequests.get(mDefaultRequest);
+ final NetworkReassignment.RequestReassignment reassignment =
+ changes.getReassignment(defaultRequestInfo);
+ final NetworkAgentInfo newDefaultNetwork =
+ null != reassignment ? reassignment.mNewNetwork : oldDefaultNetwork;
+
+ if (oldDefaultNetwork != newDefaultNetwork) {
+ if (oldDefaultNetwork != null) {
+ mLingerMonitor.noteLingerDefaultNetwork(oldDefaultNetwork, newDefaultNetwork);
+ }
+ updateDataActivityTracking(newDefaultNetwork, oldDefaultNetwork);
+ // Notify system services of the new default.
+ makeDefault(newDefaultNetwork);
+ // Log 0 -> X and Y -> X default network transitions, where X is the new default.
+ mDeps.getMetricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(
+ now, newDefaultNetwork, oldDefaultNetwork);
+ // Have a new default network, release the transition wakelock in
+ scheduleReleaseNetworkTransitionWakelock();
+ }
// Notify requested networks are available after the default net is switched, but
// before LegacyTypeTracker sends legacy broadcasts
for (final NetworkReassignment.RequestReassignment event :
changes.getRequestReassignments()) {
+ // Tell NetworkProviders about the new score, so they can stop
+ // trying to connect if they know they cannot match it.
+ // TODO - this could get expensive if there are a lot of outstanding requests for this
+ // network. Think of a way to reduce this. Push netid->request mapping to each factory?
+ sendUpdatedScoreToFactories(event.mRequest.request, event.mNewNetwork);
+
if (null != event.mNewNetwork) {
notifyNetworkAvailable(event.mNewNetwork, event.mRequest);
+ } else {
+ // TODO: Technically, sending CALLBACK_LOST here is
+ // incorrect if there is a replacement network currently
+ // connected that can satisfy nri, which is a request
+ // (not a listen). However, the only capability that can both
+ // a) be requested and b) change is NET_CAPABILITY_TRUSTED,
+ // so this code is only incorrect for a network that loses
+ // the TRUSTED capability, which is a rare case.
+ callCallbackForRequest(event.mRequest, event.mOldNetwork,
+ ConnectivityManager.CALLBACK_LOST, 0);
}
}
diff --git a/services/core/java/com/android/server/connectivity/LingerMonitor.java b/services/core/java/com/android/server/connectivity/LingerMonitor.java
index 929dfc4d1511..707151059869 100644
--- a/services/core/java/com/android/server/connectivity/LingerMonitor.java
+++ b/services/core/java/com/android/server/connectivity/LingerMonitor.java
@@ -16,6 +16,10 @@
package com.android.server.connectivity;
+import static android.net.ConnectivityManager.NETID_UNSET;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -27,18 +31,16 @@ import android.text.TextUtils;
import android.text.format.DateUtils;
import android.util.Log;
import android.util.SparseArray;
-import android.util.SparseIntArray;
import android.util.SparseBooleanArray;
-import java.util.Arrays;
-import java.util.HashMap;
+import android.util.SparseIntArray;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.MessageUtils;
-import com.android.server.connectivity.NetworkNotificationManager;
import com.android.server.connectivity.NetworkNotificationManager.NotificationType;
-import static android.net.ConnectivityManager.NETID_UNSET;
+import java.util.Arrays;
+import java.util.HashMap;
/**
* Class that monitors default network linger events and possibly notifies the user of network
@@ -206,8 +208,19 @@ public class LingerMonitor {
mEverNotified.put(fromNai.network.netId, true);
}
+ /**
+ * Put up or dismiss a notification or toast for of a change in the default network if needed.
+ *
+ * Putting up a notification when switching from no network to some network is not supported
+ * and as such this method can't be called with a null |fromNai|. It can be called with a
+ * null |toNai| if there isn't a default network any more.
+ *
+ * @param fromNai switching from this NAI
+ * @param toNai switching to this NAI
+ */
// The default network changed from fromNai to toNai due to a change in score.
- public void noteLingerDefaultNetwork(NetworkAgentInfo fromNai, NetworkAgentInfo toNai) {
+ public void noteLingerDefaultNetwork(@NonNull final NetworkAgentInfo fromNai,
+ @Nullable final NetworkAgentInfo toNai) {
if (VDBG) {
Log.d(TAG, "noteLingerDefaultNetwork from=" + fromNai.name() +
" everValidated=" + fromNai.everValidated +
@@ -221,6 +234,10 @@ public class LingerMonitor {
// Internet access).
maybeStopNotifying(fromNai);
+ // If the network was simply lost (either because it disconnected or because it stopped
+ // being the default with no replacement), then don't show a notification.
+ if (null == toNai) return;
+
// If this network never validated, don't notify. Otherwise, we could do things like:
//
// 1. Unvalidated wifi connects.
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 50f1bbeed0c5..1442b31aa8f1 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -5741,6 +5741,40 @@ public class ConnectivityServiceTest {
mCm.unregisterNetworkCallback(defaultCallback);
}
+ @Test
+ public final void testLoseTrusted() throws Exception {
+ final NetworkRequest trustedRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_TRUSTED)
+ .build();
+ final TestNetworkCallback trustedCallback = new TestNetworkCallback();
+ mCm.requestNetwork(trustedRequest, trustedCallback);
+
+ mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR);
+ mCellNetworkAgent.connect(true);
+ trustedCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(true);
+ trustedCallback.expectAvailableDoubleValidatedCallbacks(mWiFiNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mWiFiNetworkAgent.getNetwork().netId));
+
+ mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
+ // There is currently a bug where losing the TRUSTED capability will send a LOST
+ // callback to requests before the available callback, in spite of the semantics
+ // of the requests dictating this should not happen. This is considered benign, but
+ // ideally should be fixed in the future.
+ trustedCallback.expectCallback(CallbackEntry.LOST, mWiFiNetworkAgent);
+ trustedCallback.expectAvailableCallbacksValidated(mCellNetworkAgent);
+ verify(mNetworkManagementService).setDefaultNetId(eq(mCellNetworkAgent.getNetwork().netId));
+
+ mCellNetworkAgent.removeCapability(NET_CAPABILITY_TRUSTED);
+ trustedCallback.expectCallback(CallbackEntry.LOST, mCellNetworkAgent);
+ verify(mNetworkManagementService).clearDefaultNetId();
+
+ mCm.unregisterNetworkCallback(trustedCallback);
+ }
+
@Ignore // 40%+ flakiness : figure out why and re-enable.
@Test
public final void testBatteryStatsNetworkType() throws Exception {