Send LinkProperties update on new capport data
When new CaptivePortalData is received from NetworkMonitor, send a
LinkProperties updated callback.
The updated LinkProperties only contain CaptivePortalData if the
receiver has NETWORK_SETTINGS or MAINLINE_NETWORK_STACK permissions, as
defined in the current callback code.
Test: atest FrameworksNetTests
Bug: 139269711
Change-Id: I68595a519171b31792259849efff5f58c43cacd4
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1b43fc0..1f027d6 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) {
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 f40e57f..64591a3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -799,6 +799,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;
@@ -1845,18 +1853,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());
@@ -2810,6 +2821,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);
}