Merge "Drop circular dependency" into main
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index 46c435f..8552eec 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -275,7 +275,7 @@
}
@VisibleForTesting
- static class MdnsListener implements MdnsServiceBrowserListener {
+ abstract static class MdnsListener implements MdnsServiceBrowserListener {
protected final int mClientRequestId;
protected final int mTransactionId;
@NonNull
@@ -321,6 +321,10 @@
@Override
public void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) { }
+
+ // Ensure toString gets overridden
+ @NonNull
+ public abstract String toString();
}
private class DiscoveryListener extends MdnsListener {
@@ -351,13 +355,21 @@
mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
DISCOVERY_QUERY_SENT_CALLBACK, new MdnsEvent(mClientRequestId));
}
+
+ @NonNull
+ @Override
+ public String toString() {
+ return String.format("DiscoveryListener: serviceType=%s", getListenedServiceType());
+ }
}
private class ResolutionListener extends MdnsListener {
+ private final String mServiceName;
ResolutionListener(int clientRequestId, int transactionId,
- @NonNull String listenServiceType) {
+ @NonNull String listenServiceType, @NonNull String serviceName) {
super(clientRequestId, transactionId, listenServiceType);
+ mServiceName = serviceName;
}
@Override
@@ -373,13 +385,22 @@
mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
DISCOVERY_QUERY_SENT_CALLBACK, new MdnsEvent(mClientRequestId));
}
+
+ @NonNull
+ @Override
+ public String toString() {
+ return String.format("ResolutionListener serviceName=%s, serviceType=%s",
+ mServiceName, getListenedServiceType());
+ }
}
private class ServiceInfoListener extends MdnsListener {
+ private final String mServiceName;
ServiceInfoListener(int clientRequestId, int transactionId,
- @NonNull String listenServiceType) {
+ @NonNull String listenServiceType, @NonNull String serviceName) {
super(clientRequestId, transactionId, listenServiceType);
+ this.mServiceName = serviceName;
}
@Override
@@ -410,6 +431,13 @@
mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
DISCOVERY_QUERY_SENT_CALLBACK, new MdnsEvent(mClientRequestId));
}
+
+ @NonNull
+ @Override
+ public String toString() {
+ return String.format("ServiceInfoListener serviceName=%s, serviceType=%s",
+ mServiceName, getListenedServiceType());
+ }
}
private class SocketRequestMonitor implements MdnsSocketProvider.SocketRequestMonitor {
@@ -656,9 +684,12 @@
}
private void storeAdvertiserRequestMap(int clientRequestId, int transactionId,
- ClientInfo clientInfo, @Nullable Network requestedNetwork) {
+ ClientInfo clientInfo, @NonNull NsdServiceInfo serviceInfo) {
+ final String serviceFullName =
+ serviceInfo.getServiceName() + "." + serviceInfo.getServiceType();
clientInfo.mClientRequests.put(clientRequestId, new AdvertiserClientRequest(
- transactionId, requestedNetwork, mClock.elapsedRealtime()));
+ transactionId, serviceInfo.getNetwork(), serviceFullName,
+ mClock.elapsedRealtime()));
mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
updateMulticastLock();
}
@@ -1010,7 +1041,7 @@
mAdvertiser.addOrUpdateService(transactionId, serviceInfo,
mdnsAdvertisingOptions, clientInfo.mUid);
storeAdvertiserRequestMap(clientRequestId, transactionId, clientInfo,
- serviceInfo.getNetwork());
+ serviceInfo);
} else {
maybeStartDaemon();
transactionId = getUniqueId();
@@ -1104,7 +1135,7 @@
maybeStartMonitoringSockets();
final MdnsListener listener = new ResolutionListener(clientRequestId,
- transactionId, resolveServiceType);
+ transactionId, resolveServiceType, info.getServiceName());
final int ifaceIdx = info.getNetwork() != null
? 0 : info.getInterfaceIndex();
final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
@@ -1207,7 +1238,7 @@
maybeStartMonitoringSockets();
final MdnsListener listener = new ServiceInfoListener(clientRequestId,
- transactionId, resolveServiceType);
+ transactionId, resolveServiceType, info.getServiceName());
final int ifIndex = info.getNetwork() != null
? 0 : info.getInterfaceIndex();
final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
@@ -2551,6 +2582,17 @@
// Dump state machine logs
mNsdStateMachine.dump(fd, pw, args);
+ // Dump clients
+ pw.println();
+ pw.println("Active clients:");
+ pw.increaseIndent();
+ HandlerUtils.runWithScissorsForDump(mNsdStateMachine.getHandler(), () -> {
+ for (ClientInfo clientInfo : mClients.values()) {
+ pw.println(clientInfo.toString());
+ }
+ }, 10_000);
+ pw.decreaseIndent();
+
// Dump service and clients logs
pw.println();
pw.println("Logs:");
@@ -2623,6 +2665,21 @@
public int getSentQueryCount() {
return mSentQueryCount;
}
+
+ @NonNull
+ @Override
+ public String toString() {
+ return getRequestDescriptor() + " {" + mTransactionId
+ + ", startTime " + mStartTimeMs
+ + ", foundServices " + mFoundServiceCount
+ + ", lostServices " + mLostServiceCount
+ + ", fromCache " + mIsServiceFromCache
+ + ", sentQueries " + mSentQueryCount
+ + "}";
+ }
+
+ @NonNull
+ protected abstract String getRequestDescriptor();
}
private static class LegacyClientRequest extends ClientRequest {
@@ -2632,6 +2689,12 @@
super(transactionId, startTimeMs);
mRequestCode = requestCode;
}
+
+ @NonNull
+ @Override
+ protected String getRequestDescriptor() {
+ return "Legacy (" + mRequestCode + ")";
+ }
}
private abstract static class JavaBackendClientRequest extends ClientRequest {
@@ -2651,9 +2714,20 @@
}
private static class AdvertiserClientRequest extends JavaBackendClientRequest {
+ @NonNull
+ private final String mServiceFullName;
+
private AdvertiserClientRequest(int transactionId, @Nullable Network requestedNetwork,
- long startTimeMs) {
+ @NonNull String serviceFullName, long startTimeMs) {
super(transactionId, requestedNetwork, startTimeMs);
+ mServiceFullName = serviceFullName;
+ }
+
+ @NonNull
+ @Override
+ public String getRequestDescriptor() {
+ return String.format("Advertiser: serviceFullName=%s, net=%s",
+ mServiceFullName, getRequestedNetwork());
}
}
@@ -2666,6 +2740,12 @@
super(transactionId, requestedNetwork, startTimeMs);
mListener = listener;
}
+
+ @NonNull
+ @Override
+ public String getRequestDescriptor() {
+ return String.format("Discovery/%s, net=%s", mListener, getRequestedNetwork());
+ }
}
/* Information tracked per client */
@@ -2710,17 +2790,15 @@
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append("mResolvedService ").append(mResolvedService).append("\n");
- sb.append("mIsLegacy ").append(mIsPreSClient).append("\n");
- sb.append("mUseJavaBackend ").append(mUseJavaBackend).append("\n");
- sb.append("mUid ").append(mUid).append("\n");
+ sb.append("mUid ").append(mUid).append(", ");
+ sb.append("mResolvedService ").append(mResolvedService).append(", ");
+ sb.append("mIsLegacy ").append(mIsPreSClient).append(", ");
+ sb.append("mUseJavaBackend ").append(mUseJavaBackend).append(", ");
+ sb.append("mClientRequests:\n");
for (int i = 0; i < mClientRequests.size(); i++) {
int clientRequestId = mClientRequests.keyAt(i);
- sb.append("clientRequestId ")
- .append(clientRequestId)
- .append(" transactionId ").append(mClientRequests.valueAt(i).mTransactionId)
- .append(" type ").append(
- mClientRequests.valueAt(i).getClass().getSimpleName())
+ sb.append(" ").append(clientRequestId)
+ .append(": ").append(mClientRequests.valueAt(i).toString())
.append("\n");
}
return sb.toString();
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index 9c8fd99..71f289e 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -131,6 +131,10 @@
// returned when a tethered interface is requested; until then, it remains in client mode. Its
// current mode is reflected in mTetheringInterfaceMode.
private String mTetheringInterface;
+ // If the tethering interface is in server mode, it is not tracked by factory. The HW address
+ // must be maintained by the EthernetTracker. Its current mode is reflected in
+ // mTetheringInterfaceMode.
+ private String mTetheringInterfaceHwAddr;
private int mTetheringInterfaceMode = INTERFACE_MODE_CLIENT;
// Tracks whether clients were notified that the tethered interface is available
private boolean mTetheredInterfaceWasAvailable = false;
@@ -582,6 +586,7 @@
removeInterface(iface);
if (iface.equals(mTetheringInterface)) {
mTetheringInterface = null;
+ mTetheringInterfaceHwAddr = null;
}
broadcastInterfaceStateChange(iface);
}
@@ -610,13 +615,14 @@
return;
}
+ final String hwAddress = config.hwAddr;
+
if (getInterfaceMode(iface) == INTERFACE_MODE_SERVER) {
maybeUpdateServerModeInterfaceState(iface, true);
+ mTetheringInterfaceHwAddr = hwAddress;
return;
}
- final String hwAddress = config.hwAddr;
-
NetworkCapabilities nc = mNetworkCapabilities.get(iface);
if (nc == null) {
// Try to resolve using mac address
diff --git a/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java b/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java
index 2e9a99b..586f19d 100644
--- a/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java
+++ b/staticlibs/device/com/android/net/module/util/netlink/NduseroptMessage.java
@@ -156,8 +156,9 @@
@Override
public String toString() {
- return String.format("Nduseroptmsg(%d, %d, %d, %d, %d, %s)",
+ return String.format("Nduseroptmsg(family:%d, opts_len:%d, ifindex:%d, icmp_type:%d, "
+ + "icmp_code:%d, srcaddr: %s, %s)",
family, opts_len, ifindex, Byte.toUnsignedInt(icmp_type),
- Byte.toUnsignedInt(icmp_code), srcaddr.getHostAddress());
+ Byte.toUnsignedInt(icmp_code), srcaddr.getHostAddress(), option);
}
}
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java
index 4fc5ec2..d1df3a6 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/NduseroptMessageTest.java
@@ -252,8 +252,10 @@
public void testToString() {
NduseroptMessage msg = parseNduseroptMessage(toBuffer(MSG_PREF64));
assertNotNull(msg);
- assertEquals("Nduseroptmsg(10, 16, 1431655765, 134, 0, fe80:2:3:4:5:6:7:8%1431655765)",
- msg.toString());
+ final String expected = "Nduseroptmsg(family:10, opts_len:16, ifindex:1431655765, "
+ + "icmp_type:134, icmp_code:0, srcaddr: fe80:2:3:4:5:6:7:8%1431655765, "
+ + "NdOptPref64(2001:db8:3:4:5:6::/96, 10064))";
+ assertEquals(expected, msg.toString());
}
// Convenience method to parse a NduseroptMessage that's not part of a netlink message.
diff --git a/tests/cts/hostside/aidl/Android.bp b/tests/cts/hostside/aidl/Android.bp
index 18a5897..33761dc 100644
--- a/tests/cts/hostside/aidl/Android.bp
+++ b/tests/cts/hostside/aidl/Android.bp
@@ -21,9 +21,7 @@
name: "CtsHostsideNetworkTestsAidl",
sdk_version: "current",
srcs: [
- "com/android/cts/net/hostside/IMyService.aidl",
- "com/android/cts/net/hostside/INetworkCallback.aidl",
- "com/android/cts/net/hostside/INetworkStateObserver.aidl",
- "com/android/cts/net/hostside/IRemoteSocketFactory.aidl",
+ "com/android/cts/net/hostside/*.aidl",
+ "com/android/cts/net/hostside/*.java",
],
}
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl
index e7b2815..906024b 100644
--- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl
+++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/IMyService.aidl
@@ -19,11 +19,12 @@
import android.app.job.JobInfo;
import com.android.cts.net.hostside.INetworkCallback;
+import com.android.cts.net.hostside.NetworkCheckResult;
interface IMyService {
void registerBroadcastReceiver();
int getCounters(String receiverName, String action);
- String checkNetworkStatus();
+ NetworkCheckResult checkNetworkStatus(String customUrl);
String getRestrictBackgroundStatus();
void sendNotification(int notificationId, String notificationType);
void registerNetworkCallback(in NetworkRequest request, in INetworkCallback cb);
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
index 19198c5..8ef4659 100644
--- a/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
+++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/INetworkStateObserver.aidl
@@ -16,8 +16,12 @@
package com.android.cts.net.hostside;
+import android.net.NetworkInfo;
+
+import com.android.cts.net.hostside.NetworkCheckResult;
+
interface INetworkStateObserver {
- void onNetworkStateChecked(int resultCode, String resultData);
+ void onNetworkStateChecked(int resultCode, in NetworkCheckResult networkCheckResult);
const int RESULT_SUCCESS_NETWORK_STATE_CHECKED = 0;
const int RESULT_ERROR_UNEXPECTED_PROC_STATE = 1;
diff --git a/tests/cts/hostside/aidl/com/android/cts/net/hostside/NetworkCheckResult.aidl b/tests/cts/hostside/aidl/com/android/cts/net/hostside/NetworkCheckResult.aidl
new file mode 100644
index 0000000..cdd6b70
--- /dev/null
+++ b/tests/cts/hostside/aidl/com/android/cts/net/hostside/NetworkCheckResult.aidl
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.net.hostside;
+
+import android.net.NetworkInfo;
+
+@JavaDerive(toString=true)
+parcelable NetworkCheckResult {
+ boolean connected;
+ String details;
+ NetworkInfo networkInfo;
+}
\ No newline at end of file
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
index 2ca8832..4437986 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/AbstractRestrictBackgroundNetworkTestCase.java
@@ -23,6 +23,7 @@
import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
import static android.os.BatteryManager.BATTERY_PLUGGED_ANY;
+import static com.android.cts.net.arguments.InstrumentationArguments.ARG_CONNECTION_CHECK_CUSTOM_URL;
import static com.android.cts.net.arguments.InstrumentationArguments.ARG_WAIVE_BIND_PRIORITY;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.executeShellCommand;
import static com.android.cts.net.hostside.NetworkPolicyTestUtils.forceRunJob;
@@ -51,6 +52,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkInfo.State;
import android.net.NetworkRequest;
@@ -78,10 +80,10 @@
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
-import java.util.ArrayList;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Predicate;
/**
@@ -136,6 +138,7 @@
private static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
private static final String KEY_SKIP_VALIDATION_CHECKS = TEST_PKG + ".skip_validation_checks";
+ private static final String KEY_CUSTOM_URL = TEST_PKG + ".custom_url";
private static final String EMPTY_STRING = "";
@@ -165,6 +168,7 @@
protected ConnectivityManager mCm;
protected int mUid;
private int mMyUid;
+ private @Nullable String mCustomUrl;
private MyServiceClient mServiceClient;
private DeviceConfigStateHelper mDeviceIdleDeviceConfigStateHelper;
private PowerManager mPowerManager;
@@ -185,6 +189,11 @@
mServiceClient = new MyServiceClient(mContext);
final Bundle args = InstrumentationRegistry.getArguments();
+ mCustomUrl = args.getString(ARG_CONNECTION_CHECK_CUSTOM_URL);
+ if (mCustomUrl != null) {
+ Log.d(TAG, "Using custom URL " + mCustomUrl + " for network checks");
+ }
+
final int bindPriorityFlags;
if (Boolean.valueOf(args.getString(ARG_WAIVE_BIND_PRIORITY, "false"))) {
bindPriorityFlags = Context.BIND_WAIVE_PRIORITY;
@@ -502,25 +511,23 @@
*/
private String checkNetworkAccess(boolean expectAvailable,
@Nullable final String expectedUnavailableError) throws Exception {
- final String resultData = mServiceClient.checkNetworkStatus();
- return checkForAvailabilityInResultData(resultData, expectAvailable,
+ final NetworkCheckResult checkResult = mServiceClient.checkNetworkStatus(mCustomUrl);
+ return checkForAvailabilityInNetworkCheckResult(checkResult, expectAvailable,
expectedUnavailableError);
}
- private String checkForAvailabilityInResultData(String resultData, boolean expectAvailable,
- @Nullable final String expectedUnavailableError) {
- if (resultData == null) {
- assertNotNull("Network status from app2 is null", resultData);
- }
- // Network status format is described on MyBroadcastReceiver.checkNetworkStatus()
- final String[] parts = resultData.split(NETWORK_STATUS_SEPARATOR);
- assertEquals("Wrong network status: " + resultData, 5, parts.length);
- final State state = parts[0].equals("null") ? null : State.valueOf(parts[0]);
- final DetailedState detailedState = parts[1].equals("null")
- ? null : DetailedState.valueOf(parts[1]);
- final boolean connected = Boolean.valueOf(parts[2]);
- final String connectionCheckDetails = parts[3];
- final String networkInfo = parts[4];
+ private String checkForAvailabilityInNetworkCheckResult(NetworkCheckResult networkCheckResult,
+ boolean expectAvailable, @Nullable final String expectedUnavailableError) {
+ assertNotNull("NetworkCheckResult from app2 is null", networkCheckResult);
+
+ final NetworkInfo networkInfo = networkCheckResult.networkInfo;
+ assertNotNull("NetworkInfo from app2 is null", networkInfo);
+
+ final State state = networkInfo.getState();
+ final DetailedState detailedState = networkInfo.getDetailedState();
+
+ final boolean connected = networkCheckResult.connected;
+ final String connectionCheckDetails = networkCheckResult.details;
final StringBuilder errors = new StringBuilder();
final State expectedState;
@@ -926,33 +933,36 @@
if (type == TYPE_COMPONENT_FOREGROUND_SERVICE) {
startForegroundService();
assertForegroundServiceNetworkAccess();
- return;
} else if (type == TYPE_COMPONENT_ACTIVTIY) {
turnScreenOn();
final CountDownLatch latch = new CountDownLatch(1);
final Intent launchIntent = getIntentForComponent(type);
final Bundle extras = new Bundle();
- final ArrayList<Pair<Integer, String>> result = new ArrayList<>(1);
+ final AtomicReference<Pair<Integer, NetworkCheckResult>> result =
+ new AtomicReference<>();
extras.putBinder(KEY_NETWORK_STATE_OBSERVER, getNewNetworkStateObserver(latch, result));
extras.putBoolean(KEY_SKIP_VALIDATION_CHECKS, !expectAvailable);
+ extras.putString(KEY_CUSTOM_URL, mCustomUrl);
launchIntent.putExtras(extras);
mContext.startActivity(launchIntent);
if (latch.await(ACTIVITY_NETWORK_STATE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- final int resultCode = result.get(0).first;
- final String resultData = result.get(0).second;
+ final int resultCode = result.get().first;
+ final NetworkCheckResult networkCheckResult = result.get().second;
if (resultCode == INetworkStateObserver.RESULT_SUCCESS_NETWORK_STATE_CHECKED) {
- final String error = checkForAvailabilityInResultData(
- resultData, expectAvailable, null /* expectedUnavailableError */);
+ final String error = checkForAvailabilityInNetworkCheckResult(
+ networkCheckResult, expectAvailable,
+ null /* expectedUnavailableError */);
if (error != null) {
fail("Network is not available for activity in app2 (" + mUid + "): "
+ error);
}
} else if (resultCode == INetworkStateObserver.RESULT_ERROR_UNEXPECTED_PROC_STATE) {
- Log.d(TAG, resultData);
+ Log.d(TAG, networkCheckResult.details);
// App didn't come to foreground when the activity is started, so try again.
assertTopNetworkAccess(true);
} else {
- fail("Unexpected resultCode=" + resultCode + "; received=[" + resultData + "]");
+ fail("Unexpected resultCode=" + resultCode
+ + "; networkCheckResult=[" + networkCheckResult + "]");
}
} else {
fail("Timed out waiting for network availability status from app2's activity ("
@@ -960,10 +970,12 @@
}
} else if (type == TYPE_EXPEDITED_JOB) {
final Bundle extras = new Bundle();
- final ArrayList<Pair<Integer, String>> result = new ArrayList<>(1);
+ final AtomicReference<Pair<Integer, NetworkCheckResult>> result =
+ new AtomicReference<>();
final CountDownLatch latch = new CountDownLatch(1);
extras.putBinder(KEY_NETWORK_STATE_OBSERVER, getNewNetworkStateObserver(latch, result));
extras.putBoolean(KEY_SKIP_VALIDATION_CHECKS, !expectAvailable);
+ extras.putString(KEY_CUSTOM_URL, mCustomUrl);
final JobInfo jobInfo = new JobInfo.Builder(TEST_JOB_ID, TEST_JOB_COMPONENT)
.setExpedited(true)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
@@ -973,11 +985,12 @@
RESULT_SUCCESS, mServiceClient.scheduleJob(jobInfo));
forceRunJob(TEST_APP2_PKG, TEST_JOB_ID);
if (latch.await(JOB_NETWORK_STATE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
- final int resultCode = result.get(0).first;
- final String resultData = result.get(0).second;
+ final int resultCode = result.get().first;
+ final NetworkCheckResult networkCheckResult = result.get().second;
if (resultCode == INetworkStateObserver.RESULT_SUCCESS_NETWORK_STATE_CHECKED) {
- final String error = checkForAvailabilityInResultData(
- resultData, expectAvailable, null /* expectedUnavailableError */);
+ final String error = checkForAvailabilityInNetworkCheckResult(
+ networkCheckResult, expectAvailable,
+ null /* expectedUnavailableError */);
if (error != null) {
Log.d(TAG, "Network state is unexpected, checking again. " + error);
// Right now we could end up in an unexpected state if expedited job
@@ -985,7 +998,8 @@
assertNetworkAccess(expectAvailable, false /* needScreenOn */);
}
} else {
- fail("Unexpected resultCode=" + resultCode + "; received=[" + resultData + "]");
+ fail("Unexpected resultCode=" + resultCode
+ + "; networkCheckResult=[" + networkCheckResult + "]");
}
} else {
fail("Timed out waiting for network availability status from app2's expedited job ("
@@ -1028,11 +1042,12 @@
}
private Binder getNewNetworkStateObserver(final CountDownLatch latch,
- final ArrayList<Pair<Integer, String>> result) {
+ final AtomicReference<Pair<Integer, NetworkCheckResult>> result) {
return new INetworkStateObserver.Stub() {
@Override
- public void onNetworkStateChecked(int resultCode, String resultData) {
- result.add(Pair.create(resultCode, resultData));
+ public void onNetworkStateChecked(int resultCode,
+ NetworkCheckResult networkCheckResult) {
+ result.set(Pair.create(resultCode, networkCheckResult));
latch.countDown();
}
};
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnOnActivityStartTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnOnActivityStartTest.java
index c1d576d..3e22a23 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnOnActivityStartTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/ConnOnActivityStartTest.java
@@ -69,6 +69,7 @@
@RequiredProperties({BATTERY_SAVER_MODE})
public void testStartActivity_batterySaver() throws Exception {
setBatterySaverMode(true);
+ assertNetworkAccess(false, null);
assertLaunchedActivityHasNetworkAccess("testStartActivity_batterySaver", null);
}
@@ -76,6 +77,7 @@
@RequiredProperties({DATA_SAVER_MODE, METERED_NETWORK})
public void testStartActivity_dataSaver() throws Exception {
setRestrictBackground(true);
+ assertNetworkAccess(false, null);
assertLaunchedActivityHasNetworkAccess("testStartActivity_dataSaver", null);
}
@@ -83,6 +85,7 @@
@RequiredProperties({DOZE_MODE})
public void testStartActivity_doze() throws Exception {
setDozeMode(true);
+ assertNetworkAccess(false, null);
// TODO (235284115): We need to turn on Doze every time before starting
// the activity.
assertLaunchedActivityHasNetworkAccess("testStartActivity_doze", null);
@@ -93,6 +96,7 @@
public void testStartActivity_appStandby() throws Exception {
turnBatteryOn();
setAppIdle(true);
+ assertNetworkAccess(false, null);
// TODO (235284115): We need to put the app into app standby mode every
// time before starting the activity.
assertLaunchedActivityHasNetworkAccess("testStartActivity_appStandby", null);
@@ -104,6 +108,7 @@
assertLaunchedActivityHasNetworkAccess("testStartActivity_default", () -> {
assertProcessStateBelow(PROCESS_STATE_TOP_SLEEPING);
SystemClock.sleep(PROCESS_STATE_TRANSITION_DELAY_MS);
+ assertNetworkAccess(false, null);
});
}
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java
index 980ecd5..494192f 100644
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/MyServiceClient.java
@@ -98,9 +98,10 @@
return mService.getCounters(receiverName, action);
}
- public String checkNetworkStatus() throws RemoteException {
+ /** Retrieves the network state as observed from the bound test app */
+ public NetworkCheckResult checkNetworkStatus(String address) throws RemoteException {
ensureServiceConnection();
- return mService.checkNetworkStatus();
+ return mService.checkNetworkStatus(address);
}
public String getRestrictBackgroundStatus() throws RemoteException {
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
index 37dc7a0..1c45579 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/Common.java
@@ -15,10 +15,16 @@
*/
package com.android.cts.net.hostside.app2;
+import static com.android.cts.net.hostside.INetworkStateObserver.RESULT_ERROR_OTHER;
+import static com.android.cts.net.hostside.INetworkStateObserver.RESULT_ERROR_UNEXPECTED_CAPABILITIES;
+import static com.android.cts.net.hostside.INetworkStateObserver.RESULT_ERROR_UNEXPECTED_PROC_STATE;
+
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Process;
@@ -26,6 +32,12 @@
import android.util.Log;
import com.android.cts.net.hostside.INetworkStateObserver;
+import com.android.cts.net.hostside.NetworkCheckResult;
+
+import java.net.HttpURLConnection;
+import java.net.InetAddress;
+import java.net.URL;
+import java.util.concurrent.TimeUnit;
public final class Common {
@@ -48,6 +60,9 @@
static final String ACTION_SNOOZE_WARNING =
"com.android.server.net.action.SNOOZE_WARNING";
+ private static final String DEFAULT_TEST_URL =
+ "https://connectivitycheck.android.com/generate_204";
+
static final String NOTIFICATION_TYPE_CONTENT = "CONTENT";
static final String NOTIFICATION_TYPE_DELETE = "DELETE";
static final String NOTIFICATION_TYPE_FULL_SCREEN = "FULL_SCREEN";
@@ -59,10 +74,12 @@
static final String TEST_PKG = "com.android.cts.net.hostside";
static final String KEY_NETWORK_STATE_OBSERVER = TEST_PKG + ".observer";
static final String KEY_SKIP_VALIDATION_CHECKS = TEST_PKG + ".skip_validation_checks";
+ static final String KEY_CUSTOM_URL = TEST_PKG + ".custom_url";
static final int TYPE_COMPONENT_ACTIVTY = 0;
static final int TYPE_COMPONENT_FOREGROUND_SERVICE = 1;
static final int TYPE_COMPONENT_EXPEDITED_JOB = 2;
+ private static final int NETWORK_TIMEOUT_MS = (int) TimeUnit.SECONDS.toMillis(10);
static int getUid(Context context) {
final String packageName = context.getPackageName();
@@ -73,6 +90,15 @@
}
}
+ private static NetworkCheckResult createNetworkCheckResult(boolean connected, String details,
+ NetworkInfo networkInfo) {
+ final NetworkCheckResult checkResult = new NetworkCheckResult();
+ checkResult.connected = connected;
+ checkResult.details = details;
+ checkResult.networkInfo = networkInfo;
+ return checkResult;
+ }
+
private static boolean validateComponentState(Context context, int componentType,
INetworkStateObserver observer) throws RemoteException {
final ActivityManager activityManager = context.getSystemService(ActivityManager.class);
@@ -80,9 +106,9 @@
case TYPE_COMPONENT_ACTIVTY: {
final int procState = activityManager.getUidProcessState(Process.myUid());
if (procState != ActivityManager.PROCESS_STATE_TOP) {
- observer.onNetworkStateChecked(
- INetworkStateObserver.RESULT_ERROR_UNEXPECTED_PROC_STATE,
- "Unexpected procstate: " + procState);
+ observer.onNetworkStateChecked(RESULT_ERROR_UNEXPECTED_PROC_STATE,
+ createNetworkCheckResult(false, "Unexpected procstate: " + procState,
+ null));
return false;
}
return true;
@@ -90,9 +116,9 @@
case TYPE_COMPONENT_FOREGROUND_SERVICE: {
final int procState = activityManager.getUidProcessState(Process.myUid());
if (procState != ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
- observer.onNetworkStateChecked(
- INetworkStateObserver.RESULT_ERROR_UNEXPECTED_PROC_STATE,
- "Unexpected procstate: " + procState);
+ observer.onNetworkStateChecked(RESULT_ERROR_UNEXPECTED_PROC_STATE,
+ createNetworkCheckResult(false, "Unexpected procstate: " + procState,
+ null));
return false;
}
return true;
@@ -101,16 +127,17 @@
final int capabilities = activityManager.getUidProcessCapabilities(Process.myUid());
if ((capabilities
& ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK) == 0) {
- observer.onNetworkStateChecked(
- INetworkStateObserver.RESULT_ERROR_UNEXPECTED_CAPABILITIES,
- "Unexpected capabilities: " + capabilities);
+ observer.onNetworkStateChecked(RESULT_ERROR_UNEXPECTED_CAPABILITIES,
+ createNetworkCheckResult(false,
+ "Unexpected capabilities: " + capabilities, null));
return false;
}
return true;
}
default: {
- observer.onNetworkStateChecked(INetworkStateObserver.RESULT_ERROR_OTHER,
- "Unknown component type: " + componentType);
+ observer.onNetworkStateChecked(RESULT_ERROR_OTHER,
+ createNetworkCheckResult(false, "Unknown component type: " + componentType,
+ null));
return false;
}
}
@@ -131,6 +158,7 @@
final INetworkStateObserver observer = INetworkStateObserver.Stub.asInterface(
extras.getBinder(KEY_NETWORK_STATE_OBSERVER));
if (observer != null) {
+ final String customUrl = extras.getString(KEY_CUSTOM_URL);
try {
final boolean skipValidation = extras.getBoolean(KEY_SKIP_VALIDATION_CHECKS);
if (!skipValidation && !validateComponentState(context, componentType, observer)) {
@@ -143,11 +171,64 @@
try {
observer.onNetworkStateChecked(
INetworkStateObserver.RESULT_SUCCESS_NETWORK_STATE_CHECKED,
- MyBroadcastReceiver.checkNetworkStatus(context));
+ checkNetworkStatus(context, customUrl));
} catch (RemoteException e) {
Log.e(TAG, "Error occurred while notifying the observer: " + e);
}
});
}
}
+
+ /**
+ * Checks whether the network is available by attempting a connection to the given address
+ * and returns a {@link NetworkCheckResult} object containing all the relevant details for
+ * debugging. Uses a default address if the given address is {@code null}.
+ *
+ * <p>
+ * The returned object has the following fields:
+ *
+ * <ul>
+ * <li>{@code connected}: whether or not the connection was successful.
+ * <li>{@code networkInfo}: the {@link NetworkInfo} describing the current active network as
+ * visible to this app.
+ * <li>{@code details}: A human readable string giving useful information about the success or
+ * failure.
+ * </ul>
+ */
+ static NetworkCheckResult checkNetworkStatus(Context context, String customUrl) {
+ final String address = (customUrl == null) ? DEFAULT_TEST_URL : customUrl;
+
+ // The current Android DNS resolver returns an UnknownHostException whenever network access
+ // is blocked. This can get cached in the current process-local InetAddress cache. Clearing
+ // the cache before attempting a connection ensures we never report a failure due to a
+ // negative cache entry.
+ InetAddress.clearDnsCache();
+
+ final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
+
+ final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
+ Log.d(TAG, "Running checkNetworkStatus() on thread "
+ + Thread.currentThread().getName() + " for UID " + getUid(context)
+ + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
+ boolean checkStatus = false;
+ String checkDetails = "N/A";
+ try {
+ final URL url = new URL(address);
+ final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
+ conn.setReadTimeout(NETWORK_TIMEOUT_MS);
+ conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
+ conn.setRequestMethod("GET");
+ conn.connect();
+ final int response = conn.getResponseCode();
+ checkStatus = true;
+ checkDetails = "HTTP response for " + address + ": " + response;
+ } catch (Exception e) {
+ checkStatus = false;
+ checkDetails = "Exception getting " + address + ": " + e;
+ }
+ final NetworkCheckResult result = createNetworkCheckResult(checkStatus, checkDetails,
+ networkInfo);
+ Log.d(TAG, "Offering: " + result);
+ return result;
+ }
}
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
index 825f2c9..1fd3745 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyBroadcastReceiver.java
@@ -30,7 +30,6 @@
import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_DELETE;
import static com.android.cts.net.hostside.app2.Common.NOTIFICATION_TYPE_FULL_SCREEN;
import static com.android.cts.net.hostside.app2.Common.TAG;
-import static com.android.cts.net.hostside.app2.Common.getUid;
import android.app.Notification;
import android.app.Notification.Action;
@@ -42,15 +41,10 @@
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
-import android.net.NetworkInfo;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
-import java.net.HttpURLConnection;
-import java.net.InetAddress;
-import java.net.URL;
-
/**
* Receiver used to:
* <ol>
@@ -60,8 +54,6 @@
*/
public class MyBroadcastReceiver extends BroadcastReceiver {
- private static final int NETWORK_TIMEOUT_MS = 5 * 1000;
-
private final String mName;
public MyBroadcastReceiver() {
@@ -126,82 +118,6 @@
return String.valueOf(apiStatus);
}
- private static final String NETWORK_STATUS_TEMPLATE = "%s|%s|%s|%s|%s";
- /**
- * Checks whether the network is available and return a string which can then be send as a
- * result data for the ordered broadcast.
- *
- * <p>
- * The string has the following format:
- *
- * <p><pre><code>
- * NetinfoState|NetinfoDetailedState|RealConnectionCheck|RealConnectionCheckDetails|Netinfo
- * </code></pre>
- *
- * <p>Where:
- *
- * <ul>
- * <li>{@code NetinfoState}: enum value of {@link NetworkInfo.State}.
- * <li>{@code NetinfoDetailedState}: enum value of {@link NetworkInfo.DetailedState}.
- * <li>{@code RealConnectionCheck}: boolean value of a real connection check (i.e., an attempt
- * to access an external website.
- * <li>{@code RealConnectionCheckDetails}: if HTTP output core or exception string of the real
- * connection attempt
- * <li>{@code Netinfo}: string representation of the {@link NetworkInfo}.
- * </ul>
- *
- * For example, if the connection was established fine, the result would be something like:
- * <p><pre><code>
- * CONNECTED|CONNECTED|true|200|[type: WIFI[], state: CONNECTED/CONNECTED, reason: ...]
- * </code></pre>
- *
- */
- // TODO: now that it uses Binder, it counl return a Bundle with the data parts instead...
- static String checkNetworkStatus(Context context) {
- final ConnectivityManager cm =
- (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
- // TODO: connect to a hostside server instead
- final String address = "http://example.com";
- final NetworkInfo networkInfo = cm.getActiveNetworkInfo();
- Log.d(TAG, "Running checkNetworkStatus() on thread "
- + Thread.currentThread().getName() + " for UID " + getUid(context)
- + "\n\tactiveNetworkInfo: " + networkInfo + "\n\tURL: " + address);
- boolean checkStatus = false;
- String checkDetails = "N/A";
- try {
- final URL url = new URL(address);
- final HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setReadTimeout(NETWORK_TIMEOUT_MS);
- conn.setConnectTimeout(NETWORK_TIMEOUT_MS / 2);
- conn.setRequestMethod("GET");
- conn.setDoInput(true);
- conn.connect();
- final int response = conn.getResponseCode();
- checkStatus = true;
- checkDetails = "HTTP response for " + address + ": " + response;
- } catch (Exception e) {
- checkStatus = false;
- checkDetails = "Exception getting " + address + ": " + e;
- }
- // If the app tries to make a network connection in the foreground immediately after
- // trying to do the same when it's network access was blocked, it could receive a
- // UnknownHostException due to the cached DNS entry. So, clear the dns cache after
- // every network access for now until we have a fix on the platform side.
- InetAddress.clearDnsCache();
- Log.d(TAG, checkDetails);
- final String state, detailedState;
- if (networkInfo != null) {
- state = networkInfo.getState().name();
- detailedState = networkInfo.getDetailedState().name();
- } else {
- state = detailedState = "null";
- }
- final String status = String.format(NETWORK_STATUS_TEMPLATE, state, detailedState,
- Boolean.valueOf(checkStatus), checkDetails, networkInfo);
- Log.d(TAG, "Offering " + status);
- return status;
- }
-
/**
* Sends a system notification containing actions with pending intents to launch the app's
* main activitiy or service.
diff --git a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java
index 3ed5391..5010234 100644
--- a/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java
+++ b/tests/cts/hostside/app2/src/com/android/cts/net/hostside/app2/MyService.java
@@ -21,7 +21,6 @@
import static com.android.cts.net.hostside.app2.Common.ACTION_SNOOZE_WARNING;
import static com.android.cts.net.hostside.app2.Common.DYNAMIC_RECEIVER;
import static com.android.cts.net.hostside.app2.Common.TAG;
-import static com.android.networkstack.apishim.ConstantsShim.RECEIVER_EXPORTED;
import android.app.NotificationChannel;
import android.app.NotificationManager;
@@ -41,6 +40,7 @@
import com.android.cts.net.hostside.IMyService;
import com.android.cts.net.hostside.INetworkCallback;
+import com.android.cts.net.hostside.NetworkCheckResult;
import com.android.modules.utils.build.SdkLevel;
/**
@@ -56,9 +56,7 @@
// TODO: move MyBroadcast static functions here - they were kept there to make git diff easier.
- private IMyService.Stub mBinder =
- new IMyService.Stub() {
-
+ private IMyService.Stub mBinder = new IMyService.Stub() {
@Override
public void registerBroadcastReceiver() {
if (mReceiver != null) {
@@ -83,8 +81,8 @@
}
@Override
- public String checkNetworkStatus() {
- return MyBroadcastReceiver.checkNetworkStatus(getApplicationContext());
+ public NetworkCheckResult checkNetworkStatus(String customUrl) {
+ return Common.checkNetworkStatus(getApplicationContext(), customUrl);
}
@Override
@@ -94,7 +92,7 @@
@Override
public void sendNotification(int notificationId, String notificationType) {
- MyBroadcastReceiver .sendNotification(getApplicationContext(), NOTIFICATION_CHANNEL_ID,
+ MyBroadcastReceiver.sendNotification(getApplicationContext(), NOTIFICATION_CHANNEL_ID,
notificationId, notificationType);
}
@@ -170,7 +168,7 @@
.getSystemService(JobScheduler.class);
return jobScheduler.schedule(jobInfo);
}
- };
+ };
@Override
public IBinder onBind(Intent intent) {
diff --git a/tests/cts/hostside/instrumentation_arguments/src/com/android/cts/net/arguments/InstrumentationArguments.java b/tests/cts/hostside/instrumentation_arguments/src/com/android/cts/net/arguments/InstrumentationArguments.java
index 472e347..911b129 100644
--- a/tests/cts/hostside/instrumentation_arguments/src/com/android/cts/net/arguments/InstrumentationArguments.java
+++ b/tests/cts/hostside/instrumentation_arguments/src/com/android/cts/net/arguments/InstrumentationArguments.java
@@ -18,4 +18,5 @@
public interface InstrumentationArguments {
String ARG_WAIVE_BIND_PRIORITY = "waive_bind_priority";
+ String ARG_CONNECTION_CHECK_CUSTOM_URL = "connection_check_custom_url";
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideConnOnActivityStartTest.java b/tests/cts/hostside/src/com/android/cts/net/HostsideConnOnActivityStartTest.java
index 880e826..fff716d 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideConnOnActivityStartTest.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideConnOnActivityStartTest.java
@@ -47,29 +47,29 @@
@Test
public void testStartActivity_batterySaver() throws Exception {
- runDeviceTests(TEST_PKG, TEST_CLASS, "testStartActivity_batterySaver");
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_CLASS, "testStartActivity_batterySaver");
}
@Test
public void testStartActivity_dataSaver() throws Exception {
- runDeviceTests(TEST_PKG, TEST_CLASS, "testStartActivity_dataSaver");
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_CLASS, "testStartActivity_dataSaver");
}
@FlakyTest(bugId = 231440256)
@Test
public void testStartActivity_doze() throws Exception {
- runDeviceTests(TEST_PKG, TEST_CLASS, "testStartActivity_doze");
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_CLASS, "testStartActivity_doze");
}
@Test
public void testStartActivity_appStandby() throws Exception {
- runDeviceTests(TEST_PKG, TEST_CLASS, "testStartActivity_appStandby");
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_CLASS, "testStartActivity_appStandby");
}
// TODO(b/321848487): Annotate with @RequiresFlagsEnabled to mirror the device-side test.
@Test
public void testStartActivity_default() throws Exception {
- runDeviceTestsWithArgs(TEST_PKG, TEST_CLASS, "testStartActivity_default",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_CLASS, "testStartActivity_default",
Map.of(ARG_WAIVE_BIND_PRIORITY, "true"));
}
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideDefaultNetworkRestrictionsTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideDefaultNetworkRestrictionsTests.java
index 0d01fc1..faabbef 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideDefaultNetworkRestrictionsTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideDefaultNetworkRestrictionsTests.java
@@ -46,12 +46,12 @@
}
private void runMeteredTest(String methodName) throws DeviceNotAvailableException {
- runDeviceTestsWithArgs(TEST_PKG, METERED_TEST_CLASS, methodName,
+ runDeviceTestsWithCustomOptions(TEST_PKG, METERED_TEST_CLASS, methodName,
Map.of(ARG_WAIVE_BIND_PRIORITY, "true"));
}
private void runNonMeteredTest(String methodName) throws DeviceNotAvailableException {
- runDeviceTestsWithArgs(TEST_PKG, NON_METERED_TEST_CLASS, methodName,
+ runDeviceTestsWithCustomOptions(TEST_PKG, NON_METERED_TEST_CLASS, methodName,
Map.of(ARG_WAIVE_BIND_PRIORITY, "true"));
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java
index 361f7c7..c4bcdfd 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkCallbackTests.java
@@ -41,20 +41,20 @@
@Test
public void testOnBlockedStatusChanged_dataSaver() throws Exception {
- runDeviceTests(TEST_PKG,
+ runDeviceTestsWithCustomOptions(TEST_PKG,
TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_dataSaver");
}
@Test
public void testOnBlockedStatusChanged_powerSaver() throws Exception {
- runDeviceTests(TEST_PKG,
+ runDeviceTestsWithCustomOptions(TEST_PKG,
TEST_PKG + ".NetworkCallbackTest", "testOnBlockedStatusChanged_powerSaver");
}
// TODO(b/321848487): Annotate with @RequiresFlagsEnabled to mirror the device-side test.
@Test
public void testOnBlockedStatusChanged_default() throws Exception {
- runDeviceTestsWithArgs(TEST_PKG, TEST_PKG + ".NetworkCallbackTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".NetworkCallbackTest",
"testOnBlockedStatusChanged_default", Map.of(ARG_WAIVE_BIND_PRIORITY, "true"));
}
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java
index e97db58..4730b14 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkPolicyManagerTests.java
@@ -38,48 +38,48 @@
@Test
public void testIsUidNetworkingBlocked_withUidNotBlocked() throws Exception {
- runDeviceTests(TEST_PKG,
+ runDeviceTestsWithCustomOptions(TEST_PKG,
TEST_PKG + ".NetworkPolicyManagerTest",
"testIsUidNetworkingBlocked_withUidNotBlocked");
}
@Test
public void testIsUidNetworkingBlocked_withSystemUid() throws Exception {
- runDeviceTests(TEST_PKG,
+ runDeviceTestsWithCustomOptions(TEST_PKG,
TEST_PKG + ".NetworkPolicyManagerTest", "testIsUidNetworkingBlocked_withSystemUid");
}
@Test
public void testIsUidNetworkingBlocked_withDataSaverMode() throws Exception {
- runDeviceTests(TEST_PKG,
+ runDeviceTestsWithCustomOptions(TEST_PKG,
TEST_PKG + ".NetworkPolicyManagerTest",
"testIsUidNetworkingBlocked_withDataSaverMode");
}
@Test
public void testIsUidNetworkingBlocked_withRestrictedNetworkingMode() throws Exception {
- runDeviceTests(TEST_PKG,
+ runDeviceTestsWithCustomOptions(TEST_PKG,
TEST_PKG + ".NetworkPolicyManagerTest",
"testIsUidNetworkingBlocked_withRestrictedNetworkingMode");
}
@Test
public void testIsUidNetworkingBlocked_withPowerSaverMode() throws Exception {
- runDeviceTests(TEST_PKG,
+ runDeviceTestsWithCustomOptions(TEST_PKG,
TEST_PKG + ".NetworkPolicyManagerTest",
"testIsUidNetworkingBlocked_withPowerSaverMode");
}
@Test
public void testIsUidRestrictedOnMeteredNetworks() throws Exception {
- runDeviceTests(TEST_PKG,
+ runDeviceTestsWithCustomOptions(TEST_PKG,
TEST_PKG + ".NetworkPolicyManagerTest", "testIsUidRestrictedOnMeteredNetworks");
}
// TODO(b/321848487): Annotate with @RequiresFlagsEnabled to mirror the device-side test.
@Test
public void testIsUidNetworkingBlocked_whenInBackground() throws Exception {
- runDeviceTestsWithArgs(TEST_PKG, TEST_PKG + ".NetworkPolicyManagerTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".NetworkPolicyManagerTest",
"testIsUidNetworkingBlocked_whenInBackground",
Map.of(ARG_WAIVE_BIND_PRIORITY, "true"));
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
index ca95ed6..d7dfa80 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -16,12 +16,15 @@
package com.android.cts.net;
+import static com.android.cts.net.arguments.InstrumentationArguments.ARG_CONNECTION_CHECK_CUSTOM_URL;
+
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import com.android.ddmlib.Log;
import com.android.modules.utils.build.testing.DeviceSdkLevel;
+import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.invoker.TestInformation;
import com.android.tradefed.targetprep.BuildError;
@@ -48,6 +51,10 @@
protected static final String TEST_APP2_PKG = "com.android.cts.net.hostside.app2";
protected static final String TEST_APP2_APK = "CtsHostsideNetworkTestsApp2.apk";
+ @Option(name = "custom-url", importance = Option.Importance.IF_UNSET,
+ description = "A custom url to use for testing network connections")
+ protected String mCustomUrl;
+
@BeforeClassWithInfo
public static void setUpOnceBase(TestInformation testInfo) throws Exception {
DeviceSdkLevel deviceSdkLevel = new DeviceSdkLevel(testInfo.getDevice());
@@ -149,13 +156,31 @@
+ packageName + ", u=" + currentUser);
}
- protected boolean runDeviceTestsWithArgs(String packageName, String className,
- String methodName, Map<String, String> args) throws DeviceNotAvailableException {
+ protected boolean runDeviceTestsWithCustomOptions(String packageName, String className)
+ throws DeviceNotAvailableException {
+ return runDeviceTestsWithCustomOptions(packageName, className, null);
+ }
+
+ protected boolean runDeviceTestsWithCustomOptions(String packageName, String className,
+ String methodName) throws DeviceNotAvailableException {
+ return runDeviceTestsWithCustomOptions(packageName, className, methodName, null);
+ }
+
+ protected boolean runDeviceTestsWithCustomOptions(String packageName, String className,
+ String methodName, Map<String, String> testArgs) throws DeviceNotAvailableException {
final DeviceTestRunOptions deviceTestRunOptions = new DeviceTestRunOptions(packageName)
.setTestClassName(className)
.setTestMethodName(methodName);
- for (Map.Entry<String, String> arg : args.entrySet()) {
- deviceTestRunOptions.addInstrumentationArg(arg.getKey(), arg.getValue());
+
+ // Currently there is only one custom option that the test exposes.
+ if (mCustomUrl != null) {
+ deviceTestRunOptions.addInstrumentationArg(ARG_CONNECTION_CHECK_CUSTOM_URL, mCustomUrl);
+ }
+ // Pass over any test specific arguments.
+ if (testArgs != null) {
+ for (Map.Entry<String, String> arg : testArgs.entrySet()) {
+ deviceTestRunOptions.addInstrumentationArg(arg.getKey(), arg.getValue());
+ }
}
return runDeviceTests(deviceTestRunOptions);
}
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
index 9c3751d..7b9d3b5 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideRestrictBackgroundNetworkTests.java
@@ -46,7 +46,7 @@
@SecurityTest
@Test
public void testDataWarningReceiver() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataWarningReceiverTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DataWarningReceiverTest",
"testSnoozeWarningNotReceived");
}
@@ -56,25 +56,25 @@
@Test
public void testDataSaverMode_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testGetRestrictBackgroundStatus_disabled");
}
@Test
public void testDataSaverMode_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testGetRestrictBackgroundStatus_whitelisted");
}
@Test
public void testDataSaverMode_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testGetRestrictBackgroundStatus_enabled");
}
@Test
public void testDataSaverMode_blacklisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testGetRestrictBackgroundStatus_blacklisted");
}
@@ -97,13 +97,13 @@
@Test
public void testDataSaverMode_requiredWhitelistedPackages() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testGetRestrictBackgroundStatus_requiredWhitelistedPackages");
}
@Test
public void testDataSaverMode_broadcastNotSentOnUnsupportedDevices() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DataSaverModeTest",
"testBroadcastNotSentOnUnsupportedDevices");
}
@@ -113,19 +113,19 @@
@Test
public void testBatterySaverModeMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
"testBackgroundNetworkAccess_disabled");
}
@Test
public void testBatterySaverModeMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
"testBackgroundNetworkAccess_whitelisted");
}
@Test
public void testBatterySaverModeMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".BatterySaverModeMeteredTest",
"testBackgroundNetworkAccess_enabled");
}
@@ -149,19 +149,19 @@
@Test
public void testBatterySaverModeNonMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
"testBackgroundNetworkAccess_disabled");
}
@Test
public void testBatterySaverModeNonMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
"testBackgroundNetworkAccess_whitelisted");
}
@Test
public void testBatterySaverModeNonMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".BatterySaverModeNonMeteredTest",
"testBackgroundNetworkAccess_enabled");
}
@@ -171,31 +171,31 @@
@Test
public void testAppIdleMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
"testBackgroundNetworkAccess_disabled");
}
@Test
public void testAppIdleMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
"testBackgroundNetworkAccess_whitelisted");
}
@Test
public void testAppIdleMetered_tempWhitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
"testBackgroundNetworkAccess_tempWhitelisted");
}
@Test
public void testAppIdleMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
"testBackgroundNetworkAccess_enabled");
}
@Test
public void testAppIdleMetered_idleWhitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
"testAppIdleNetworkAccess_idleWhitelisted");
}
@@ -206,51 +206,51 @@
@Test
public void testAppIdleNonMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testBackgroundNetworkAccess_disabled");
}
@Test
public void testAppIdleNonMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testBackgroundNetworkAccess_whitelisted");
}
@Test
public void testAppIdleNonMetered_tempWhitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testBackgroundNetworkAccess_tempWhitelisted");
}
@Test
public void testAppIdleNonMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testBackgroundNetworkAccess_enabled");
}
@Test
public void testAppIdleNonMetered_idleWhitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testAppIdleNetworkAccess_idleWhitelisted");
}
@Test
public void testAppIdleNonMetered_whenCharging() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testAppIdleNetworkAccess_whenCharging");
}
@Test
public void testAppIdleMetered_whenCharging() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleMeteredTest",
"testAppIdleNetworkAccess_whenCharging");
}
@Test
public void testAppIdle_toast() throws Exception {
// Check that showing a toast doesn't bring an app out of standby
- runDeviceTests(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".AppIdleNonMeteredTest",
"testAppIdle_toast");
}
@@ -260,25 +260,25 @@
@Test
public void testDozeModeMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
"testBackgroundNetworkAccess_disabled");
}
@Test
public void testDozeModeMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
"testBackgroundNetworkAccess_whitelisted");
}
@Test
public void testDozeModeMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
"testBackgroundNetworkAccess_enabled");
}
@Test
public void testDozeModeMetered_enabledButWhitelistedOnNotificationAction() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DozeModeMeteredTest",
"testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction");
}
@@ -289,26 +289,26 @@
@Test
public void testDozeModeNonMetered_disabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
"testBackgroundNetworkAccess_disabled");
}
@Test
public void testDozeModeNonMetered_whitelisted() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
"testBackgroundNetworkAccess_whitelisted");
}
@Test
public void testDozeModeNonMetered_enabled() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
"testBackgroundNetworkAccess_enabled");
}
@Test
public void testDozeModeNonMetered_enabledButWhitelistedOnNotificationAction()
throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".DozeModeNonMeteredTest",
"testBackgroundNetworkAccess_enabledButWhitelistedOnNotificationAction");
}
@@ -318,55 +318,55 @@
@Test
public void testDataAndBatterySaverModes_meteredNetwork() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testDataAndBatterySaverModes_meteredNetwork");
}
@Test
public void testDataAndBatterySaverModes_nonMeteredNetwork() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testDataAndBatterySaverModes_nonMeteredNetwork");
}
@Test
public void testDozeAndBatterySaverMode_powerSaveWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testDozeAndBatterySaverMode_powerSaveWhitelists");
}
@Test
public void testDozeAndAppIdle_powerSaveWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testDozeAndAppIdle_powerSaveWhitelists");
}
@Test
public void testAppIdleAndDoze_tempPowerSaveWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testAppIdleAndDoze_tempPowerSaveWhitelists");
}
@Test
public void testAppIdleAndBatterySaver_tempPowerSaveWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testAppIdleAndBatterySaver_tempPowerSaveWhitelists");
}
@Test
public void testDozeAndAppIdle_appIdleWhitelist() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testDozeAndAppIdle_appIdleWhitelist");
}
@Test
public void testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testAppIdleAndDoze_tempPowerSaveAndAppIdleWhitelists");
}
@Test
public void testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".MixedModesTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".MixedModesTest",
"testAppIdleAndBatterySaver_tempPowerSaveAndAppIdleWhitelists");
}
@@ -376,13 +376,13 @@
@Test
public void testNetworkAccess_restrictedMode() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".RestrictedModeTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".RestrictedModeTest",
"testNetworkAccess");
}
@Test
public void testNetworkAccess_restrictedMode_withBatterySaver() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".RestrictedModeTest",
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".RestrictedModeTest",
"testNetworkAccess_withBatterySaver");
}
@@ -392,12 +392,12 @@
@Test
public void testMeteredNetworkAccess_expeditedJob() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".ExpeditedJobMeteredTest");
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".ExpeditedJobMeteredTest");
}
@Test
public void testNonMeteredNetworkAccess_expeditedJob() throws Exception {
- runDeviceTests(TEST_PKG, TEST_PKG + ".ExpeditedJobNonMeteredTest");
+ runDeviceTestsWithCustomOptions(TEST_PKG, TEST_PKG + ".ExpeditedJobNonMeteredTest");
}
/*******************
diff --git a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
index a2e4ab6..159af00 100644
--- a/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
+++ b/tests/cts/net/src/android/net/cts/ApfIntegrationTest.kt
@@ -13,6 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+// ktlint does not allow annotating function argument literals inline. Disable the specific rule
+// since this negatively affects readability.
+@file:Suppress("ktlint:standard:comment-wrapping")
+
package android.net.cts
import android.Manifest.permission.WRITE_DEVICE_CONFIG
@@ -22,21 +26,28 @@
import android.net.NetworkRequest
import android.net.apf.ApfCapabilities
import android.os.Build
+import android.os.PowerManager
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY
import android.system.OsConstants
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.compatibility.common.util.PropertyUtil.isVendorApiLevelNewerThan
+import com.android.compatibility.common.util.PropertyUtil.getVsrApiLevel
+import com.android.compatibility.common.util.SystemUtil.runShellCommand
import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
-import com.android.testutils.DevSdkIgnoreRule
+import com.android.internal.util.HexDump
+import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.NetworkStackModuleTest
import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
+import com.android.testutils.SkipPresubmit
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.runAsShell
import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
import com.google.common.truth.TruthJUnit.assume
+import java.lang.Thread
+import kotlin.random.Random
import kotlin.test.assertNotNull
import org.junit.After
import org.junit.Before
@@ -44,17 +55,19 @@
import org.junit.Test
import org.junit.runner.RunWith
+private const val TAG = "ApfIntegrationTest"
private const val TIMEOUT_MS = 2000L
private const val APF_NEW_RA_FILTER_VERSION = "apf_new_ra_filter_version"
+private const val POLLING_INTERVAL_MS: Int = 100
@AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
@RunWith(DevSdkIgnoreRunner::class)
@NetworkStackModuleTest
-@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
class ApfIntegrationTest {
companion object {
@BeforeClass
@JvmStatic
+ @Suppress("ktlint:standard:no-multi-spaces")
fun setupOnce() {
// TODO: check that there is no active wifi network. Otherwise, ApfFilter has already been
// created.
@@ -74,20 +87,52 @@
private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
private val cm by lazy { context.getSystemService(ConnectivityManager::class.java)!! }
private val pm by lazy { context.packageManager }
+ private val powerManager by lazy { context.getSystemService(PowerManager::class.java)!! }
+ private val wakeLock by lazy { powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG) }
private lateinit var ifname: String
private lateinit var networkCallback: TestableNetworkCallback
private lateinit var caps: ApfCapabilities
fun getApfCapabilities(): ApfCapabilities {
- val caps = runShellCommandOrThrow("cmd network_stack apf $ifname capabilities").trim()
+ val caps = runShellCommand("cmd network_stack apf $ifname capabilities").trim()
+ if (caps.isEmpty()) {
+ return ApfCapabilities(0, 0, 0)
+ }
val (version, maxLen, packetFormat) = caps.split(",").map { it.toInt() }
return ApfCapabilities(version, maxLen, packetFormat)
}
+ fun pollingCheck(condition: () -> Boolean, timeout_ms: Int): Boolean {
+ var polling_time = 0
+ do {
+ Thread.sleep(POLLING_INTERVAL_MS.toLong())
+ polling_time += POLLING_INTERVAL_MS
+ if (condition()) return true
+ } while (polling_time < timeout_ms)
+ return false
+ }
+
+ fun turnScreenOff() {
+ if (!wakeLock.isHeld()) wakeLock.acquire()
+ runShellCommandOrThrow("input keyevent KEYCODE_SLEEP")
+ val result = pollingCheck({ !powerManager.isInteractive() }, timeout_ms = 2000)
+ assertThat(result).isTrue()
+ }
+
+ fun turnScreenOn() {
+ if (wakeLock.isHeld()) wakeLock.release()
+ runShellCommandOrThrow("input keyevent KEYCODE_WAKEUP")
+ val result = pollingCheck({ powerManager.isInteractive() }, timeout_ms = 2000)
+ assertThat(result).isTrue()
+ }
+
@Before
fun setUp() {
assume().that(pm.hasSystemFeature(FEATURE_WIFI)).isTrue()
- assume().that(isVendorApiLevelNewerThan(Build.VERSION_CODES.TIRAMISU)).isTrue()
+ // APF must run when the screen is off and the device is not interactive.
+ // TODO: consider running some of the tests with screen on (capabilities, read / write).
+ turnScreenOff()
+
networkCallback = TestableNetworkCallback()
cm.requestNetwork(
NetworkRequest.Builder()
@@ -100,27 +145,90 @@
ifname = assertNotNull(it.lp.interfaceName)
true
}
- runShellCommandOrThrow("cmd network_stack apf $ifname pause")
+ // It's possible the device does not support APF, in which case this command will not be
+ // successful. Ignore the error as testApfCapabilities() already asserts APF support on the
+ // respective VSR releases and all other tests are based on the capabilities indicated.
+ runShellCommand("cmd network_stack apf $ifname pause")
caps = getApfCapabilities()
}
@After
fun tearDown() {
+ if (::ifname.isInitialized) {
+ runShellCommand("cmd network_stack apf $ifname resume")
+ }
if (::networkCallback.isInitialized) {
cm.unregisterNetworkCallback(networkCallback)
}
- if (::ifname.isInitialized) {
- runShellCommandOrThrow("cmd network_stack apf $ifname resume")
- }
+ turnScreenOn()
}
@Test
- fun testGetApfCapabilities() {
+ fun testApfCapabilities() {
+ // APF became mandatory in Android 14 VSR.
+ assume().that(getVsrApiLevel()).isAtLeast(34)
+
+ // ApfFilter does not support anything but ARPHRD_ETHER.
+ assertThat(caps.apfPacketFormat).isEqualTo(OsConstants.ARPHRD_ETHER)
+
+ // DEVICEs launching with Android 14 with CHIPSETs that set ro.board.first_api_level to 34:
+ // - [GMS-VSR-5.3.12-003] MUST return 4 or higher as the APF version number from calls to
+ // the getApfPacketFilterCapabilities HAL method.
+ // - [GMS-VSR-5.3.12-004] MUST indicate at least 1024 bytes of usable memory from calls to
+ // the getApfPacketFilterCapabilities HAL method.
+ // TODO: check whether above text should be changed "34 or higher"
+ // This should assert apfVersionSupported >= 4 as per the VSR requirements, but there are
+ // currently no tests for APFv6 and there cannot be a valid implementation as the
+ // interpreter has yet to be finalized.
assertThat(caps.apfVersionSupported).isEqualTo(4)
assertThat(caps.maximumApfProgramSize).isAtLeast(1024)
- if (isVendorApiLevelNewerThan(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)) {
+
+ // DEVICEs launching with Android 15 (AOSP experimental) or higher with CHIPSETs that set
+ // ro.board.first_api_level or ro.board.api_level to 202404 or higher:
+ // - [GMS-VSR-5.3.12-009] MUST indicate at least 2000 bytes of usable memory from calls to
+ // the getApfPacketFilterCapabilities HAL method.
+ if (getVsrApiLevel() >= 202404) {
assertThat(caps.maximumApfProgramSize).isAtLeast(2000)
}
- assertThat(caps.apfPacketFormat).isEqualTo(OsConstants.ARPHRD_ETHER)
+ }
+
+ // APF is backwards compatible, i.e. a v6 interpreter supports both v2 and v4 functionality.
+ fun assumeApfVersionSupportAtLeast(version: Int) {
+ assume().that(caps.apfVersionSupported).isAtLeast(version)
+ }
+
+ fun installProgram(bytes: ByteArray) {
+ val prog = HexDump.toHexString(bytes, 0 /* offset */, bytes.size, false /* upperCase */)
+ val result = runShellCommandOrThrow("cmd network_stack apf $ifname install $prog").trim()
+ // runShellCommandOrThrow only throws on S+.
+ assertThat(result).isEqualTo("success")
+ }
+
+ fun readProgram(): ByteArray {
+ val progHexString = runShellCommandOrThrow("cmd network_stack apf $ifname read").trim()
+ // runShellCommandOrThrow only throws on S+.
+ assertThat(progHexString).isNotEmpty()
+ return HexDump.hexStringToByteArray(progHexString)
+ }
+
+ @SkipPresubmit(reason = "This test takes longer than 1 minute, do not run it on presubmit.")
+ // APF integration is mostly broken before V, only run the full read / write test on V+.
+ @IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ @Test
+ fun testReadWriteProgram() {
+ assumeApfVersionSupportAtLeast(4)
+
+ // Only test down to 2 bytes. The first byte always stays PASS.
+ val program = ByteArray(caps.maximumApfProgramSize)
+ for (i in caps.maximumApfProgramSize downTo 2) {
+ // Randomize bytes in range [1, i). And install first [0, i) bytes of program.
+ // Note that only the very first instruction (PASS) is valid APF bytecode.
+ Random.nextBytes(program, 1 /* fromIndex */, i /* toIndex */)
+ installProgram(program.sliceArray(0..<i))
+
+ // Compare entire memory region.
+ val readResult = readProgram()
+ assertWithMessage("read/write $i byte prog failed").that(readResult).isEqualTo(program)
+ }
}
}
diff --git a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
index d29e657..8f8aa5f 100644
--- a/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
+++ b/thread/tests/integration/src/android/net/thread/ThreadIntegrationTest.java
@@ -21,6 +21,7 @@
import static android.net.thread.ThreadNetworkController.DEVICE_ROLE_STOPPED;
import static android.net.thread.utils.IntegrationTestUtils.CALLBACK_TIMEOUT;
import static android.net.thread.utils.IntegrationTestUtils.RESTART_JOIN_TIMEOUT;
+import static android.net.thread.utils.IntegrationTestUtils.waitFor;
import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
import static com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow;
@@ -65,6 +66,9 @@
// The byte[] buffer size for UDP tests
private static final int UDP_BUFFER_SIZE = 1024;
+ // The maximum time for OT addresses to be propagated to the TUN interface "thread-wpan"
+ private static final Duration TUN_ADDR_UPDATE_TIMEOUT = Duration.ofSeconds(1);
+
// A valid Thread Active Operational Dataset generated from OpenThread CLI "dataset init new".
private static final byte[] DEFAULT_DATASET_TLVS =
base16().decode(
@@ -149,16 +153,22 @@
assertThat(ifconfig).doesNotContain("inet6 addr");
}
+ // TODO (b/323300829): add test for removing an OT address
@Test
public void tunInterface_joinedNetwork_otAddressesAddedToTunInterface() throws Exception {
mController.joinAndWait(DEFAULT_DATASET);
- String ifconfig = runShellCommand("ifconfig thread-wpan");
List<Inet6Address> otAddresses = mOtCtl.getAddresses();
assertThat(otAddresses).isNotEmpty();
- for (Inet6Address otAddress : otAddresses) {
- assertThat(ifconfig).contains(otAddress.getHostAddress());
- }
+ // TODO: it's cleaner to have a retry() method to retry failed asserts in given delay so
+ // that we can write assertThat() in the Predicate
+ waitFor(
+ () -> {
+ String ifconfig = runShellCommand("ifconfig thread-wpan");
+ return otAddresses.stream()
+ .allMatch(addr -> ifconfig.contains(addr.getHostAddress()));
+ },
+ TUN_ADDR_UPDATE_TIMEOUT);
}
@Test
diff --git a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
index 2237e65..3efdf7d 100644
--- a/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
+++ b/thread/tests/integration/src/android/net/thread/utils/IntegrationTestUtils.java
@@ -85,7 +85,7 @@
*/
public static void waitFor(Supplier<Boolean> condition, Duration timeout)
throws TimeoutException {
- final long intervalMills = 1000;
+ final long intervalMills = 500;
final long timeoutMills = timeout.toMillis();
for (long i = 0; i < timeoutMills; i += intervalMills) {