Merge changes Ide9daebc,Id47ada57
* changes:
Ensure all VPN runners clean up state when exiting
Enforce restricted user, getConnectionOwnerUid checks
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6351f34..5f032fc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -66,6 +66,7 @@
import android.content.res.Configuration;
import android.database.ContentObserver;
import android.net.CaptivePortal;
+import android.net.CaptivePortalData;
import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport;
@@ -548,6 +549,14 @@
public static final int EVENT_PROBE_STATUS_CHANGED = 46;
/**
+ * Event for NetworkMonitor to inform ConnectivityService that captive portal data has changed.
+ * arg1 = unused
+ * arg2 = netId
+ * obj = captive portal data
+ */
+ private static final int EVENT_CAPPORT_DATA_CHANGED = 47;
+
+ /**
* Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown.
*/
@@ -2817,6 +2826,12 @@
updatePrivateDns(nai, (PrivateDnsConfig) msg.obj);
break;
}
+ case EVENT_CAPPORT_DATA_CHANGED: {
+ final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
+ if (nai == null) break;
+ handleCaptivePortalDataUpdate(nai, (CaptivePortalData) msg.obj);
+ break;
+ }
}
return true;
}
@@ -2984,6 +2999,13 @@
}
@Override
+ public void notifyCaptivePortalDataChanged(CaptivePortalData data) {
+ mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
+ EVENT_CAPPORT_DATA_CHANGED,
+ 0, mNetId, data));
+ }
+
+ @Override
public void showProvisioningNotification(String action, String packageName) {
final Intent intent = new Intent(action);
intent.setPackage(packageName);
@@ -3111,6 +3133,13 @@
handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
}
+ private void handleCaptivePortalDataUpdate(@NonNull final NetworkAgentInfo nai,
+ @Nullable final CaptivePortalData data) {
+ nai.captivePortalData = data;
+ // CaptivePortalData will be merged into LinkProperties from NetworkAgentInfo
+ handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties));
+ }
+
/**
* Updates the linger state from the network requests inside the NAI.
* @param nai the agent info to update
@@ -5847,6 +5876,10 @@
updateWakeOnLan(newLp);
+ // Captive portal data is obtained from NetworkMonitor and stored in NetworkAgentInfo,
+ // it is not contained in LinkProperties sent from NetworkAgents so needs to be merged here.
+ newLp.setCaptivePortalData(networkAgent.captivePortalData);
+
// TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) {
synchronized (networkAgent) {
@@ -6907,6 +6940,15 @@
// worry about multiple different substates of CONNECTED.
newInfo.setDetailedState(NetworkInfo.DetailedState.SUSPENDED, info.getReason(),
info.getExtraInfo());
+ } else if (!suspended && info.getDetailedState() == NetworkInfo.DetailedState.SUSPENDED) {
+ // SUSPENDED state is currently only overridden from CONNECTED state. In the case the
+ // network agent is created, then goes to suspended, then goes out of suspended without
+ // ever setting connected. Check if network agent is ever connected to update the state.
+ newInfo.setDetailedState(nai.everConnected
+ ? NetworkInfo.DetailedState.CONNECTED
+ : NetworkInfo.DetailedState.CONNECTING,
+ info.getReason(),
+ info.getExtraInfo());
}
newInfo.setRoaming(!nai.networkCapabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING));
return newInfo;
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index d30a320..58b5cba 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -21,6 +21,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.net.CaptivePortalData;
import android.net.IDnsResolver;
import android.net.INetd;
import android.net.INetworkMonitor;
@@ -167,6 +168,10 @@
// Set to true when partial connectivity was detected.
public boolean partialConnectivity;
+ // Captive portal info of the network, if any.
+ // Obtained by ConnectivityService and merged into NetworkAgent-provided information.
+ public CaptivePortalData captivePortalData;
+
// Networks are lingered when they become unneeded as a result of their NetworkRequests being
// satisfied by a higher-scoring network. so as to allow communication to wrap up before the
// network is taken down. This usually only happens to the default network. Lingering ends with
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index e233651..8ed497b 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -810,6 +810,14 @@
mProbesSucceeded = probesSucceeded;
}
+ void notifyCaptivePortalDataChanged(CaptivePortalData data) {
+ try {
+ mNmCallbacks.notifyCaptivePortalDataChanged(data);
+ } catch (RemoteException e) {
+ throw new AssertionError("This cannot happen", e);
+ }
+ }
+
public String waitForRedirectUrl() {
assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
return mRedirectUrl;
@@ -1866,18 +1874,21 @@
final Uri capportUrl = Uri.parse("https://capport.example.com/api");
final CaptivePortalData capportData = new CaptivePortalData.Builder()
.setCaptive(true).build();
- newLp.setCaptivePortalApiUrl(capportUrl);
- newLp.setCaptivePortalData(capportData);
- mWiFiNetworkAgent.sendLinkProperties(newLp);
final Uri expectedCapportUrl = sanitized ? null : capportUrl;
- final CaptivePortalData expectedCapportData = sanitized ? null : capportData;
+ newLp.setCaptivePortalApiUrl(capportUrl);
+ mWiFiNetworkAgent.sendLinkProperties(newLp);
callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl())
- && Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
+ Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
- Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl())
- && Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
+ Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
+
+ final CaptivePortalData expectedCapportData = sanitized ? null : capportData;
+ mWiFiNetworkAgent.notifyCaptivePortalDataChanged(capportData);
+ callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
+ Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
+ defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
+ Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork());
assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl());
@@ -2831,6 +2842,40 @@
assertNoCallbacks(captivePortalCallback, validatedCallback);
}
+ @Test
+ public void testCaptivePortalApi() throws Exception {
+ mServiceContext.setPermission(
+ android.Manifest.permission.NETWORK_SETTINGS, PERMISSION_GRANTED);
+
+ final TestNetworkCallback captivePortalCallback = new TestNetworkCallback();
+ final NetworkRequest captivePortalRequest = new NetworkRequest.Builder()
+ .addCapability(NET_CAPABILITY_CAPTIVE_PORTAL).build();
+ mCm.registerNetworkCallback(captivePortalRequest, captivePortalCallback);
+
+ mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI);
+ final String redirectUrl = "http://example.com/firstPath";
+
+ mWiFiNetworkAgent.connectWithCaptivePortal(redirectUrl, false /* isStrictMode */);
+ captivePortalCallback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent);
+
+ final CaptivePortalData testData = new CaptivePortalData.Builder()
+ .setUserPortalUrl(Uri.parse(redirectUrl))
+ .setBytesRemaining(12345L)
+ .build();
+
+ mWiFiNetworkAgent.notifyCaptivePortalDataChanged(testData);
+
+ captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
+ lp -> testData.equals(lp.getCaptivePortalData()));
+
+ final LinkProperties newLps = new LinkProperties();
+ newLps.setMtu(1234);
+ mWiFiNetworkAgent.sendLinkProperties(newLps);
+ // CaptivePortalData is not lost and unchanged when LPs are received from the NetworkAgent
+ captivePortalCallback.expectLinkPropertiesThat(mWiFiNetworkAgent,
+ lp -> testData.equals(lp.getCaptivePortalData()) && lp.getMtu() == 1234);
+ }
+
private NetworkRequest.Builder newWifiRequestBuilder() {
return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
}
@@ -3175,6 +3220,7 @@
mCellNetworkAgent);
cellNetworkCallback.expectCallback(CallbackEntry.SUSPENDED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
+ assertEquals(NetworkInfo.State.SUSPENDED, mCm.getActiveNetworkInfo().getState());
// Register a garden variety default network request.
TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
@@ -3190,6 +3236,7 @@
mCellNetworkAgent);
cellNetworkCallback.expectCallback(CallbackEntry.RESUMED, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
+ assertEquals(NetworkInfo.State.CONNECTED, mCm.getActiveNetworkInfo().getState());
dfltNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(dfltNetworkCallback);