Merge "Delete unused function" into main
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000..347e497
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,2 @@
+IndentWidth: 4
+AllowShortIfStatementsOnASingleLine: WithoutElse
diff --git a/bpf/headers/include/bpf_helpers.h b/bpf/headers/include/bpf_helpers.h
index 9d6b6f6..199661d 100644
--- a/bpf/headers/include/bpf_helpers.h
+++ b/bpf/headers/include/bpf_helpers.h
@@ -256,10 +256,11 @@
#define ABSOLUTE(x) ((x) < 0 ? -(x) : (x))
-#define DEFAULT_BPF_MAP_FLAGS(type, num_entries, mapflags) \
- ( (mapflags) | \
- ((num_entries) < 0 ? BPF_F_NO_PREALLOC : 0) | \
- (type == BPF_MAP_TYPE_LPM_TRIE ? BPF_F_NO_PREALLOC : 0) \
+#define DEFAULT_BPF_MAP_FLAGS(type, num_entries, mapflags) \
+ ( (mapflags) | \
+ ((num_entries) < 0 ? BPF_F_NO_PREALLOC : 0) | \
+ ( (type == BPF_MAP_TYPE_LPM_TRIE || \
+ type == BPF_MAP_TYPE_SK_STORAGE) ? BPF_F_NO_PREALLOC : 0) \
)
#define DEFINE_BPF_MAP_BASE(the_map, TYPE, keysize, valuesize, num_entries, \
diff --git a/bpf/loader/NetBpfLoad.cpp b/bpf/loader/NetBpfLoad.cpp
index bdc2e8c..74c37c4 100644
--- a/bpf/loader/NetBpfLoad.cpp
+++ b/bpf/loader/NetBpfLoad.cpp
@@ -1832,7 +1832,9 @@
int v = fscanf(f, "# %d %d %d %d %d #", &y, &q, &a, &b, &c);
ALOGI("detected %d of 5: %dQ%d api:%d.%d.%d", v, y, q, a, b, c);
fclose(f);
- if (v != 5 || y != 2025 || q != 2 || a != 36 || b || c) return 1;
+ if (v != 5 || y != 2025 || a != 36 || b) return 1;
+ if (q < 2 || q > 3) return 1;
+ if (c < 0 || c > 1) return 1;
}
// Ensure we can determine the Android build type.
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
index 41b58fa..a477cc8 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
@@ -32,7 +32,6 @@
import java.io.IOException;
import java.io.InputStream;
-import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.Optional;
@@ -151,13 +150,19 @@
return;
}
+ LogListUpdateStatus updateStatus;
try {
- mSignatureVerifier.setPublicKeyFrom(publicKeyUri);
- } catch (GeneralSecurityException | IOException | IllegalArgumentException e) {
+ updateStatus = mSignatureVerifier.setPublicKeyFrom(publicKeyUri);
+ } catch (IOException e) {
Log.e(TAG, "Error setting the public Key", e);
return;
}
+ if (!updateStatus.isPublicKeySet()) {
+ mLogger.logCTLogListUpdateStateChangedEvent(updateStatus);
+ return;
+ }
+
startMetadataDownload();
}
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLogger.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLogger.java
index 2a37d8f..8d13e45 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLogger.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLogger.java
@@ -36,6 +36,8 @@
UNKNOWN_STATE,
HTTP_ERROR,
LOG_LIST_INVALID,
+ PUBLIC_KEY_INVALID,
+ PUBLIC_KEY_NOT_ALLOWED,
PUBLIC_KEY_NOT_FOUND,
SIGNATURE_INVALID,
SIGNATURE_NOT_FOUND,
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLoggerImpl.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLoggerImpl.java
index f617523..12cdef3 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLoggerImpl.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyLoggerImpl.java
@@ -22,6 +22,8 @@
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_HTTP_ERROR;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_LOG_LIST_INVALID;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_NO_DISK_SPACE;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_PUBLIC_KEY_INVALID;
+import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_PUBLIC_KEY_NOT_ALLOWED;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_PUBLIC_KEY_NOT_FOUND;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_SIGNATURE_INVALID;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_SIGNATURE_NOT_FOUND;
@@ -133,6 +135,10 @@
return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_HTTP_ERROR;
case LOG_LIST_INVALID:
return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_LOG_LIST_INVALID;
+ case PUBLIC_KEY_INVALID:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_PUBLIC_KEY_INVALID;
+ case PUBLIC_KEY_NOT_ALLOWED:
+ return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_PUBLIC_KEY_NOT_ALLOWED;
case PUBLIC_KEY_NOT_FOUND:
return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_PUBLIC_KEY_NOT_FOUND;
case SIGNATURE_INVALID:
diff --git a/networksecurity/service/src/com/android/server/net/ct/LogListUpdateStatus.java b/networksecurity/service/src/com/android/server/net/ct/LogListUpdateStatus.java
index 3f9b762..df32e42 100644
--- a/networksecurity/service/src/com/android/server/net/ct/LogListUpdateStatus.java
+++ b/networksecurity/service/src/com/android/server/net/ct/LogListUpdateStatus.java
@@ -15,6 +15,8 @@
*/
package com.android.server.net.ct;
+import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.PUBLIC_KEY_INVALID;
+import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.PUBLIC_KEY_NOT_ALLOWED;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.PUBLIC_KEY_NOT_FOUND;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_INVALID;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_NOT_FOUND;
@@ -41,6 +43,11 @@
abstract Optional<Integer> downloadStatus();
+ boolean isPublicKeySet() {
+ // Check that none of the public key setting failures have been set as the state
+ return state() != PUBLIC_KEY_INVALID && state() != PUBLIC_KEY_NOT_ALLOWED;
+ }
+
boolean isSignatureVerified() {
// Check that none of the signature verification failures have been set as the state
return state() != PUBLIC_KEY_NOT_FOUND
diff --git a/networksecurity/service/src/com/android/server/net/ct/SignatureVerifier.java b/networksecurity/service/src/com/android/server/net/ct/SignatureVerifier.java
index 87a4973..22953f4 100644
--- a/networksecurity/service/src/com/android/server/net/ct/SignatureVerifier.java
+++ b/networksecurity/service/src/com/android/server/net/ct/SignatureVerifier.java
@@ -15,6 +15,8 @@
*/
package com.android.server.net.ct;
+import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.PUBLIC_KEY_INVALID;
+import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.PUBLIC_KEY_NOT_ALLOWED;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.PUBLIC_KEY_NOT_FOUND;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_INVALID;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_NOT_FOUND;
@@ -84,28 +86,35 @@
mPublicKey = Optional.empty();
}
- void setPublicKeyFrom(Uri file) throws GeneralSecurityException, IOException {
+ LogListUpdateStatus setPublicKeyFrom(Uri file) throws IOException {
try (InputStream fileStream = mContext.getContentResolver().openInputStream(file)) {
- setPublicKey(new String(fileStream.readAllBytes()));
+ return setPublicKey(new String(fileStream.readAllBytes()));
}
}
- void setPublicKey(String publicKey) throws GeneralSecurityException {
+ private LogListUpdateStatus setPublicKey(String publicKey) {
byte[] decodedPublicKey = null;
+ LogListUpdateStatus.Builder statusBuilder = LogListUpdateStatus.builder();
+
try {
decodedPublicKey = Base64.getDecoder().decode(publicKey);
- } catch (IllegalArgumentException e) {
- throw new GeneralSecurityException("Invalid public key base64 encoding", e);
- }
- setPublicKey(
+ setPublicKey(
KeyFactory.getInstance("RSA")
.generatePublic(new X509EncodedKeySpec(decodedPublicKey)));
+ } catch (IllegalArgumentException e) {
+ statusBuilder.setState(PUBLIC_KEY_INVALID);
+ Log.w(TAG, "Invalid public key base64 encoding", e);
+ } catch (GeneralSecurityException e) {
+ statusBuilder.setState(PUBLIC_KEY_NOT_ALLOWED);
+ Log.e(TAG, "Public key not in allowlist", e);
+ }
+
+ return statusBuilder.build();
}
@VisibleForTesting
void setPublicKey(PublicKey publicKey) throws GeneralSecurityException {
if (!mAllowedKeys.contains(publicKey)) {
- // TODO(b/400704086): add logging for this failure.
throw new GeneralSecurityException("Public key not in allowlist");
}
mPublicKey = Optional.of(publicKey);
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
index 956bad5..f5e3b7d 100644
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
@@ -184,6 +184,41 @@
@Test
public void
+ testDownloader_publicKeyDownloadSuccess_publicKeyNotAllowed_logsFailure()
+ throws Exception {
+ mCertificateTransparencyDownloader.startPublicKeyDownload();
+ PublicKey notAllowed = KeyPairGenerator.getInstance("RSA").generateKeyPair().getPublic();
+
+ mCertificateTransparencyDownloader.onReceive(
+ mContext, makePublicKeyDownloadCompleteIntent(writePublicKeyToFile(notAllowed)));
+
+ verify(mLogger, times(1))
+ .logCTLogListUpdateStateChangedEvent(
+ LogListUpdateStatus.builder()
+ .setState(CTLogListUpdateState.PUBLIC_KEY_NOT_ALLOWED)
+ .build());
+ }
+
+ @Test
+ public void
+ testDownloader_publicKeyDownloadSuccess_publicKeyInvalidEncoding_logsFailure()
+ throws Exception {
+ mCertificateTransparencyDownloader.startPublicKeyDownload();
+
+ mCertificateTransparencyDownloader.onReceive(
+ mContext,
+ makePublicKeyDownloadCompleteIntent(
+ writeToFile("i_am_not_a_base64_encoded_public_key".getBytes())));
+
+ verify(mLogger, times(1))
+ .logCTLogListUpdateStateChangedEvent(
+ LogListUpdateStatus.builder()
+ .setState(CTLogListUpdateState.PUBLIC_KEY_INVALID)
+ .build());
+ }
+
+ @Test
+ public void
testDownloader_publicKeyDownloadSuccess_updatePublicKeyFail_doNotStartMetadataDownload()
throws Exception {
mCertificateTransparencyDownloader.startPublicKeyDownload();
@@ -216,7 +251,7 @@
}
@Test
- public void testDownloader_publicKeyDownloadFail_logsFailure() throws Exception {
+ public void testDownloader_publicKeyDownloadFail_logsDownloadFailure() throws Exception {
mCertificateTransparencyDownloader.startPublicKeyDownload();
mCertificateTransparencyDownloader.onReceive(
diff --git a/service-t/src/com/android/server/ethernet/EthernetTracker.java b/service-t/src/com/android/server/ethernet/EthernetTracker.java
index bd4bfbd..c3749bd 100644
--- a/service-t/src/com/android/server/ethernet/EthernetTracker.java
+++ b/service-t/src/com/android/server/ethernet/EthernetTracker.java
@@ -791,8 +791,6 @@
new NetworkCapabilities.Builder(DEFAULT_CAPABILITIES);
if (isTestIface) {
builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST);
- // TODO: do not remove INTERNET capability for test networks.
- builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
}
return builder.build();
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 2c44b62..45b431f 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -5787,6 +5787,10 @@
mDeps.disableIngressRateLimit(nai.linkProperties.getInterfaceName());
}
+ // Removes the interfaces associated with the network being destroyed from the tracker.
+ for (String interfaceName : nai.linkProperties.getAllInterfaceNames()) {
+ mInterfaceTracker.removeInterface(interfaceName);
+ }
nai.setDestroyed();
nai.onNetworkDestroyed();
}
diff --git a/service/src/com/android/server/connectivity/InterfaceTracker.java b/service/src/com/android/server/connectivity/InterfaceTracker.java
index 0b4abeb..c6686af 100644
--- a/service/src/com/android/server/connectivity/InterfaceTracker.java
+++ b/service/src/com/android/server/connectivity/InterfaceTracker.java
@@ -22,6 +22,7 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.BpfNetMaps;
@@ -39,6 +40,7 @@
}
private static final String TAG = "InterfaceTracker";
private final Dependencies mDeps;
+ @GuardedBy("mInterfaceMap")
private final Map<String, Integer> mInterfaceMap;
public InterfaceTracker(final Context context) {
diff --git a/service/src/com/android/server/connectivity/NetworkNotificationManager.java b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
index fd41ee6..c5b2762 100644
--- a/service/src/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
@@ -38,6 +38,7 @@
import android.os.UserHandle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.text.BidiFormatter;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;
@@ -87,6 +88,7 @@
// The context is for the current user (system server)
private final Context mContext;
+ private final Dependencies mDependencies;
private final ConnectivityResources mResources;
private final TelephonyManager mTelephonyManager;
// The notification manager is created from a context for User.ALL, so notifications
@@ -96,7 +98,15 @@
private final SparseIntArray mNotificationTypeMap;
public NetworkNotificationManager(@NonNull final Context c, @NonNull final TelephonyManager t) {
+ this(c, t, new Dependencies());
+ }
+
+ @VisibleForTesting
+ protected NetworkNotificationManager(@NonNull final Context c,
+ @NonNull final TelephonyManager t,
+ @NonNull Dependencies dependencies) {
mContext = c;
+ mDependencies = dependencies;
mTelephonyManager = t;
mNotificationManager =
(NotificationManager) c.createContextAsUser(UserHandle.ALL, 0 /* flags */)
@@ -106,6 +116,13 @@
}
@VisibleForTesting
+ protected static class Dependencies {
+ public BidiFormatter getBidiFormatter() {
+ return BidiFormatter.getInstance();
+ }
+ }
+
+ @VisibleForTesting
protected static int approximateTransportType(NetworkAgentInfo nai) {
return nai.isVPN() ? TRANSPORT_VPN : getFirstTransportType(nai);
}
@@ -174,7 +191,7 @@
name = extraInfo;
} else {
final String ssid = WifiInfo.sanitizeSsid(nai.networkCapabilities.getSsid());
- name = ssid == null ? "" : ssid;
+ name = ssid == null ? "" : mDependencies.getBidiFormatter().unicodeWrap(ssid);
}
// Only notify for Internet-capable networks.
if (!nai.networkCapabilities.hasCapability(NET_CAPABILITY_INTERNET)) return;
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt b/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt
index 60285a8..1db5765 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ConnectivityDiagnosticsCollector.kt
@@ -36,6 +36,7 @@
import android.net.wifi.WifiManager
import android.os.Build
import android.os.ParcelFileDescriptor
+import android.os.ParcelFileDescriptor.AutoCloseInputStream
import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.SIM_STATE_UNKNOWN
import android.util.Log
@@ -46,6 +47,7 @@
import java.io.CharArrayWriter
import java.io.File
import java.io.FileReader
+import java.io.InputStream
import java.io.OutputStream
import java.io.OutputStreamWriter
import java.io.PrintWriter
@@ -438,13 +440,44 @@
* <p>The output will be collected immediately, and exported to a test artifact file when the
* test ends.
* @param cmd The command to run. Stdout of the command will be collected.
- * @param shell The shell to run the command in.
+ * @param shell The shell to run the command in, for example "sh".
+ * @param exceptionContext An exception to write a stacktrace to the dump for context.
+ */
+ @RequiresApi(Build.VERSION_CODES.S)
+ fun collectCommandOutput(
+ cmd: String,
+ shell: String,
+ exceptionContext: Throwable? = null
+ ) = collectCommandOutput(cmd, exceptionContext) { c, outputProcessor ->
+ runCommandInShell(c, shell, outputProcessor)
+ }
+
+ /**
+ * Add the output of a command to the test data dump.
+ *
+ * <p>The output will be collected immediately, and exported to a test artifact file when the
+ * test ends.
+ *
+ * <p>Note this does not support shell pipes, redirections, or quoted arguments. See the S+
+ * overload if that is needed.
+ * @param cmd The command to run. Stdout of the command will be collected.
* @param exceptionContext An exception to write a stacktrace to the dump for context.
*/
fun collectCommandOutput(
cmd: String,
- shell: String = "sh",
exceptionContext: Throwable? = null
+ ) = collectCommandOutput(cmd, exceptionContext) { c, outputProcessor ->
+ AutoCloseInputStream(
+ InstrumentationRegistry.getInstrumentation().uiAutomation.executeShellCommand(c)
+ ).use {
+ outputProcessor(it)
+ }
+ }
+
+ private fun collectCommandOutput(
+ cmd: String,
+ exceptionContext: Throwable? = null,
+ commandRunner: (String, (InputStream) -> Unit) -> Unit
) {
Log.i(TAG, "Collecting '$cmd' for test artifacts")
PrintWriter(buffer).let {
@@ -453,7 +486,7 @@
it.flush()
}
- runCommandInShell(cmd, shell) { stdout, _ ->
+ commandRunner(cmd) { stdout ->
stdout.copyTo(buffer)
}
}
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt b/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt
index fadc2ab..2b74036 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/ShellUtil.kt
@@ -19,8 +19,10 @@
package com.android.testutils
import android.app.UiAutomation
+import android.os.Build
import android.os.ParcelFileDescriptor.AutoCloseInputStream
import android.os.ParcelFileDescriptor.AutoCloseOutputStream
+import androidx.annotation.RequiresApi
import androidx.test.platform.app.InstrumentationRegistry
import java.io.InputStream
@@ -37,18 +39,17 @@
* when this function returns.
* @return Result of [outputProcessor].
*/
+@RequiresApi(Build.VERSION_CODES.S) // executeShellCommandRw is 31+
fun <T> runCommandInShell(
cmd: String,
shell: String = "sh",
- outputProcessor: (InputStream, InputStream) -> T,
+ outputProcessor: (InputStream) -> T,
): T {
- val (stdout, stdin, stderr) = InstrumentationRegistry.getInstrumentation().uiAutomation
- .executeShellCommandRwe(shell)
+ val (stdout, stdin) = InstrumentationRegistry.getInstrumentation().uiAutomation
+ .executeShellCommandRw(shell)
AutoCloseOutputStream(stdin).bufferedWriter().use { it.write(cmd) }
AutoCloseInputStream(stdout).use { outStream ->
- AutoCloseInputStream(stderr).use { errStream ->
- return outputProcessor(outStream, errStream)
- }
+ return outputProcessor(outStream)
}
}
@@ -57,10 +58,11 @@
*
* Overload of [runCommandInShell] that reads and returns stdout as String.
*/
+@RequiresApi(Build.VERSION_CODES.S)
fun runCommandInShell(
cmd: String,
shell: String = "sh",
-) = runCommandInShell(cmd, shell) { stdout, _ ->
+) = runCommandInShell(cmd, shell) { stdout ->
stdout.reader().use { it.readText() }
}
@@ -70,6 +72,7 @@
* This is generally only usable on devices on which [DeviceInfoUtils.isDebuggable] is true.
* @see runCommandInShell
*/
+@RequiresApi(Build.VERSION_CODES.S)
fun runCommandInRootShell(
cmd: String
) = runCommandInShell(cmd, shell = "su root sh")
diff --git a/tests/cts/multidevices/snippet/MdnsMultiDevicesSnippet.kt b/tests/cts/multidevices/snippet/MdnsMultiDevicesSnippet.kt
index 1b288df..1ed54a8 100644
--- a/tests/cts/multidevices/snippet/MdnsMultiDevicesSnippet.kt
+++ b/tests/cts/multidevices/snippet/MdnsMultiDevicesSnippet.kt
@@ -20,6 +20,7 @@
import android.net.nsd.NsdServiceInfo
import androidx.test.platform.app.InstrumentationRegistry
import com.android.testutils.NsdDiscoveryRecord
+import com.android.testutils.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStarted
import com.android.testutils.NsdDiscoveryRecord.DiscoveryEvent.DiscoveryStopped
import com.android.testutils.NsdRegistrationRecord
import com.android.testutils.NsdRegistrationRecord.RegistrationEvent.ServiceRegistered
@@ -58,6 +59,10 @@
@Rpc(description = "Unregister a mDns service")
fun unregisterMDnsService() {
+ if (!(registrationRecord.poll(timeoutMs = 0, pos = 0) is ServiceRegistered)) {
+ // Ignore unregistration if the service has not registered
+ return
+ }
nsdManager.unregisterService(registrationRecord)
registrationRecord.expectCallback<ServiceUnregistered>()
}
@@ -86,6 +91,10 @@
@Rpc(description = "Stop discovery")
fun stopMDnsServiceDiscovery() {
+ if (!(discoveryRecord.poll(timeoutMs = 0, pos = 0) is DiscoveryStarted)) {
+ // Ignore discovery stop if discovery has not started
+ return
+ }
nsdManager.stopServiceDiscovery(discoveryRecord)
discoveryRecord.expectCallbackEventually<DiscoveryStopped>()
}
diff --git a/tests/cts/net/api23Test/Android.bp b/tests/cts/net/api23Test/Android.bp
index 7d93c3a..c8e630f 100644
--- a/tests/cts/net/api23Test/Android.bp
+++ b/tests/cts/net/api23Test/Android.bp
@@ -57,4 +57,5 @@
],
per_testcase_directory: true,
sdk_version: "test_current",
+ host_required: ["net-tests-utils-host-common"],
}
diff --git a/tests/cts/net/api23Test/AndroidTest.xml b/tests/cts/net/api23Test/AndroidTest.xml
index fcc73f3..cc5568b 100644
--- a/tests/cts/net/api23Test/AndroidTest.xml
+++ b/tests/cts/net/api23Test/AndroidTest.xml
@@ -25,6 +25,10 @@
<option name="test-file-name" value="CtsNetApi23TestCases.apk" />
<option name="test-file-name" value="CtsNetTestAppForApi23.apk" />
</target_preparer>
+ <target_preparer class="com.android.testutils.ConnectivityTestTargetPreparer">
+ <!-- The tests require a working Wi-Fi network only -->
+ <option name="ignore-mobile-data-check" value="true" />
+ </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.net.cts.api23test" />
<option name="hidden-api-checks" value="false" />
diff --git a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
index 727db58..bcdc4c5 100644
--- a/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/NetworkNotificationManagerTest.java
@@ -27,6 +27,7 @@
import static com.android.server.connectivity.NetworkNotificationManager.NotificationType.SIGN_IN;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
@@ -61,6 +62,7 @@
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.testing.PollingCheck;
+import android.text.BidiFormatter;
import android.util.DisplayMetrics;
import android.util.Log;
import android.widget.TextView;
@@ -95,13 +97,14 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
+import java.util.Locale;
@RunWith(DevSdkIgnoreRunner.class)
@SmallTest
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
public class NetworkNotificationManagerTest {
- private static final String TEST_SSID = "Test SSID";
+ private static final String TEST_SSID = "?Test SSID+";
private static final String TEST_EXTRA_INFO = "extra";
private static final int TEST_NOTIF_ID = 101;
private static final String TEST_NOTIF_TAG = NetworkNotificationManager.tagFor(TEST_NOTIF_ID);
@@ -166,6 +169,7 @@
@Mock NetworkAgentInfo mBluetoothNai;
@Mock NetworkInfo mNetworkInfo;
@Mock NetworkInfo mEmptyNetworkInfo;
+ @Mock NetworkNotificationManager.Dependencies mDependencies;
ArgumentCaptor<Notification> mCaptor;
NetworkNotificationManager mManager;
@@ -192,6 +196,7 @@
doReturn(asUserCtx).when(mCtx).createContextAsUser(eq(UserHandle.ALL), anyInt());
doReturn(mNotificationManager).when(mCtx)
.getSystemService(eq(Context.NOTIFICATION_SERVICE));
+ doReturn(BidiFormatter.getInstance(Locale.US)).when(mDependencies).getBidiFormatter();
doReturn(TEST_EXTRA_INFO).when(mNetworkInfo).getExtraInfo();
ConnectivityResources.setResourcesContextForTest(mCtx);
doReturn(0xFF607D8B).when(mResources).getColor(anyInt(), any());
@@ -209,7 +214,7 @@
.thenReturn(transportNames);
when(mResources.getBoolean(R.bool.config_autoCancelNetworkNotifications)).thenReturn(true);
- mManager = new NetworkNotificationManager(mCtx, mTelephonyManager);
+ mManager = new NetworkNotificationManager(mCtx, mTelephonyManager, mDependencies);
}
@After
@@ -535,6 +540,26 @@
}
@Test
+ public void testNotificationText_NoInternet_WithSsid() {
+ doReturn(null).when(mNetworkInfo).getExtraInfo();
+ doNotificationTextTest(NO_INTERNET,
+ R.string.wifi_no_internet, TEST_SSID,
+ R.string.wifi_no_internet_detailed);
+ }
+
+ @Test
+ public void testNotificationText_NoInternet_WithRtlSsid() {
+ final BidiFormatter formatter = BidiFormatter.getInstance(Locale.forLanguageTag("ar"));
+ final String wrappedString = formatter.unicodeWrap(TEST_SSID);
+ doReturn(formatter).when(mDependencies).getBidiFormatter();
+ doReturn(null).when(mNetworkInfo).getExtraInfo();
+ assertNotEquals(TEST_SSID, wrappedString);
+ doNotificationTextTest(NO_INTERNET,
+ R.string.wifi_no_internet, wrappedString,
+ R.string.wifi_no_internet_detailed);
+ }
+
+ @Test
public void testNotificationText_Partial() {
doNotificationTextTest(PARTIAL_CONNECTIVITY,
R.string.network_partial_connectivity, TEST_EXTRA_INFO,
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
index efae244..2253913 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
@@ -35,14 +35,14 @@
import com.android.server.connectivity.mdns.util.MdnsUtils.truncateServiceName
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
+import java.net.DatagramPacket
+import kotlin.test.assertContentEquals
import org.junit.Assert.assertArrayEquals
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
-import java.net.DatagramPacket
-import kotlin.test.assertContentEquals
@RunWith(DevSdkIgnoreRunner::class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
@@ -178,8 +178,13 @@
val interfaceIndex = 99
val response = MdnsResponse(0 /* now */, serviceName, interfaceIndex, null /* network */)
// Set PTR record
- response.addPointerRecord(MdnsPointerRecord(serviceType.split(".").toTypedArray(),
- testElapsedRealtime, false /* cacheFlush */, ttlTime, serviceName))
+ response.addPointerRecord(MdnsPointerRecord(
+ serviceType.split(".").toTypedArray(),
+ testElapsedRealtime,
+ false /* cacheFlush */,
+ ttlTime,
+ serviceName
+ ))
// Set SRV record.
response.serviceRecord = MdnsServiceRecord(serviceName, testElapsedRealtime,
false /* cacheFlush */, ttlTime, 0 /* servicePriority */, 0 /* serviceWeight */,
@@ -189,16 +194,27 @@
testElapsedRealtime, true /* cacheFlush */, 0L /* ttlMillis */,
listOf(MdnsServiceInfo.TextEntry.fromString("somedifferent=entry")))
// Set InetAddress record.
- response.addInet4AddressRecord(MdnsInetAddressRecord(hostName.split(".").toTypedArray(),
- testElapsedRealtime, true /* cacheFlush */,
- 0L /* ttlMillis */, InetAddresses.parseNumericAddress(v4Address)))
- response.addInet6AddressRecord(MdnsInetAddressRecord(hostName.split(".").toTypedArray(),
- testElapsedRealtime, true /* cacheFlush */,
- 0L /* ttlMillis */, InetAddresses.parseNumericAddress(v6Address)))
+ response.addInet4AddressRecord(MdnsInetAddressRecord(
+ hostName.split(".").toTypedArray(),
+ testElapsedRealtime,
+ true /* cacheFlush */,
+ 0L /* ttlMillis */,
+ InetAddresses.parseNumericAddress(v4Address)
+ ))
+ response.addInet6AddressRecord(MdnsInetAddressRecord(
+ hostName.split(".").toTypedArray(),
+ testElapsedRealtime,
+ true /* cacheFlush */,
+ 0L /* ttlMillis */,
+ InetAddresses.parseNumericAddress(v6Address)
+ ))
// Convert a MdnsResponse to a MdnsServiceInfo
val serviceInfo = MdnsUtils.buildMdnsServiceInfoFromResponse(
- response, serviceType.split(".").toTypedArray(), testElapsedRealtime)
+ response,
+ serviceType.split(".").toTypedArray(),
+ testElapsedRealtime
+ )
assertEquals(serviceInstanceName, serviceInfo.serviceInstanceName)
assertArrayEquals(serviceType.split(".").toTypedArray(), serviceInfo.serviceType)
@@ -210,7 +226,6 @@
assertEquals(v6Address, serviceInfo.ipv6Addresses[0])
assertEquals(interfaceIndex, serviceInfo.interfaceIndex)
assertEquals(null, serviceInfo.network)
- assertEquals(mapOf("somedifferent" to "entry"),
- serviceInfo.attributes)
+ assertEquals(mapOf("somedifferent" to "entry"), serviceInfo.attributes)
}
}
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSInterfaceTrackerTest.kt b/tests/unit/java/com/android/server/connectivityservice/CSInterfaceTrackerTest.kt
new file mode 100644
index 0000000..b06e113
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivityservice/CSInterfaceTrackerTest.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2023 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.server.connectivityservice
+
+import android.net.IpPrefix
+import android.net.LinkAddress
+import android.net.LinkProperties
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED
+import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
+import android.net.NetworkCapabilities.TRANSPORT_VPN
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.NetworkRequest
+import android.os.Build
+import androidx.test.filters.SmallTest
+import com.android.server.CSTest
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.RecorderCallback.CallbackEntry.Lost
+import com.android.testutils.TestableNetworkCallback
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.inOrder
+import org.mockito.Mockito.verify
+
+private const val WIFI_IFNAME = "wlan0"
+
+private val wifiNc = NetworkCapabilities.Builder()
+ .addTransportType(TRANSPORT_WIFI)
+ .addCapability(NET_CAPABILITY_INTERNET)
+ .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
+ .build()
+
+private fun lp(iface: String, vararg linkAddresses: LinkAddress) = LinkProperties().apply {
+ interfaceName = iface
+ for (linkAddress in linkAddresses) {
+ addLinkAddress(linkAddress)
+ }
+}
+
+private fun nr(transport: Int) = NetworkRequest.Builder()
+ .clearCapabilities()
+ .addTransportType(transport).apply {
+ if (transport != TRANSPORT_VPN) {
+ addCapability(NET_CAPABILITY_NOT_VPN)
+ }
+ }.build()
+
+@DevSdkIgnoreRunner.MonitorThreadLeak
+@RunWith(DevSdkIgnoreRunner::class)
+@SmallTest
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+class CSInterfaceTrackerTest : CSTest() {
+ private val LOCAL_IPV6_IP_ADDRESS_PREFIX = IpPrefix("fe80::1cf1:35ff:fe8c:db87/64")
+ private val LOCAL_IPV6_LINK_ADDRESS = LinkAddress(
+ LOCAL_IPV6_IP_ADDRESS_PREFIX.getAddress(),
+ LOCAL_IPV6_IP_ADDRESS_PREFIX.getPrefixLength()
+ )
+
+ @Test
+ fun testDisconnectingNetwork_InterfaceRemoved() {
+ val nr = nr(NetworkCapabilities.TRANSPORT_WIFI)
+ val cb = TestableNetworkCallback()
+ val interfaceTrackerInorder = inOrder(interfaceTracker)
+ cm.requestNetwork(nr, cb)
+
+ // Connecting to network with IPv6 local address in LinkProperties
+ val wifiLp = lp(WIFI_IFNAME, LOCAL_IPV6_LINK_ADDRESS)
+ val wifiAgent = Agent(nc = wifiNc, lp = wifiLp)
+ wifiAgent.connect()
+ cb.expectAvailableCallbacks(wifiAgent.network, validated = false)
+ interfaceTrackerInorder.verify(interfaceTracker).addInterface(WIFI_IFNAME)
+
+ wifiAgent.disconnect()
+ cb.expect<Lost>(timeoutMs = 500) { it.network == wifiAgent.network }
+ // onLost is fired before the network is destroyed.
+ waitForIdle()
+
+ interfaceTrackerInorder.verify(interfaceTracker).removeInterface(WIFI_IFNAME)
+ }
+}
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
index 0fe61ec..5c55483 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSTest.kt
@@ -288,6 +288,8 @@
netd: INetd,
interfaceTracker: InterfaceTracker
) = this@CSTest.bpfNetMaps
+
+ override fun getInterfaceTracker(context: Context?) = this@CSTest.interfaceTracker
override fun getClatCoordinator(netd: INetd?) = this@CSTest.clatCoordinator
override fun getNetworkStack() = this@CSTest.networkStack
diff --git a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
index 5be8f49..6165afa 100644
--- a/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
+++ b/thread/tests/cts/src/android/net/thread/cts/ThreadNetworkManagerTest.java
@@ -43,6 +43,8 @@
@SmallTest
@RunWith(AndroidJUnit4.class)
public class ThreadNetworkManagerTest {
+ private static final String THREAD_NETWORK_FEATURE = "android.hardware.thread_network";
+
@Rule public DevSdkIgnoreRule mIgnoreRule = new DevSdkIgnoreRule();
private final Context mContext = ApplicationProvider.getApplicationContext();
@@ -64,7 +66,7 @@
@Test
@IgnoreUpTo(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public void getManager_hasThreadFeatureOnVOrHigher_returnsNonNull() {
- assumeTrue(mPackageManager.hasSystemFeature("android.hardware.thread_network"));
+ assumeTrue(mPackageManager.hasSystemFeature(THREAD_NETWORK_FEATURE));
assertThat(mManager).isNotNull();
}
@@ -81,8 +83,9 @@
@Test
@IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
@IgnoreAfter(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
- public void getManager_onUAndTv_returnsNonNull() {
+ public void getManager_onUAndTvWithThreadFeature_returnsNonNull() {
assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK));
+ assumeTrue(mPackageManager.hasSystemFeature(THREAD_NETWORK_FEATURE));
assertThat(mManager).isNotNull();
}