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
This commit is contained in:
Remi NGUYEN VAN
2019-12-12 12:57:11 +09:00
parent 02d8578fc3
commit 45e11181b4
3 changed files with 91 additions and 8 deletions

View File

@@ -66,6 +66,7 @@ import android.content.IntentFilter;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.net.CaptivePortal; import android.net.CaptivePortal;
import android.net.CaptivePortalData;
import android.net.ConnectionInfo; import android.net.ConnectionInfo;
import android.net.ConnectivityDiagnosticsManager.ConnectivityReport; import android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import android.net.ConnectivityDiagnosticsManager.DataStallReport; import android.net.ConnectivityDiagnosticsManager.DataStallReport;
@@ -547,6 +548,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
*/ */
public static final int EVENT_PROBE_STATUS_CHANGED = 46; 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 * Argument for {@link #EVENT_PROVISIONING_NOTIFICATION} to indicate that the notification
* should be shown. * should be shown.
@@ -2817,6 +2826,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
updatePrivateDns(nai, (PrivateDnsConfig) msg.obj); updatePrivateDns(nai, (PrivateDnsConfig) msg.obj);
break; break;
} }
case EVENT_CAPPORT_DATA_CHANGED: {
final NetworkAgentInfo nai = getNetworkAgentInfoForNetId(msg.arg2);
if (nai == null) break;
handleCaptivePortalDataUpdate(nai, (CaptivePortalData) msg.obj);
break;
}
} }
return true; return true;
} }
@@ -2983,6 +2998,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
probesCompleted, probesSucceeded, new Integer(mNetId))); probesCompleted, probesSucceeded, new Integer(mNetId)));
} }
@Override
public void notifyCaptivePortalDataChanged(CaptivePortalData data) {
mTrackerHandler.sendMessage(mTrackerHandler.obtainMessage(
EVENT_CAPPORT_DATA_CHANGED,
0, mNetId, data));
}
@Override @Override
public void showProvisioningNotification(String action, String packageName) { public void showProvisioningNotification(String action, String packageName) {
final Intent intent = new Intent(action); final Intent intent = new Intent(action);
@@ -3111,6 +3133,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
handleUpdateLinkProperties(nai, new LinkProperties(nai.linkProperties)); 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. * Updates the linger state from the network requests inside the NAI.
* @param nai the agent info to update * @param nai the agent info to update
@@ -5847,6 +5876,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
updateWakeOnLan(newLp); 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 // TODO - move this check to cover the whole function
if (!Objects.equals(newLp, oldLp)) { if (!Objects.equals(newLp, oldLp)) {
synchronized (networkAgent) { synchronized (networkAgent) {

View File

@@ -21,6 +21,7 @@ import static android.net.NetworkCapabilities.transportNamesOf;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.net.CaptivePortalData;
import android.net.IDnsResolver; import android.net.IDnsResolver;
import android.net.INetd; import android.net.INetd;
import android.net.INetworkMonitor; import android.net.INetworkMonitor;
@@ -167,6 +168,10 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
// Set to true when partial connectivity was detected. // Set to true when partial connectivity was detected.
public boolean partialConnectivity; 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 // 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 // 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 // network is taken down. This usually only happens to the default network. Lingering ends with

View File

@@ -799,6 +799,14 @@ public class ConnectivityServiceTest {
mProbesSucceeded = probesSucceeded; mProbesSucceeded = probesSucceeded;
} }
void notifyCaptivePortalDataChanged(CaptivePortalData data) {
try {
mNmCallbacks.notifyCaptivePortalDataChanged(data);
} catch (RemoteException e) {
throw new AssertionError("This cannot happen", e);
}
}
public String waitForRedirectUrl() { public String waitForRedirectUrl() {
assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS)); assertTrue(mNetworkStatusReceived.block(TIMEOUT_MS));
return mRedirectUrl; return mRedirectUrl;
@@ -1845,18 +1853,21 @@ public class ConnectivityServiceTest {
final Uri capportUrl = Uri.parse("https://capport.example.com/api"); final Uri capportUrl = Uri.parse("https://capport.example.com/api");
final CaptivePortalData capportData = new CaptivePortalData.Builder() final CaptivePortalData capportData = new CaptivePortalData.Builder()
.setCaptive(true).build(); .setCaptive(true).build();
newLp.setCaptivePortalApiUrl(capportUrl);
newLp.setCaptivePortalData(capportData);
mWiFiNetworkAgent.sendLinkProperties(newLp);
final Uri expectedCapportUrl = sanitized ? null : capportUrl; final Uri expectedCapportUrl = sanitized ? null : capportUrl;
final CaptivePortalData expectedCapportData = sanitized ? null : capportData; newLp.setCaptivePortalApiUrl(capportUrl);
mWiFiNetworkAgent.sendLinkProperties(newLp);
callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> callback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()) Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
&& Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp -> defaultCallback.expectLinkPropertiesThat(mWiFiNetworkAgent, lp ->
Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()) Objects.equals(expectedCapportUrl, lp.getCaptivePortalApiUrl()));
&& Objects.equals(expectedCapportData, lp.getCaptivePortalData()));
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()); final LinkProperties lp = mCm.getLinkProperties(mWiFiNetworkAgent.getNetwork());
assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl()); assertEquals(expectedCapportUrl, lp.getCaptivePortalApiUrl());
@@ -2810,6 +2821,40 @@ public class ConnectivityServiceTest {
assertNoCallbacks(captivePortalCallback, validatedCallback); 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() { private NetworkRequest.Builder newWifiRequestBuilder() {
return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI); return new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI);
} }