Merge "Make the MTU tests more realistic."
diff --git a/Cronet/tests/cts/Android.bp b/Cronet/tests/cts/Android.bp
index 7b440cd..22eccf9 100644
--- a/Cronet/tests/cts/Android.bp
+++ b/Cronet/tests/cts/Android.bp
@@ -69,7 +69,7 @@
libs: [
"android.test.base",
"androidx.annotation_annotation",
- "framework-tethering",
+ "framework-connectivity",
"org.apache.http.legacy",
],
lint: { test: true }
diff --git a/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java b/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
index ed86854..31990fb 100644
--- a/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
+++ b/Cronet/tests/cts/src/android/net/http/cts/HttpEngineTest.java
@@ -222,29 +222,16 @@
@Test
public void testHttpEngine_EnableQuic() throws Exception {
+ String url = mTestServer.getSuccessUrl();
mEngine = mEngineBuilder.setEnableQuic(true).addQuicHint(HOST, 443, 443).build();
- // The hint doesn't guarantee that QUIC will win the race, just that it will race TCP.
- // We send multiple requests to reduce the flakiness of the test.
- boolean quicWasUsed = false;
- for (int i = 0; i < 5; i++) {
- mCallback = new TestUrlRequestCallback();
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
+ UrlRequest.Builder builder =
+ mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
+ mRequest = builder.build();
+ mRequest.start();
- // This tests uses a non-hermetic server. Instead of asserting, assume the next
- // callback. This way, if the request were to fail, the test would just be skipped
- // instead of failing.
- mCallback.assumeCallback(ResponseStep.ON_SUCCEEDED);
- UrlResponseInfo info = mCallback.mResponseInfo;
- assumeOKStatusCode(info);
- quicWasUsed = isQuic(info.getNegotiatedProtocol());
- if (quicWasUsed) {
- break;
- }
- }
- assertTrue(quicWasUsed);
+ mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+ UrlResponseInfo info = mCallback.mResponseInfo;
+ assertOKStatusCode(info);
}
@Test
@@ -379,34 +366,22 @@
@Test
public void testHttpEngine_SetQuicOptions_RequestSucceedsWithQuic() throws Exception {
+ String url = mTestServer.getSuccessUrl();
QuicOptions options = new QuicOptions.Builder().build();
mEngine = mEngineBuilder
.setEnableQuic(true)
.addQuicHint(HOST, 443, 443)
.setQuicOptions(options)
.build();
+ UrlRequest.Builder builder =
+ mEngine.newUrlRequestBuilder(url, mCallback.getExecutor(), mCallback);
+ mRequest = builder.build();
+ mRequest.start();
- // The hint doesn't guarantee that QUIC will win the race, just that it will race TCP.
- // We send multiple requests to reduce the flakiness of the test.
- boolean quicWasUsed = false;
- for (int i = 0; i < 5; i++) {
- mCallback = new TestUrlRequestCallback();
- UrlRequest.Builder builder =
- mEngine.newUrlRequestBuilder(URL, mCallback.getExecutor(), mCallback);
- mRequest = builder.build();
- mRequest.start();
- mCallback.blockForDone();
+ mCallback.expectCallback(ResponseStep.ON_SUCCEEDED);
+ UrlResponseInfo info = mCallback.mResponseInfo;
+ assertOKStatusCode(info);
- quicWasUsed = isQuic(mCallback.mResponseInfo.getNegotiatedProtocol());
- if (quicWasUsed) {
- break;
- }
- }
-
- assertTrue(quicWasUsed);
- // This tests uses a non-hermetic server. Instead of asserting, assume the next callback.
- // This way, if the request were to fail, the test would just be skipped instead of failing.
- assumeOKStatusCode(mCallback.mResponseInfo);
}
@Test
diff --git a/Cronet/tests/mts/Android.bp b/Cronet/tests/mts/Android.bp
index 8fec6f3..ecf4b7f 100644
--- a/Cronet/tests/mts/Android.bp
+++ b/Cronet/tests/mts/Android.bp
@@ -19,6 +19,7 @@
java_genrule {
name: "net-http-test-jarjar-rules",
+ defaults: ["CronetTestJavaDefaults"],
tool_files: [
":NetHttpTestsLibPreJarJar{.jar}",
"jarjar_excludes.txt",
@@ -29,13 +30,14 @@
out: ["net_http_test_jarjar_rules.txt"],
cmd: "$(location jarjar-rules-generator) " +
"$(location :NetHttpTestsLibPreJarJar{.jar}) " +
- "--prefix android.net.http.internal " +
+ "--prefix android.net.connectivity " +
"--excludes $(location jarjar_excludes.txt) " +
"--output $(out)",
}
android_library {
name: "NetHttpTestsLibPreJarJar",
+ defaults: ["CronetTestJavaDefaults"],
srcs: [":cronet_aml_javatests_sources"],
sdk_version: "module_current",
min_sdk_version: "30",
@@ -47,11 +49,7 @@
],
libs: [
"android.test.base",
- // Needed for direct access to tethering's hidden apis and to avoid `symbol not found`
- // errors on some builds.
- "framework-tethering.impl",
- // android.net.Network apis
- "framework-connectivity",
+ "framework-connectivity-pre-jarjar",
// android.net.TrafficStats apis
"framework-connectivity-t",
],
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 4c50bee..d2f6d6a 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -97,7 +97,13 @@
},
// Runs both NetHttpTests and CtsNetHttpTestCases
{
- "name": "NetHttpCoverageTests"
+ "name": "NetHttpCoverageTests",
+ "options": [
+ {
+ // These sometimes take longer than 1 min which is the presubmit timeout
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
}
],
"postsubmit": [
@@ -211,7 +217,13 @@
"name": "libnetworkstats_test[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
},
{
- "name": "NetHttpCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]"
+ "name": "NetHttpCoverageTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
+ "options": [
+ {
+ // These sometimes take longer than 1 min which is the presubmit timeout
+ "exclude-annotation": "androidx.test.filters.LargeTest"
+ }
+ ]
}
],
"mainline-postsubmit": [
diff --git a/Tethering/Android.bp b/Tethering/Android.bp
index 8810a8c..83ca2b7 100644
--- a/Tethering/Android.bp
+++ b/Tethering/Android.bp
@@ -250,6 +250,9 @@
// e.g. *classpath_fragments.
"com.android.tethering",
],
+ native_shared_libs: [
+ "libnetd_updatable",
+ ],
}
java_library_static {
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 3f35c6b..d84fef3 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -242,7 +242,6 @@
"android.net.apf",
"android.net.connectivity",
"android.net.http.apihelpers",
- "android.net.http.internal",
"android.net.netstats.provider",
"android.net.nsd",
"android.net.wear",
diff --git a/Tethering/common/TetheringLib/Android.bp b/Tethering/common/TetheringLib/Android.bp
index 74170cb..6b62da9 100644
--- a/Tethering/common/TetheringLib/Android.bp
+++ b/Tethering/common/TetheringLib/Android.bp
@@ -30,7 +30,6 @@
java_sdk_library {
name: "framework-tethering",
defaults: [
- "CronetJavaDefaults",
"framework-tethering-defaults",
],
impl_library_visibility: [
@@ -54,7 +53,6 @@
"//packages/modules/CaptivePortalLogin/tests",
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
"//packages/modules/Connectivity/tests:__subpackages__",
- "//packages/modules/Connectivity/Cronet/tests:__subpackages__",
"//packages/modules/IPsec/tests/iketests",
"//packages/modules/NetworkStack/tests:__subpackages__",
"//packages/modules/Wifi/service/tests/wifitests",
@@ -83,11 +81,11 @@
impl_only_static_libs: [
"cronet_aml_java",
],
- api_dir: "cronet_enabled/api",
}
java_defaults {
name: "CronetJavaDefaultsDisabled",
+ api_dir: "cronet_disabled/api",
}
java_defaults {
@@ -111,7 +109,6 @@
name: "framework-tethering-pre-jarjar",
defaults: [
"framework-tethering-defaults",
- "CronetJavaPrejarjarDefaults",
],
}
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/current.txt b/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
deleted file mode 100644
index 333ea1c..0000000
--- a/Tethering/common/TetheringLib/cronet_enabled/api/current.txt
+++ /dev/null
@@ -1,290 +0,0 @@
-// Signature format: 2.0
-package android.net.http {
-
- public abstract class BidirectionalStream {
- ctor public BidirectionalStream();
- method public abstract void cancel();
- method public abstract void flush();
- method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
- method @NonNull public abstract String getHttpMethod();
- method public abstract int getPriority();
- method public abstract int getTrafficStatsTag();
- method public abstract int getTrafficStatsUid();
- method public abstract boolean hasTrafficStatsTag();
- method public abstract boolean hasTrafficStatsUid();
- method public abstract boolean isDelayRequestHeadersUntilFirstFlushEnabled();
- method public abstract boolean isDone();
- method public abstract void read(@NonNull java.nio.ByteBuffer);
- method public abstract void start();
- method public abstract void write(@NonNull java.nio.ByteBuffer, boolean);
- field public static final int STREAM_PRIORITY_HIGHEST = 4; // 0x4
- field public static final int STREAM_PRIORITY_IDLE = 0; // 0x0
- field public static final int STREAM_PRIORITY_LOW = 2; // 0x2
- field public static final int STREAM_PRIORITY_LOWEST = 1; // 0x1
- field public static final int STREAM_PRIORITY_MEDIUM = 3; // 0x3
- }
-
- public abstract static class BidirectionalStream.Builder {
- ctor public BidirectionalStream.Builder();
- method @NonNull public abstract android.net.http.BidirectionalStream.Builder addHeader(@NonNull String, @NonNull String);
- method @NonNull public abstract android.net.http.BidirectionalStream build();
- method @NonNull public abstract android.net.http.BidirectionalStream.Builder setDelayRequestHeadersUntilFirstFlushEnabled(boolean);
- method @NonNull public abstract android.net.http.BidirectionalStream.Builder setHttpMethod(@NonNull String);
- method @NonNull public abstract android.net.http.BidirectionalStream.Builder setPriority(int);
- method @NonNull public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsTag(int);
- method @NonNull public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsUid(int);
- }
-
- public static interface BidirectionalStream.Callback {
- method public void onCanceled(@NonNull android.net.http.BidirectionalStream, @Nullable android.net.http.UrlResponseInfo);
- method public void onFailed(@NonNull android.net.http.BidirectionalStream, @Nullable android.net.http.UrlResponseInfo, @NonNull android.net.http.HttpException);
- method public void onReadCompleted(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer, boolean);
- method public void onResponseHeadersReceived(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo);
- method public void onResponseTrailersReceived(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull android.net.http.HeaderBlock);
- method public void onStreamReady(@NonNull android.net.http.BidirectionalStream);
- method public void onSucceeded(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo);
- method public void onWriteCompleted(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer, boolean);
- }
-
- public abstract class CallbackException extends android.net.http.HttpException {
- ctor protected CallbackException(@Nullable String, @Nullable Throwable);
- }
-
- public class ConnectionMigrationOptions {
- method public int getAllowNonDefaultNetworkUsage();
- method public int getDefaultNetworkMigration();
- method public int getPathDegradationMigration();
- field public static final int MIGRATION_OPTION_DISABLED = 2; // 0x2
- field public static final int MIGRATION_OPTION_ENABLED = 1; // 0x1
- field public static final int MIGRATION_OPTION_UNSPECIFIED = 0; // 0x0
- }
-
- public static final class ConnectionMigrationOptions.Builder {
- ctor public ConnectionMigrationOptions.Builder();
- method @NonNull public android.net.http.ConnectionMigrationOptions build();
- method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setAllowNonDefaultNetworkUsage(int);
- method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setDefaultNetworkMigration(int);
- method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setPathDegradationMigration(int);
- }
-
- public final class DnsOptions {
- method public int getPersistHostCache();
- method @Nullable public java.time.Duration getPersistHostCachePeriod();
- method public int getPreestablishConnectionsToStaleDnsResults();
- method public int getStaleDns();
- method @Nullable public android.net.http.DnsOptions.StaleDnsOptions getStaleDnsOptions();
- method public int getUseHttpStackDnsResolver();
- field public static final int DNS_OPTION_DISABLED = 2; // 0x2
- field public static final int DNS_OPTION_ENABLED = 1; // 0x1
- field public static final int DNS_OPTION_UNSPECIFIED = 0; // 0x0
- }
-
- public static final class DnsOptions.Builder {
- ctor public DnsOptions.Builder();
- method @NonNull public android.net.http.DnsOptions build();
- method @NonNull public android.net.http.DnsOptions.Builder setPersistHostCache(int);
- method @NonNull public android.net.http.DnsOptions.Builder setPersistHostCachePeriod(@NonNull java.time.Duration);
- method @NonNull public android.net.http.DnsOptions.Builder setPreestablishConnectionsToStaleDnsResults(int);
- method @NonNull public android.net.http.DnsOptions.Builder setStaleDns(int);
- method @NonNull public android.net.http.DnsOptions.Builder setStaleDnsOptions(@NonNull android.net.http.DnsOptions.StaleDnsOptions);
- method @NonNull public android.net.http.DnsOptions.Builder setUseHttpStackDnsResolver(int);
- }
-
- public static class DnsOptions.StaleDnsOptions {
- method public int getAllowCrossNetworkUsage();
- method @Nullable public java.time.Duration getFreshLookupTimeout();
- method @Nullable public java.time.Duration getMaxExpiredDelay();
- method public int getUseStaleOnNameNotResolved();
- }
-
- public static final class DnsOptions.StaleDnsOptions.Builder {
- ctor public DnsOptions.StaleDnsOptions.Builder();
- method @NonNull public android.net.http.DnsOptions.StaleDnsOptions build();
- method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setAllowCrossNetworkUsage(int);
- method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setFreshLookupTimeout(@NonNull java.time.Duration);
- method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setMaxExpiredDelay(@NonNull java.time.Duration);
- method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setUseStaleOnNameNotResolved(int);
- }
-
- public abstract class HeaderBlock {
- ctor public HeaderBlock();
- method @NonNull public abstract java.util.List<java.util.Map.Entry<java.lang.String,java.lang.String>> getAsList();
- method @NonNull public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> getAsMap();
- }
-
- public abstract class HttpEngine {
- method public void bindToNetwork(@Nullable android.net.Network);
- method @NonNull public abstract java.net.URLStreamHandlerFactory createUrlStreamHandlerFactory();
- method @NonNull public static String getVersionString();
- method @NonNull public abstract android.net.http.BidirectionalStream.Builder newBidirectionalStreamBuilder(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.http.BidirectionalStream.Callback);
- method @NonNull public abstract android.net.http.UrlRequest.Builder newUrlRequestBuilder(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.http.UrlRequest.Callback);
- method @NonNull public abstract java.net.URLConnection openConnection(@NonNull java.net.URL) throws java.io.IOException;
- method public abstract void shutdown();
- }
-
- public static class HttpEngine.Builder {
- ctor public HttpEngine.Builder(@NonNull android.content.Context);
- method @NonNull public android.net.http.HttpEngine.Builder addPublicKeyPins(@NonNull String, @NonNull java.util.Set<byte[]>, boolean, @NonNull java.time.Instant);
- method @NonNull public android.net.http.HttpEngine.Builder addQuicHint(@NonNull String, int, int);
- method @NonNull public android.net.http.HttpEngine build();
- method @NonNull public String getDefaultUserAgent();
- method @NonNull public android.net.http.HttpEngine.Builder setConnectionMigrationOptions(@NonNull android.net.http.ConnectionMigrationOptions);
- method @NonNull public android.net.http.HttpEngine.Builder setDnsOptions(@NonNull android.net.http.DnsOptions);
- method @NonNull public android.net.http.HttpEngine.Builder setEnableBrotli(boolean);
- method @NonNull public android.net.http.HttpEngine.Builder setEnableHttp2(boolean);
- method @NonNull public android.net.http.HttpEngine.Builder setEnableHttpCache(int, long);
- method @NonNull public android.net.http.HttpEngine.Builder setEnablePublicKeyPinningBypassForLocalTrustAnchors(boolean);
- method @NonNull public android.net.http.HttpEngine.Builder setEnableQuic(boolean);
- method @NonNull public android.net.http.HttpEngine.Builder setQuicOptions(@NonNull android.net.http.QuicOptions);
- method @NonNull public android.net.http.HttpEngine.Builder setStoragePath(@NonNull String);
- method @NonNull public android.net.http.HttpEngine.Builder setUserAgent(@NonNull String);
- field public static final int HTTP_CACHE_DISABLED = 0; // 0x0
- field public static final int HTTP_CACHE_DISK = 3; // 0x3
- field public static final int HTTP_CACHE_DISK_NO_HTTP = 2; // 0x2
- field public static final int HTTP_CACHE_IN_MEMORY = 1; // 0x1
- }
-
- public class HttpException extends java.io.IOException {
- ctor public HttpException(@Nullable String, @Nullable Throwable);
- }
-
- public final class InlineExecutionProhibitedException extends java.util.concurrent.RejectedExecutionException {
- ctor public InlineExecutionProhibitedException();
- }
-
- public abstract class NetworkException extends android.net.http.HttpException {
- ctor public NetworkException(@Nullable String, @Nullable Throwable);
- method public abstract int getErrorCode();
- method public abstract boolean isImmediatelyRetryable();
- field public static final int ERROR_ADDRESS_UNREACHABLE = 9; // 0x9
- field public static final int ERROR_CONNECTION_CLOSED = 5; // 0x5
- field public static final int ERROR_CONNECTION_REFUSED = 7; // 0x7
- field public static final int ERROR_CONNECTION_RESET = 8; // 0x8
- field public static final int ERROR_CONNECTION_TIMED_OUT = 6; // 0x6
- field public static final int ERROR_HOSTNAME_NOT_RESOLVED = 1; // 0x1
- field public static final int ERROR_INTERNET_DISCONNECTED = 2; // 0x2
- field public static final int ERROR_NETWORK_CHANGED = 3; // 0x3
- field public static final int ERROR_OTHER = 11; // 0xb
- field public static final int ERROR_QUIC_PROTOCOL_FAILED = 10; // 0xa
- field public static final int ERROR_TIMED_OUT = 4; // 0x4
- }
-
- public abstract class QuicException extends android.net.http.NetworkException {
- ctor protected QuicException(@Nullable String, @Nullable Throwable);
- }
-
- public class QuicOptions {
- method @NonNull public java.util.Set<java.lang.String> getAllowedQuicHosts();
- method @Nullable public String getHandshakeUserAgent();
- method @Nullable public java.time.Duration getIdleConnectionTimeout();
- method public int getInMemoryServerConfigsCacheSize();
- method public boolean hasInMemoryServerConfigsCacheSize();
- }
-
- public static final class QuicOptions.Builder {
- ctor public QuicOptions.Builder();
- method @NonNull public android.net.http.QuicOptions.Builder addAllowedQuicHost(@NonNull String);
- method @NonNull public android.net.http.QuicOptions build();
- method @NonNull public android.net.http.QuicOptions.Builder setHandshakeUserAgent(@NonNull String);
- method @NonNull public android.net.http.QuicOptions.Builder setIdleConnectionTimeout(@NonNull java.time.Duration);
- method @NonNull public android.net.http.QuicOptions.Builder setInMemoryServerConfigsCacheSize(int);
- }
-
- public abstract class UploadDataProvider implements java.io.Closeable {
- ctor public UploadDataProvider();
- method public void close() throws java.io.IOException;
- method public abstract long getLength() throws java.io.IOException;
- method public abstract void read(@NonNull android.net.http.UploadDataSink, @NonNull java.nio.ByteBuffer) throws java.io.IOException;
- method public abstract void rewind(@NonNull android.net.http.UploadDataSink) throws java.io.IOException;
- }
-
- public abstract class UploadDataSink {
- ctor public UploadDataSink();
- method public abstract void onReadError(@NonNull Exception);
- method public abstract void onReadSucceeded(boolean);
- method public abstract void onRewindError(@NonNull Exception);
- method public abstract void onRewindSucceeded();
- }
-
- public abstract class UrlRequest {
- method public abstract void cancel();
- method public abstract void followRedirect();
- method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
- method @Nullable public abstract String getHttpMethod();
- method public abstract int getPriority();
- method public abstract void getStatus(@NonNull android.net.http.UrlRequest.StatusListener);
- method public abstract int getTrafficStatsTag();
- method public abstract int getTrafficStatsUid();
- method public abstract boolean hasTrafficStatsTag();
- method public abstract boolean hasTrafficStatsUid();
- method public abstract boolean isCacheDisabled();
- method public abstract boolean isDirectExecutorAllowed();
- method public abstract boolean isDone();
- method public abstract void read(@NonNull java.nio.ByteBuffer);
- method public abstract void start();
- field public static final int REQUEST_PRIORITY_HIGHEST = 4; // 0x4
- field public static final int REQUEST_PRIORITY_IDLE = 0; // 0x0
- field public static final int REQUEST_PRIORITY_LOW = 2; // 0x2
- field public static final int REQUEST_PRIORITY_LOWEST = 1; // 0x1
- field public static final int REQUEST_PRIORITY_MEDIUM = 3; // 0x3
- }
-
- public abstract static class UrlRequest.Builder {
- method @NonNull public abstract android.net.http.UrlRequest.Builder addHeader(@NonNull String, @NonNull String);
- method @NonNull public abstract android.net.http.UrlRequest.Builder bindToNetwork(@Nullable android.net.Network);
- method @NonNull public abstract android.net.http.UrlRequest build();
- method @NonNull public abstract android.net.http.UrlRequest.Builder setCacheDisabled(boolean);
- method @NonNull public abstract android.net.http.UrlRequest.Builder setDirectExecutorAllowed(boolean);
- method @NonNull public abstract android.net.http.UrlRequest.Builder setHttpMethod(@NonNull String);
- method @NonNull public abstract android.net.http.UrlRequest.Builder setPriority(int);
- method @NonNull public abstract android.net.http.UrlRequest.Builder setTrafficStatsTag(int);
- method @NonNull public abstract android.net.http.UrlRequest.Builder setTrafficStatsUid(int);
- method @NonNull public abstract android.net.http.UrlRequest.Builder setUploadDataProvider(@NonNull android.net.http.UploadDataProvider, @NonNull java.util.concurrent.Executor);
- }
-
- public static interface UrlRequest.Callback {
- method public void onCanceled(@NonNull android.net.http.UrlRequest, @Nullable android.net.http.UrlResponseInfo);
- method public void onFailed(@NonNull android.net.http.UrlRequest, @Nullable android.net.http.UrlResponseInfo, @NonNull android.net.http.HttpException);
- method public void onReadCompleted(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer) throws java.lang.Exception;
- method public void onRedirectReceived(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo, @NonNull String) throws java.lang.Exception;
- method public void onResponseStarted(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo) throws java.lang.Exception;
- method public void onSucceeded(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo);
- }
-
- public static class UrlRequest.Status {
- field public static final int CONNECTING = 10; // 0xa
- field public static final int DOWNLOADING_PAC_FILE = 5; // 0x5
- field public static final int ESTABLISHING_PROXY_TUNNEL = 8; // 0x8
- field public static final int IDLE = 0; // 0x0
- field public static final int INVALID = -1; // 0xffffffff
- field public static final int READING_RESPONSE = 14; // 0xe
- field public static final int RESOLVING_HOST = 9; // 0x9
- field public static final int RESOLVING_HOST_IN_PAC_FILE = 7; // 0x7
- field public static final int RESOLVING_PROXY_FOR_URL = 6; // 0x6
- field public static final int SENDING_REQUEST = 12; // 0xc
- field public static final int SSL_HANDSHAKE = 11; // 0xb
- field public static final int WAITING_FOR_AVAILABLE_SOCKET = 2; // 0x2
- field public static final int WAITING_FOR_CACHE = 4; // 0x4
- field public static final int WAITING_FOR_DELEGATE = 3; // 0x3
- field public static final int WAITING_FOR_RESPONSE = 13; // 0xd
- field public static final int WAITING_FOR_STALLED_SOCKET_POOL = 1; // 0x1
- }
-
- public static interface UrlRequest.StatusListener {
- method public void onStatus(int);
- }
-
- public abstract class UrlResponseInfo {
- ctor public UrlResponseInfo();
- method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
- method public abstract int getHttpStatusCode();
- method @NonNull public abstract String getHttpStatusText();
- method @NonNull public abstract String getNegotiatedProtocol();
- method public abstract long getReceivedByteCount();
- method @NonNull public abstract String getUrl();
- method @NonNull public abstract java.util.List<java.lang.String> getUrlChain();
- method public abstract boolean wasCached();
- }
-
-}
-
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/module-lib-current.txt b/Tethering/common/TetheringLib/cronet_enabled/api/module-lib-current.txt
deleted file mode 100644
index 460c216..0000000
--- a/Tethering/common/TetheringLib/cronet_enabled/api/module-lib-current.txt
+++ /dev/null
@@ -1,50 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public final class TetheringConstants {
- field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
- field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
- field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
- field public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
- field public static final String EXTRA_SET_ALARM = "extraSetAlarm";
- }
-
- public class TetheringManager {
- ctor public TetheringManager(@NonNull android.content.Context, @NonNull java.util.function.Supplier<android.os.IBinder>);
- method public int getLastTetherError(@NonNull String);
- method @NonNull public String[] getTetherableBluetoothRegexs();
- method @NonNull public String[] getTetherableIfaces();
- method @NonNull public String[] getTetherableUsbRegexs();
- method @NonNull public String[] getTetherableWifiRegexs();
- method @NonNull public String[] getTetheredIfaces();
- method @NonNull public String[] getTetheringErroredIfaces();
- method public boolean isTetheringSupported();
- method public boolean isTetheringSupported(@NonNull String);
- method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
- method @Deprecated public int setUsbTethering(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @Deprecated public int tether(@NonNull String);
- method @Deprecated public int untether(@NonNull String);
- }
-
- public static interface TetheringManager.TetheredInterfaceCallback {
- method public void onAvailable(@NonNull String);
- method public void onUnavailable();
- }
-
- public static interface TetheringManager.TetheredInterfaceRequest {
- method public void release();
- }
-
- public static interface TetheringManager.TetheringEventCallback {
- method @Deprecated public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
- }
-
- @Deprecated public static class TetheringManager.TetheringInterfaceRegexps {
- method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableBluetoothRegexs();
- method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableUsbRegexs();
- method @Deprecated @NonNull public java.util.List<java.lang.String> getTetherableWifiRegexs();
- }
-
-}
-
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/removed.txt b/Tethering/common/TetheringLib/cronet_enabled/api/removed.txt
deleted file mode 100644
index d802177..0000000
--- a/Tethering/common/TetheringLib/cronet_enabled/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/system-current.txt b/Tethering/common/TetheringLib/cronet_enabled/api/system-current.txt
deleted file mode 100644
index 844ff64..0000000
--- a/Tethering/common/TetheringLib/cronet_enabled/api/system-current.txt
+++ /dev/null
@@ -1,117 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public final class TetheredClient implements android.os.Parcelable {
- ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection<android.net.TetheredClient.AddressInfo>, int);
- method public int describeContents();
- method @NonNull public java.util.List<android.net.TetheredClient.AddressInfo> getAddresses();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public int getTetheringType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient> CREATOR;
- }
-
- public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.LinkAddress getAddress();
- method @Nullable public String getHostname();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheredClient.AddressInfo> CREATOR;
- }
-
- public final class TetheringInterface implements android.os.Parcelable {
- ctor public TetheringInterface(int, @NonNull String);
- method public int describeContents();
- method @NonNull public String getInterface();
- method public int getType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator<android.net.TetheringInterface> CREATOR;
- }
-
- public class TetheringManager {
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
- field @Deprecated public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
- field public static final int CONNECTIVITY_SCOPE_GLOBAL = 1; // 0x1
- field public static final int CONNECTIVITY_SCOPE_LOCAL = 2; // 0x2
- field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
- field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
- field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
- field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_ETHERNET = 5; // 0x5
- field public static final int TETHERING_INVALID = -1; // 0xffffffff
- field public static final int TETHERING_NCM = 4; // 0x4
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHERING_WIFI_P2P = 3; // 0x3
- field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
- field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
- field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
- field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
- field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
- field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
- field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
- field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
- field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
- field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
- field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
- field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
- field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
- field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
- field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
- field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
- field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
- }
-
- public static interface TetheringManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
- }
-
- public static interface TetheringManager.StartTetheringCallback {
- method public default void onTetheringFailed(int);
- method public default void onTetheringStarted();
- }
-
- public static interface TetheringManager.TetheringEventCallback {
- method public default void onClientsChanged(@NonNull java.util.Collection<android.net.TetheredClient>);
- method public default void onError(@NonNull String, int);
- method public default void onError(@NonNull android.net.TetheringInterface, int);
- method public default void onLocalOnlyInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onLocalOnlyInterfacesChanged(@NonNull java.util.Set<android.net.TetheringInterface>);
- method public default void onOffloadStatusChanged(int);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.Set<android.net.TetheringInterface>);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.List<java.lang.String>);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.Set<android.net.TetheringInterface>);
- method public default void onTetheringSupported(boolean);
- method public default void onUpstreamChanged(@Nullable android.net.Network);
- }
-
- public static class TetheringManager.TetheringRequest {
- method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
- method public int getConnectivityScope();
- method @Nullable public android.net.LinkAddress getLocalIpv4Address();
- method public boolean getShouldShowEntitlementUi();
- method public int getTetheringType();
- method public boolean isExemptFromEntitlementCheck();
- }
-
- public static class TetheringManager.TetheringRequest.Builder {
- ctor public TetheringManager.TetheringRequest.Builder(int);
- method @NonNull public android.net.TetheringManager.TetheringRequest build();
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setConnectivityScope(int);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
- }
-
-}
-
diff --git a/Tethering/jni/com_android_networkstack_tethering_util_TetheringUtils.cpp b/Tethering/jni/com_android_networkstack_tethering_util_TetheringUtils.cpp
index a878fa5..14e4b9a 100644
--- a/Tethering/jni/com_android_networkstack_tethering_util_TetheringUtils.cpp
+++ b/Tethering/jni/com_android_networkstack_tethering_util_TetheringUtils.cpp
@@ -18,21 +18,19 @@
#include <error.h>
#include <jni.h>
#include <linux/filter.h>
+#include <linux/ipv6.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
#include <netjniutils/netjniutils.h>
#include <net/if.h>
#include <netinet/ether.h>
-#include <netinet/ip6.h>
#include <netinet/icmp6.h>
#include <sys/socket.h>
#include <stdio.h>
-namespace android {
+#include <bpf/BpfClassic.h>
-static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt);
-static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr);
-static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
+namespace android {
static void throwSocketException(JNIEnv *env, const char* msg, int error) {
jniThrowExceptionFmt(env, "java/net/SocketException", "%s: %s", msg, strerror(error));
@@ -42,18 +40,14 @@
uint32_t type) {
sock_filter filter_code[] = {
// Check header is ICMPv6.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeaderOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
+ BPF_LOAD_IPV6_U8(nexthdr),
+ BPF2_REJECT_IF_NOT_EQUAL(IPPROTO_ICMPV6),
// Check ICMPv6 type.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, type, 0, 1),
+ BPF_LOAD_NET_RELATIVE_U8(sizeof(ipv6hdr) + offsetof(icmp6_hdr, icmp6_type)),
+ BPF2_REJECT_IF_NOT_EQUAL(type),
- // Accept.
- BPF_STMT(BPF_RET | BPF_K, 0xffff),
-
- // Reject.
- BPF_STMT(BPF_RET | BPF_K, 0)
+ BPF_ACCEPT,
};
const sock_fprog filter = {
diff --git a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
index 775c36f..18c2171 100644
--- a/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ b/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
@@ -129,9 +129,6 @@
// Tethered traffic will have the hop limit properly decremented.
// Consequently, set the hoplimit greater by one than the upstream
// unicast hop limit.
- //
- // TODO: Dynamically pass down the IPV6_UNICAST_HOPS value from the
- // upstream interface for more correct behaviour.
static final byte DEFAULT_HOPLIMIT = 65;
public boolean hasDefaultRoute;
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/Tethering/src/com/android/networkstack/tethering/OffloadController.java
index 5fa6b2d..b4c0d6a 100644
--- a/Tethering/src/com/android/networkstack/tethering/OffloadController.java
+++ b/Tethering/src/com/android/networkstack/tethering/OffloadController.java
@@ -762,6 +762,16 @@
String upstream = (lp != null) ? lp.getInterfaceName() : null;
pw.println("Current upstream: " + upstream);
pw.println("Exempt prefixes: " + mLastLocalPrefixStrs);
+ pw.println("ForwardedStats:");
+ pw.increaseIndent();
+ if (mForwardedStats.isEmpty()) {
+ pw.println("<empty>");
+ } else {
+ for (final Map.Entry<String, ForwardedStats> kv : mForwardedStats.entrySet()) {
+ pw.println(kv.getKey() + ": " + kv.getValue());
+ }
+ }
+ pw.decreaseIndent();
pw.println("NAT timeout update callbacks received during the "
+ (isStarted ? "current" : "last")
+ " offload session: "
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java b/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java
index 3e02543..e0a9878 100644
--- a/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java
+++ b/Tethering/src/com/android/networkstack/tethering/OffloadHalHidlImpl.java
@@ -288,9 +288,12 @@
IOffloadConfig config = null;
try {
config = IOffloadConfig.getService(true /*retry*/);
- } catch (RemoteException | NoSuchElementException e) {
+ } catch (RemoteException e) {
log.e("getIOffloadConfig error " + e);
return null;
+ } catch (NoSuchElementException e) {
+ log.i("getIOffloadConfig Tether Offload HAL not present/implemented");
+ return null;
}
IOffloadControl control = null;
diff --git a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
index ea20063..de15c5b 100644
--- a/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ b/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
@@ -307,7 +307,7 @@
if (mIOffload == null) {
mIOffload = mDeps.getOffload();
if (mIOffload == null) {
- mLog.e("No tethering offload HAL service found.");
+ mLog.i("No tethering offload HAL service found.");
return OFFLOAD_HAL_VERSION_NONE;
}
mLog.i("Tethering offload version "
diff --git a/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java b/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java
index c181994..814afcd 100644
--- a/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java
+++ b/Tethering/src/com/android/networkstack/tethering/metrics/TetheringMetrics.java
@@ -20,7 +20,6 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_LOWPAN;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
@@ -160,27 +159,20 @@
}
/**
- * Returns the greater of two start times.
- * @param first the first start time
- * @param second the second start time
- * @return the greater start time
- */
- private long getGreaterStartTime(long first, long second) {
- return first > second ? first : second;
- }
-
- /**
* Updates the upstream events builder with a new upstream event.
* @param upstreamEventsBuilder the builder for the upstream events list
* @param start the start time of the upstream event
* @param stop the stop time of the upstream event
* @param upstream the type of upstream type (e.g. Wifi, Cellular, Bluetooth, ...)
*/
- private void updateUpstreamEvents(final UpstreamEvents.Builder upstreamEventsBuilder,
- final long start, final long stop, @Nullable final UpstreamType upstream) {
+ private void addUpstreamEvent(final UpstreamEvents.Builder upstreamEventsBuilder,
+ final long start, final long stop, @Nullable final UpstreamType upstream,
+ final long txBytes, final long rxBytes) {
final UpstreamEvent.Builder upstreamEventBuilder = UpstreamEvent.newBuilder()
.setUpstreamType(upstream == null ? UpstreamType.UT_NO_NETWORK : upstream)
- .setDurationMillis(stop - start);
+ .setDurationMillis(stop - start)
+ .setTxBytes(txBytes)
+ .setRxBytes(rxBytes);
upstreamEventsBuilder.addUpstreamEvent(upstreamEventBuilder);
}
@@ -201,21 +193,23 @@
* @param downstreamStartTime the start time of the downstream event to find relevant upstream
* events for
*/
- private void updateStatsBuilderToWrite(final NetworkTetheringReported.Builder statsBuilder,
+ private void noteDownstreamStopped(final NetworkTetheringReported.Builder statsBuilder,
final long downstreamStartTime) {
UpstreamEvents.Builder upstreamEventsBuilder = UpstreamEvents.newBuilder();
+
for (RecordUpstreamEvent event : mUpstreamEventList) {
if (downstreamStartTime > event.mStopTime) continue;
- final long startTime = getGreaterStartTime(downstreamStartTime, event.mStartTime);
+ final long startTime = Math.max(downstreamStartTime, event.mStartTime);
// Handle completed upstream events.
- updateUpstreamEvents(upstreamEventsBuilder, startTime, event.mStopTime,
- event.mUpstreamType);
+ addUpstreamEvent(upstreamEventsBuilder, startTime, event.mStopTime,
+ event.mUpstreamType, 0L /* txBytes */, 0L /* rxBytes */);
}
- final long startTime = getGreaterStartTime(downstreamStartTime, mCurrentUpStreamStartTime);
+ final long startTime = Math.max(downstreamStartTime, mCurrentUpStreamStartTime);
final long stopTime = timeNow();
// Handle the last upstream event.
- updateUpstreamEvents(upstreamEventsBuilder, startTime, stopTime, mCurrentUpstream);
+ addUpstreamEvent(upstreamEventsBuilder, startTime, stopTime, mCurrentUpstream,
+ 0L /* txBytes */, 0L /* rxBytes */);
statsBuilder.setUpstreamEvents(upstreamEventsBuilder);
statsBuilder.setDurationMillis(stopTime - downstreamStartTime);
}
@@ -237,7 +231,7 @@
return;
}
- updateStatsBuilderToWrite(statsBuilder, mDownstreamStartTime.get(downstreamType));
+ noteDownstreamStopped(statsBuilder, mDownstreamStartTime.get(downstreamType));
write(statsBuilder.build());
mBuilderMap.remove(downstreamType);
@@ -365,34 +359,19 @@
if (nc == null) return UpstreamType.UT_NO_NETWORK;
final int typeCount = nc.getTransportTypes().length;
+ // It's possible for a VCN network to be mapped to UT_UNKNOWN, as it may consist of both
+ // Wi-Fi and cellular transport.
+ // TODO: It's necessary to define a new upstream type for VCN, which can be identified by
+ // NET_CAPABILITY_NOT_VCN_MANAGED.
+ if (typeCount > 1) return UpstreamType.UT_UNKNOWN;
- boolean hasCellular = nc.hasTransport(TRANSPORT_CELLULAR);
- boolean hasWifi = nc.hasTransport(TRANSPORT_WIFI);
- boolean hasBT = nc.hasTransport(TRANSPORT_BLUETOOTH);
- boolean hasEthernet = nc.hasTransport(TRANSPORT_ETHERNET);
- boolean hasVpn = nc.hasTransport(TRANSPORT_VPN);
- boolean hasWifiAware = nc.hasTransport(TRANSPORT_WIFI_AWARE);
- boolean hasLopan = nc.hasTransport(TRANSPORT_LOWPAN);
+ if (nc.hasTransport(TRANSPORT_CELLULAR)) return UpstreamType.UT_CELLULAR;
+ if (nc.hasTransport(TRANSPORT_WIFI)) return UpstreamType.UT_WIFI;
+ if (nc.hasTransport(TRANSPORT_BLUETOOTH)) return UpstreamType.UT_BLUETOOTH;
+ if (nc.hasTransport(TRANSPORT_ETHERNET)) return UpstreamType.UT_ETHERNET;
+ if (nc.hasTransport(TRANSPORT_WIFI_AWARE)) return UpstreamType.UT_WIFI_AWARE;
+ if (nc.hasTransport(TRANSPORT_LOWPAN)) return UpstreamType.UT_LOWPAN;
- if (typeCount == 3 && hasCellular && hasWifi && hasVpn) {
- return UpstreamType.UT_WIFI_CELLULAR_VPN;
- }
-
- if (typeCount == 2 && hasVpn) {
- if (hasCellular) return UpstreamType.UT_CELLULAR_VPN;
- if (hasWifi) return UpstreamType.UT_WIFI_VPN;
- if (hasBT) return UpstreamType.UT_BLUETOOTH_VPN;
- if (hasEthernet) return UpstreamType.UT_ETHERNET_VPN;
- }
-
- if (typeCount == 1) {
- if (hasCellular) return UpstreamType.UT_CELLULAR;
- if (hasWifi) return UpstreamType.UT_WIFI;
- if (hasBT) return UpstreamType.UT_BLUETOOTH;
- if (hasEthernet) return UpstreamType.UT_ETHERNET;
- if (hasWifiAware) return UpstreamType.UT_WIFI_AWARE;
- if (hasLopan) return UpstreamType.UT_LOWPAN;
- }
return UpstreamType.UT_UNKNOWN;
}
}
diff --git a/Tethering/src/com/android/networkstack/tethering/metrics/stats.proto b/Tethering/src/com/android/networkstack/tethering/metrics/stats.proto
index 27f2126..b276389 100644
--- a/Tethering/src/com/android/networkstack/tethering/metrics/stats.proto
+++ b/Tethering/src/com/android/networkstack/tethering/metrics/stats.proto
@@ -21,13 +21,21 @@
import "frameworks/proto_logging/stats/enums/stats/connectivity/tethering.proto";
-// Logs each upstream for a successful switch over
+/**
+ * Represents an event that logs information about a successful switch to an upstream network.
+ */
message UpstreamEvent {
- // Transport type of upstream network
+ // Indicates the transport type of network.
optional .android.stats.connectivity.UpstreamType upstream_type = 1;
- // A time period that an upstream continued
+ // The duration of network usage.
optional int64 duration_millis = 2;
+
+ // The amount of data received from tethered clients.
+ optional int64 tx_bytes = 3;
+
+ // The amount of data received from remote.
+ optional int64 rx_bytes = 4;
}
message UpstreamEvents {
diff --git a/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java b/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java
index cb57d13..c2bc812 100644
--- a/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java
+++ b/Tethering/tests/mts/src/android/tethering/mts/MtsEthernetTetheringTest.java
@@ -80,8 +80,8 @@
// Per RX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
private static final int RX_UDP_PACKET_SIZE = 30;
private static final int RX_UDP_PACKET_COUNT = 456;
- // Per TX UDP packet size: ethhdr (14) + iphdr (20) + udphdr (8) + payload (2) = 44 bytes.
- private static final int TX_UDP_PACKET_SIZE = 44;
+ // Per TX UDP packet size: iphdr (20) + udphdr (8) + payload (2) = 30 bytes.
+ private static final int TX_UDP_PACKET_SIZE = 30;
private static final int TX_UDP_PACKET_COUNT = 123;
private static final String DUMPSYS_TETHERING_RAWMAP_ARG = "bpfRawMap";
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/metrics/TetheringMetricsTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/metrics/TetheringMetricsTest.java
index aa2d16c..e2c924c 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/metrics/TetheringMetricsTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/metrics/TetheringMetricsTest.java
@@ -20,7 +20,6 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
import static android.net.NetworkCapabilities.TRANSPORT_LOWPAN;
-import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE;
import static android.net.TetheringManager.TETHERING_BLUETOOTH;
@@ -151,10 +150,13 @@
}
private void addUpstreamEvent(UpstreamEvents.Builder upstreamEvents,
- final UpstreamType expectedResult, final long duration) {
+ final UpstreamType expectedResult, final long duration, final long txBytes,
+ final long rxBytes) {
UpstreamEvent.Builder upstreamEvent = UpstreamEvent.newBuilder()
.setUpstreamType(expectedResult)
- .setDurationMillis(duration);
+ .setDurationMillis(duration)
+ .setTxBytes(txBytes)
+ .setRxBytes(rxBytes);
upstreamEvents.addUpstreamEvent(upstreamEvent);
}
@@ -165,7 +167,7 @@
incrementCurrentTime(duration);
UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder();
// Set UpstreamType as NO_NETWORK because the upstream type has not been changed.
- addUpstreamEvent(upstreamEvents, UpstreamType.UT_NO_NETWORK, duration);
+ addUpstreamEvent(upstreamEvents, UpstreamType.UT_NO_NETWORK, duration, 0L, 0L);
updateErrorAndSendReport(type, TETHER_ERROR_NO_ERROR);
verifyReport(expectedResult, ErrorCode.EC_NO_ERROR, UserType.USER_UNKNOWN,
@@ -194,7 +196,7 @@
updateErrorAndSendReport(TETHERING_WIFI, errorCode);
UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder();
- addUpstreamEvent(upstreamEvents, UpstreamType.UT_WIFI, duration);
+ addUpstreamEvent(upstreamEvents, UpstreamType.UT_WIFI, duration, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_WIFI, expectedResult, UserType.USER_UNKNOWN,
upstreamEvents, getElapsedRealtime());
reset(mTetheringMetrics);
@@ -236,7 +238,7 @@
UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder();
// Set UpstreamType as NO_NETWORK because the upstream type has not been changed.
- addUpstreamEvent(upstreamEvents, UpstreamType.UT_NO_NETWORK, duration);
+ addUpstreamEvent(upstreamEvents, UpstreamType.UT_NO_NETWORK, duration, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR, expectedResult,
upstreamEvents, getElapsedRealtime());
reset(mTetheringMetrics);
@@ -261,7 +263,7 @@
updateErrorAndSendReport(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder();
- addUpstreamEvent(upstreamEvents, expectedResult, duration);
+ addUpstreamEvent(upstreamEvents, expectedResult, duration, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR,
UserType.USER_UNKNOWN, upstreamEvents, getElapsedRealtime());
reset(mTetheringMetrics);
@@ -278,17 +280,7 @@
runUpstreamTypesTest(buildUpstreamState(TRANSPORT_ETHERNET), UpstreamType.UT_ETHERNET);
runUpstreamTypesTest(buildUpstreamState(TRANSPORT_WIFI_AWARE), UpstreamType.UT_WIFI_AWARE);
runUpstreamTypesTest(buildUpstreamState(TRANSPORT_LOWPAN), UpstreamType.UT_LOWPAN);
- runUpstreamTypesTest(buildUpstreamState(TRANSPORT_CELLULAR, TRANSPORT_VPN),
- UpstreamType.UT_CELLULAR_VPN);
- runUpstreamTypesTest(buildUpstreamState(TRANSPORT_WIFI, TRANSPORT_VPN),
- UpstreamType.UT_WIFI_VPN);
- runUpstreamTypesTest(buildUpstreamState(TRANSPORT_BLUETOOTH, TRANSPORT_VPN),
- UpstreamType.UT_BLUETOOTH_VPN);
- runUpstreamTypesTest(buildUpstreamState(TRANSPORT_ETHERNET, TRANSPORT_VPN),
- UpstreamType.UT_ETHERNET_VPN);
- runUpstreamTypesTest(buildUpstreamState(TRANSPORT_CELLULAR, TRANSPORT_WIFI, TRANSPORT_VPN),
- UpstreamType.UT_WIFI_CELLULAR_VPN);
- runUpstreamTypesTest(buildUpstreamState(TRANSPORT_CELLULAR, TRANSPORT_WIFI, TRANSPORT_VPN,
+ runUpstreamTypesTest(buildUpstreamState(TRANSPORT_CELLULAR, TRANSPORT_WIFI,
TRANSPORT_BLUETOOTH), UpstreamType.UT_UNKNOWN);
}
@@ -307,7 +299,7 @@
UpstreamEvents.Builder wifiTetheringUpstreamEvents = UpstreamEvents.newBuilder();
addUpstreamEvent(wifiTetheringUpstreamEvents, UpstreamType.UT_NO_NETWORK,
- currentTimeMillis() - wifiTetheringStartTime);
+ currentTimeMillis() - wifiTetheringStartTime, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_DHCPSERVER_ERROR,
UserType.USER_SETTINGS, wifiTetheringUpstreamEvents,
currentTimeMillis() - wifiTetheringStartTime);
@@ -316,7 +308,7 @@
UpstreamEvents.Builder usbTetheringUpstreamEvents = UpstreamEvents.newBuilder();
addUpstreamEvent(usbTetheringUpstreamEvents, UpstreamType.UT_NO_NETWORK,
- currentTimeMillis() - usbTetheringStartTime);
+ currentTimeMillis() - usbTetheringStartTime, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_USB, ErrorCode.EC_ENABLE_FORWARDING_ERROR,
UserType.USER_SYSTEMUI, usbTetheringUpstreamEvents,
@@ -326,7 +318,7 @@
UpstreamEvents.Builder bluetoothTetheringUpstreamEvents = UpstreamEvents.newBuilder();
addUpstreamEvent(bluetoothTetheringUpstreamEvents, UpstreamType.UT_NO_NETWORK,
- currentTimeMillis() - bluetoothTetheringStartTime);
+ currentTimeMillis() - bluetoothTetheringStartTime, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_BLUETOOTH, ErrorCode.EC_TETHER_IFACE_ERROR,
UserType.USER_GMS, bluetoothTetheringUpstreamEvents,
currentTimeMillis() - bluetoothTetheringStartTime);
@@ -347,7 +339,7 @@
UpstreamEvents.Builder usbTetheringUpstreamEvents = UpstreamEvents.newBuilder();
addUpstreamEvent(usbTetheringUpstreamEvents, UpstreamType.UT_WIFI,
- currentTimeMillis() - usbTetheringStartTime);
+ currentTimeMillis() - usbTetheringStartTime, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_USB, ErrorCode.EC_NO_ERROR,
UserType.USER_SYSTEMUI, usbTetheringUpstreamEvents,
currentTimeMillis() - usbTetheringStartTime);
@@ -356,7 +348,7 @@
UpstreamEvents.Builder wifiTetheringUpstreamEvents = UpstreamEvents.newBuilder();
addUpstreamEvent(wifiTetheringUpstreamEvents, UpstreamType.UT_WIFI,
- currentTimeMillis() - wifiUpstreamStartTime);
+ currentTimeMillis() - wifiUpstreamStartTime, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR,
UserType.USER_SETTINGS, wifiTetheringUpstreamEvents,
currentTimeMillis() - wifiTetheringStartTime);
@@ -379,9 +371,9 @@
updateErrorAndSendReport(TETHERING_WIFI, TETHER_ERROR_NO_ERROR);
UpstreamEvents.Builder upstreamEvents = UpstreamEvents.newBuilder();
- addUpstreamEvent(upstreamEvents, UpstreamType.UT_WIFI, wifiDuration);
- addUpstreamEvent(upstreamEvents, UpstreamType.UT_BLUETOOTH, bluetoothDuration);
- addUpstreamEvent(upstreamEvents, UpstreamType.UT_CELLULAR, celltoothDuration);
+ addUpstreamEvent(upstreamEvents, UpstreamType.UT_WIFI, wifiDuration, 0L, 0L);
+ addUpstreamEvent(upstreamEvents, UpstreamType.UT_BLUETOOTH, bluetoothDuration, 0L, 0L);
+ addUpstreamEvent(upstreamEvents, UpstreamType.UT_CELLULAR, celltoothDuration, 0L, 0L);
verifyReport(DownstreamType.DS_TETHERING_WIFI, ErrorCode.EC_NO_ERROR,
UserType.USER_SETTINGS, upstreamEvents,
diff --git a/bpf_progs/block.c b/bpf_progs/block.c
index f2a3e62..3797a38 100644
--- a/bpf_progs/block.c
+++ b/bpf_progs/block.c
@@ -19,8 +19,8 @@
#include <netinet/in.h>
#include <stdint.h>
-// The resulting .o needs to load on the Android T beta 3 bpfloader
-#define BPFLOADER_MIN_VER BPFLOADER_T_BETA3_VERSION
+// The resulting .o needs to load on the Android T bpfloader
+#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION
#include "bpf_helpers.h"
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h
index b7ca3af..ed33cc9 100644
--- a/bpf_progs/bpf_net_helpers.h
+++ b/bpf_progs/bpf_net_helpers.h
@@ -86,3 +86,30 @@
if (len > skb->len) len = skb->len;
if (skb->data_end - skb->data < len) bpf_skb_pull_data(skb, len);
}
+
+// constants for passing in to 'bool egress'
+static const bool INGRESS = false;
+static const bool EGRESS = true;
+
+// constants for passing in to 'bool downstream'
+static const bool UPSTREAM = false;
+static const bool DOWNSTREAM = true;
+
+// constants for passing in to 'bool is_ethernet'
+static const bool RAWIP = false;
+static const bool ETHER = true;
+
+// constants for passing in to 'bool updatetime'
+static const bool NO_UPDATETIME = false;
+static const bool UPDATETIME = true;
+
+// constants for passing in to ignore_on_eng / ignore_on_user / ignore_on_userdebug
+// define's instead of static const due to tm-mainline-prod compiler static_assert limitations
+#define LOAD_ON_ENG false
+#define LOAD_ON_USER false
+#define LOAD_ON_USERDEBUG false
+#define IGNORE_ON_ENG true
+#define IGNORE_ON_USER true
+#define IGNORE_ON_USERDEBUG true
+
+#define KVER_4_14 KVER(4, 14, 0)
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index 7c6811a..85ba58e 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -30,8 +30,8 @@
#define __kernel_udphdr udphdr
#include <linux/udp.h>
-// The resulting .o needs to load on the Android T beta 3 bpfloader
-#define BPFLOADER_MIN_VER BPFLOADER_T_BETA3_VERSION
+// The resulting .o needs to load on the Android T bpfloader
+#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION
#include "bpf_helpers.h"
#include "bpf_net_helpers.h"
@@ -52,12 +52,6 @@
__be32 identification;
};
-// constants for passing in to 'bool is_ethernet'
-static const bool RAWIP = false;
-static const bool ETHER = true;
-
-#define KVER_4_14 KVER(4, 14, 0)
-
DEFINE_BPF_MAP_GRW(clat_ingress6_map, HASH, ClatIngress6Key, ClatIngress6Value, 16, AID_SYSTEM)
static inline __always_inline int nat64(struct __sk_buff* skb,
diff --git a/bpf_progs/dscpPolicy.c b/bpf_progs/dscpPolicy.c
index 72f63c6..262b65b 100644
--- a/bpf_progs/dscpPolicy.c
+++ b/bpf_progs/dscpPolicy.c
@@ -27,8 +27,8 @@
#include <stdint.h>
#include <string.h>
-// The resulting .o needs to load on the Android T beta 3 bpfloader
-#define BPFLOADER_MIN_VER BPFLOADER_T_BETA3_VERSION
+// The resulting .o needs to load on the Android T bpfloader
+#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION
#include "bpf_helpers.h"
#include "dscpPolicy.h"
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index e068d8a..839ca40 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -14,8 +14,8 @@
* limitations under the License.
*/
-// The resulting .o needs to load on the Android T Beta 3 bpfloader
-#define BPFLOADER_MIN_VER BPFLOADER_T_BETA3_VERSION
+// The resulting .o needs to load on the Android T bpfloader
+#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION
#include <bpf_helpers.h>
#include <linux/bpf.h>
@@ -42,10 +42,6 @@
static const int BPF_NOMATCH = 0;
static const int BPF_MATCH = 1;
-// Used for 'bool egress'
-static const bool INGRESS = false;
-static const bool EGRESS = true;
-
// Used for 'bool enable_tracing'
static const bool TRACE_ON = true;
static const bool TRACE_OFF = false;
@@ -64,15 +60,15 @@
#define DEFINE_BPF_MAP_NO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
AID_ROOT, AID_NET_BW_ACCT, 0060, "fs_bpf_net_shared", "", false, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, /*ignore_on_eng*/false, \
- /*ignore_on_user*/false, /*ignore_on_userdebug*/false)
+ BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \
+ LOAD_ON_USER, LOAD_ON_USERDEBUG)
// For maps netd only needs read only access to
#define DEFINE_BPF_MAP_RO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
DEFINE_BPF_MAP_EXT(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries, \
AID_ROOT, AID_NET_BW_ACCT, 0460, "fs_bpf_netd_readonly", "", false, \
- BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, /*ignore_on_eng*/false, \
- /*ignore_on_user*/false, /*ignore_on_userdebug*/false)
+ BPFLOADER_MIN_VER, BPFLOADER_MAX_VER, LOAD_ON_ENG, \
+ LOAD_ON_USER, LOAD_ON_USERDEBUG)
// For maps netd needs to be able to read and write
#define DEFINE_BPF_MAP_RW_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
@@ -103,15 +99,15 @@
// A single-element configuration array, packet tracing is enabled when 'true'.
DEFINE_BPF_MAP_EXT(packet_trace_enabled_map, ARRAY, uint32_t, bool, 1,
AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", false,
- BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, /*ignore_on_eng*/false,
- /*ignore_on_user*/true, /*ignore_on_userdebug*/false)
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
+ IGNORE_ON_USER, LOAD_ON_USERDEBUG)
// A ring buffer on which packet information is pushed. This map will only be loaded
// on eng and userdebug devices. User devices won't load this to save memory.
DEFINE_BPF_RINGBUF_EXT(packet_trace_ringbuf, PacketTrace, PACKET_TRACE_BUF_SIZE,
AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", false,
- BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, /*ignore_on_eng*/false,
- /*ignore_on_user*/true, /*ignore_on_userdebug*/false);
+ BPFLOADER_IGNORED_ON_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
+ IGNORE_ON_USER, LOAD_ON_USERDEBUG);
// iptables xt_bpf programs need to be usable by both netd and netutils_wrappers
// selinux contexts, because even non-xt_bpf iptables mutations are implemented as
@@ -176,36 +172,38 @@
* Especially since the number of packets is important for any future clat offload correction.
* (which adjusts upward by 20 bytes per packet to account for ipv4 -> ipv6 header conversion)
*/
-#define DEFINE_UPDATE_STATS(the_stats_map, TypeOfKey) \
- static __always_inline inline void update_##the_stats_map(struct __sk_buff* skb, \
- bool egress, TypeOfKey* key) { \
- StatsValue* value = bpf_##the_stats_map##_lookup_elem(key); \
- if (!value) { \
- StatsValue newValue = {}; \
- bpf_##the_stats_map##_update_elem(key, &newValue, BPF_NOEXIST); \
- value = bpf_##the_stats_map##_lookup_elem(key); \
- } \
- if (value) { \
- const int mtu = 1500; \
- uint64_t packets = 1; \
- uint64_t bytes = skb->len; \
- if (bytes > mtu) { \
- bool is_ipv6 = (skb->protocol == htons(ETH_P_IPV6)); \
- int ip_overhead = (is_ipv6 ? sizeof(struct ipv6hdr) : sizeof(struct iphdr)); \
- int tcp_overhead = ip_overhead + sizeof(struct tcphdr) + 12; \
- int mss = mtu - tcp_overhead; \
- uint64_t payload = bytes - tcp_overhead; \
- packets = (payload + mss - 1) / mss; \
- bytes = tcp_overhead * packets + payload; \
- } \
- if (egress) { \
- __sync_fetch_and_add(&value->txPackets, packets); \
- __sync_fetch_and_add(&value->txBytes, bytes); \
- } else { \
- __sync_fetch_and_add(&value->rxPackets, packets); \
- __sync_fetch_and_add(&value->rxBytes, bytes); \
- } \
- } \
+#define DEFINE_UPDATE_STATS(the_stats_map, TypeOfKey) \
+ static __always_inline inline void update_##the_stats_map(const struct __sk_buff* const skb, \
+ const TypeOfKey* const key, \
+ const bool egress, \
+ const unsigned kver) { \
+ StatsValue* value = bpf_##the_stats_map##_lookup_elem(key); \
+ if (!value) { \
+ StatsValue newValue = {}; \
+ bpf_##the_stats_map##_update_elem(key, &newValue, BPF_NOEXIST); \
+ value = bpf_##the_stats_map##_lookup_elem(key); \
+ } \
+ if (value) { \
+ const int mtu = 1500; \
+ uint64_t packets = 1; \
+ uint64_t bytes = skb->len; \
+ if (bytes > mtu) { \
+ bool is_ipv6 = (skb->protocol == htons(ETH_P_IPV6)); \
+ int ip_overhead = (is_ipv6 ? sizeof(struct ipv6hdr) : sizeof(struct iphdr)); \
+ int tcp_overhead = ip_overhead + sizeof(struct tcphdr) + 12; \
+ int mss = mtu - tcp_overhead; \
+ uint64_t payload = bytes - tcp_overhead; \
+ packets = (payload + mss - 1) / mss; \
+ bytes = tcp_overhead * packets + payload; \
+ } \
+ if (egress) { \
+ __sync_fetch_and_add(&value->txPackets, packets); \
+ __sync_fetch_and_add(&value->txBytes, bytes); \
+ } else { \
+ __sync_fetch_and_add(&value->rxPackets, packets); \
+ __sync_fetch_and_add(&value->rxBytes, bytes); \
+ } \
+ } \
}
DEFINE_UPDATE_STATS(app_uid_stats_map, uint32_t)
@@ -300,7 +298,8 @@
bpf_packet_trace_ringbuf_submit(pkt);
}
-static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, const unsigned kver) {
+static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, bool egress,
+ const unsigned kver) {
uint32_t flag = 0;
if (skb->protocol == htons(ETH_P_IP)) {
uint8_t proto;
@@ -330,7 +329,8 @@
} else {
return false;
}
- return flag & TCP_FLAG_RST; // false on read failure
+ // Always allow RST's, and additionally allow ingress FINs
+ return flag & (TCP_FLAG_RST | (egress ? 0 : TCP_FLAG_FIN)); // false on read failure
}
static __always_inline inline BpfConfig getConfig(uint32_t configKey) {
@@ -352,7 +352,7 @@
bool egress, const unsigned kver) {
if (is_system_uid(uid)) return PASS;
- if (skip_owner_match(skb, kver)) return PASS;
+ if (skip_owner_match(skb, egress, kver)) return PASS;
BpfConfig enabledRules = getConfig(UID_RULES_CONFIGURATION_KEY);
@@ -383,12 +383,15 @@
return PASS;
}
-static __always_inline inline void update_stats_with_config(struct __sk_buff* skb, bool egress,
- StatsKey* key, uint32_t selectedMap) {
+static __always_inline inline void update_stats_with_config(const uint32_t selectedMap,
+ const struct __sk_buff* const skb,
+ const StatsKey* const key,
+ const bool egress,
+ const unsigned kver) {
if (selectedMap == SELECT_MAP_A) {
- update_stats_map_A(skb, egress, key);
+ update_stats_map_A(skb, key, egress, kver);
} else {
- update_stats_map_B(skb, egress, key);
+ update_stats_map_B(skb, key, egress, kver);
}
}
@@ -446,14 +449,9 @@
return match;
}
- if (key.tag) {
- update_stats_with_config(skb, egress, &key, *selectedMap);
- key.tag = 0;
- }
-
do_packet_tracing(skb, egress, uid, tag, enable_tracing, kver);
- update_stats_with_config(skb, egress, &key, *selectedMap);
- update_app_uid_stats_map(skb, egress, &uid);
+ update_stats_with_config(*selectedMap, skb, &key, egress, kver);
+ update_app_uid_stats_map(skb, &uid, egress, kver);
asm("%0 &= 1" : "+r"(match));
return match;
}
@@ -514,7 +512,7 @@
}
uint32_t key = skb->ifindex;
- update_iface_stats_map(skb, EGRESS, &key);
+ update_iface_stats_map(skb, &key, EGRESS, KVER_NONE);
return BPF_MATCH;
}
@@ -527,7 +525,7 @@
// Keep that in mind when moving this out of iptables xt_bpf and into tc ingress (or xdp).
uint32_t key = skb->ifindex;
- update_iface_stats_map(skb, INGRESS, &key);
+ update_iface_stats_map(skb, &key, INGRESS, KVER_NONE);
return BPF_MATCH;
}
@@ -537,7 +535,7 @@
if (is_received_skb(skb)) {
// Account for ingress traffic before tc drops it.
uint32_t key = skb->ifindex;
- update_iface_stats_map(skb, INGRESS, &key);
+ update_iface_stats_map(skb, &key, INGRESS, KVER_NONE);
}
return TC_ACT_UNSPEC;
}
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
index a8612df..f4d4254 100644
--- a/bpf_progs/offload.c
+++ b/bpf_progs/offload.c
@@ -131,7 +131,7 @@
TETHERING_GID)
static inline __always_inline int do_forward6(struct __sk_buff* skb, const bool is_ethernet,
- const bool downstream) {
+ const bool downstream, const unsigned kver) {
// Must be meta-ethernet IPv6 frame
if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_PIPE;
@@ -232,13 +232,13 @@
// This would require a much newer kernel with newer ebpf accessors.
// (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header)
uint64_t packets = 1;
- uint64_t bytes = skb->len;
- if (bytes > v->pmtu) {
- const int tcp_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12;
- const int mss = v->pmtu - tcp_overhead;
- const uint64_t payload = bytes - tcp_overhead;
+ uint64_t L3_bytes = skb->len - l2_header_size;
+ if (L3_bytes > v->pmtu) {
+ const int tcp6_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12;
+ const int mss = v->pmtu - tcp6_overhead;
+ const uint64_t payload = L3_bytes - tcp6_overhead;
packets = (payload + mss - 1) / mss;
- bytes = tcp_overhead * packets + payload;
+ L3_bytes = tcp6_overhead * packets + payload;
}
// Are we past the limit? If so, then abort...
@@ -247,7 +247,7 @@
// a packet we let the core stack deal with things.
// (The core stack needs to handle limits correctly anyway,
// since we don't offload all traffic in both directions)
- if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) TC_PUNT(LIMIT_REACHED);
+ if (stat_v->rxBytes + stat_v->txBytes + L3_bytes > *limit_v) TC_PUNT(LIMIT_REACHED);
if (!is_ethernet) {
// Try to inject an ethernet header, and simply return if we fail.
@@ -287,7 +287,7 @@
bpf_csum_update(skb, 0xFFFF - ntohs(old_hl) + ntohs(new_hl));
__sync_fetch_and_add(downstream ? &stat_v->rxPackets : &stat_v->txPackets, packets);
- __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, bytes);
+ __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, L3_bytes);
// Overwrite any mac header with the new one
// For a rawip tx interface it will simply be a bunch of zeroes and later stripped.
@@ -305,13 +305,13 @@
DEFINE_BPF_PROG("schedcls/tether_downstream6_ether", TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream6_ether)
(struct __sk_buff* skb) {
- return do_forward6(skb, /* is_ethernet */ true, /* downstream */ true);
+ return do_forward6(skb, ETHER, DOWNSTREAM, KVER_NONE);
}
DEFINE_BPF_PROG("schedcls/tether_upstream6_ether", TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream6_ether)
(struct __sk_buff* skb) {
- return do_forward6(skb, /* is_ethernet */ true, /* downstream */ false);
+ return do_forward6(skb, ETHER, UPSTREAM, KVER_NONE);
}
// Note: section names must be unique to prevent programs from appending to each other,
@@ -331,13 +331,13 @@
DEFINE_BPF_PROG_KVER("schedcls/tether_downstream6_rawip$4_14", TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream6_rawip_4_14, KVER(4, 14, 0))
(struct __sk_buff* skb) {
- return do_forward6(skb, /* is_ethernet */ false, /* downstream */ true);
+ return do_forward6(skb, RAWIP, DOWNSTREAM, KVER(4, 14, 0));
}
DEFINE_BPF_PROG_KVER("schedcls/tether_upstream6_rawip$4_14", TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream6_rawip_4_14, KVER(4, 14, 0))
(struct __sk_buff* skb) {
- return do_forward6(skb, /* is_ethernet */ false, /* downstream */ false);
+ return do_forward6(skb, RAWIP, UPSTREAM, KVER(4, 14, 0));
}
// and define no-op stubs for pre-4.14 kernels.
@@ -362,7 +362,8 @@
static inline __always_inline int do_forward4_bottom(struct __sk_buff* skb,
const int l2_header_size, void* data, const void* data_end,
struct ethhdr* eth, struct iphdr* ip, const bool is_ethernet,
- const bool downstream, const bool updatetime, const bool is_tcp) {
+ const bool downstream, const bool updatetime, const bool is_tcp,
+ const unsigned kver) {
struct tcphdr* tcph = is_tcp ? (void*)(ip + 1) : NULL;
struct udphdr* udph = is_tcp ? NULL : (void*)(ip + 1);
@@ -449,13 +450,13 @@
// This would require a much newer kernel with newer ebpf accessors.
// (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header)
uint64_t packets = 1;
- uint64_t bytes = skb->len;
- if (bytes > v->pmtu) {
- const int tcp_overhead = sizeof(struct iphdr) + sizeof(struct tcphdr) + 12;
- const int mss = v->pmtu - tcp_overhead;
- const uint64_t payload = bytes - tcp_overhead;
+ uint64_t L3_bytes = skb->len - l2_header_size;
+ if (L3_bytes > v->pmtu) {
+ const int tcp4_overhead = sizeof(struct iphdr) + sizeof(struct tcphdr) + 12;
+ const int mss = v->pmtu - tcp4_overhead;
+ const uint64_t payload = L3_bytes - tcp4_overhead;
packets = (payload + mss - 1) / mss;
- bytes = tcp_overhead * packets + payload;
+ L3_bytes = tcp4_overhead * packets + payload;
}
// Are we past the limit? If so, then abort...
@@ -464,7 +465,7 @@
// a packet we let the core stack deal with things.
// (The core stack needs to handle limits correctly anyway,
// since we don't offload all traffic in both directions)
- if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) TC_PUNT(LIMIT_REACHED);
+ if (stat_v->rxBytes + stat_v->txBytes + L3_bytes > *limit_v) TC_PUNT(LIMIT_REACHED);
if (!is_ethernet) {
// Try to inject an ethernet header, and simply return if we fail.
@@ -540,7 +541,7 @@
if (updatetime) v->last_used = bpf_ktime_get_boot_ns();
__sync_fetch_and_add(downstream ? &stat_v->rxPackets : &stat_v->txPackets, packets);
- __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, bytes);
+ __sync_fetch_and_add(downstream ? &stat_v->rxBytes : &stat_v->txBytes, L3_bytes);
// Redirect to forwarded interface.
//
@@ -552,7 +553,7 @@
}
static inline __always_inline int do_forward4(struct __sk_buff* skb, const bool is_ethernet,
- const bool downstream, const bool updatetime) {
+ const bool downstream, const bool updatetime, const unsigned kver) {
// Require ethernet dst mac address to be our unicast address.
if (is_ethernet && (skb->pkt_type != PACKET_HOST)) return TC_ACT_PIPE;
@@ -640,10 +641,10 @@
// if the underlying requisite kernel support (bpf_ktime_get_boot_ns) was backported.
if (is_tcp) {
return do_forward4_bottom(skb, l2_header_size, data, data_end, eth, ip,
- is_ethernet, downstream, updatetime, /* is_tcp */ true);
+ is_ethernet, downstream, updatetime, /* is_tcp */ true, kver);
} else {
return do_forward4_bottom(skb, l2_header_size, data, data_end, eth, ip,
- is_ethernet, downstream, updatetime, /* is_tcp */ false);
+ is_ethernet, downstream, updatetime, /* is_tcp */ false, kver);
}
}
@@ -652,25 +653,25 @@
DEFINE_BPF_PROG_KVER("schedcls/tether_downstream4_rawip$5_8", TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream4_rawip_5_8, KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ false, /* downstream */ true, /* updatetime */ true);
+ return do_forward4(skb, RAWIP, DOWNSTREAM, UPDATETIME, KVER(5, 8, 0));
}
DEFINE_BPF_PROG_KVER("schedcls/tether_upstream4_rawip$5_8", TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream4_rawip_5_8, KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ false, /* downstream */ false, /* updatetime */ true);
+ return do_forward4(skb, RAWIP, UPSTREAM, UPDATETIME, KVER(5, 8, 0));
}
DEFINE_BPF_PROG_KVER("schedcls/tether_downstream4_ether$5_8", TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream4_ether_5_8, KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ true, /* downstream */ true, /* updatetime */ true);
+ return do_forward4(skb, ETHER, DOWNSTREAM, UPDATETIME, KVER(5, 8, 0));
}
DEFINE_BPF_PROG_KVER("schedcls/tether_upstream4_ether$5_8", TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream4_ether_5_8, KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ true, /* downstream */ false, /* updatetime */ true);
+ return do_forward4(skb, ETHER, UPSTREAM, UPDATETIME, KVER(5, 8, 0));
}
// Full featured (optional) implementations for 4.14-S, 4.19-S & 5.4-S kernels
@@ -681,7 +682,7 @@
sched_cls_tether_downstream4_rawip_opt,
KVER(4, 14, 0), KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ false, /* downstream */ true, /* updatetime */ true);
+ return do_forward4(skb, RAWIP, DOWNSTREAM, UPDATETIME, KVER(4, 14, 0));
}
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$opt",
@@ -689,7 +690,7 @@
sched_cls_tether_upstream4_rawip_opt,
KVER(4, 14, 0), KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ false, /* downstream */ false, /* updatetime */ true);
+ return do_forward4(skb, RAWIP, UPSTREAM, UPDATETIME, KVER(4, 14, 0));
}
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_ether$opt",
@@ -697,7 +698,7 @@
sched_cls_tether_downstream4_ether_opt,
KVER(4, 14, 0), KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ true, /* downstream */ true, /* updatetime */ true);
+ return do_forward4(skb, ETHER, DOWNSTREAM, UPDATETIME, KVER(4, 14, 0));
}
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_ether$opt",
@@ -705,7 +706,7 @@
sched_cls_tether_upstream4_ether_opt,
KVER(4, 14, 0), KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ true, /* downstream */ false, /* updatetime */ true);
+ return do_forward4(skb, ETHER, UPSTREAM, UPDATETIME, KVER(4, 14, 0));
}
// Partial (TCP-only: will not update 'last_used' field) implementations for 4.14+ kernels.
@@ -725,13 +726,13 @@
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_rawip$5_4", TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream4_rawip_5_4, KVER(5, 4, 0), KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ false, /* downstream */ true, /* updatetime */ false);
+ return do_forward4(skb, RAWIP, DOWNSTREAM, NO_UPDATETIME, KVER(5, 4, 0));
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$5_4", TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream4_rawip_5_4, KVER(5, 4, 0), KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ false, /* downstream */ false, /* updatetime */ false);
+ return do_forward4(skb, RAWIP, UPSTREAM, NO_UPDATETIME, KVER(5, 4, 0));
}
// RAWIP: Optional for 4.14/4.19 (R) kernels -- which support bpf_skb_change_head().
@@ -742,7 +743,7 @@
sched_cls_tether_downstream4_rawip_4_14,
KVER(4, 14, 0), KVER(5, 4, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ false, /* downstream */ true, /* updatetime */ false);
+ return do_forward4(skb, RAWIP, DOWNSTREAM, NO_UPDATETIME, KVER(4, 14, 0));
}
DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_rawip$4_14",
@@ -750,7 +751,7 @@
sched_cls_tether_upstream4_rawip_4_14,
KVER(4, 14, 0), KVER(5, 4, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ false, /* downstream */ false, /* updatetime */ false);
+ return do_forward4(skb, RAWIP, UPSTREAM, NO_UPDATETIME, KVER(4, 14, 0));
}
// ETHER: Required for 4.14-Q/R, 4.19-Q/R & 5.4-R kernels.
@@ -758,13 +759,13 @@
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_downstream4_ether$4_14", TETHERING_UID, TETHERING_GID,
sched_cls_tether_downstream4_ether_4_14, KVER(4, 14, 0), KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ true, /* downstream */ true, /* updatetime */ false);
+ return do_forward4(skb, ETHER, DOWNSTREAM, NO_UPDATETIME, KVER(4, 14, 0));
}
DEFINE_BPF_PROG_KVER_RANGE("schedcls/tether_upstream4_ether$4_14", TETHERING_UID, TETHERING_GID,
sched_cls_tether_upstream4_ether_4_14, KVER(4, 14, 0), KVER(5, 8, 0))
(struct __sk_buff* skb) {
- return do_forward4(skb, /* is_ethernet */ true, /* downstream */ false, /* updatetime */ false);
+ return do_forward4(skb, ETHER, UPSTREAM, NO_UPDATETIME, KVER(4, 14, 0));
}
// Placeholder (no-op) implementations for older Q kernels
@@ -820,9 +821,9 @@
if ((void*)(eth + 1) > data_end) return XDP_PASS;
if (eth->h_proto == htons(ETH_P_IPV6))
- return do_xdp_forward6(ctx, /* is_ethernet */ true, downstream);
+ return do_xdp_forward6(ctx, ETHER, downstream);
if (eth->h_proto == htons(ETH_P_IP))
- return do_xdp_forward4(ctx, /* is_ethernet */ true, downstream);
+ return do_xdp_forward4(ctx, ETHER, downstream);
// Anything else we don't know how to handle...
return XDP_PASS;
@@ -836,8 +837,8 @@
if (data_end - data < 1) return XDP_PASS;
const uint8_t v = (*(uint8_t*)data) >> 4;
- if (v == 6) return do_xdp_forward6(ctx, /* is_ethernet */ false, downstream);
- if (v == 4) return do_xdp_forward4(ctx, /* is_ethernet */ false, downstream);
+ if (v == 6) return do_xdp_forward6(ctx, RAWIP, downstream);
+ if (v == 4) return do_xdp_forward4(ctx, RAWIP, downstream);
// Anything else we don't know how to handle...
return XDP_PASS;
@@ -848,22 +849,22 @@
DEFINE_XDP_PROG("xdp/tether_downstream_ether",
xdp_tether_downstream_ether) {
- return do_xdp_forward_ether(ctx, /* downstream */ true);
+ return do_xdp_forward_ether(ctx, DOWNSTREAM);
}
DEFINE_XDP_PROG("xdp/tether_downstream_rawip",
xdp_tether_downstream_rawip) {
- return do_xdp_forward_rawip(ctx, /* downstream */ true);
+ return do_xdp_forward_rawip(ctx, DOWNSTREAM);
}
DEFINE_XDP_PROG("xdp/tether_upstream_ether",
xdp_tether_upstream_ether) {
- return do_xdp_forward_ether(ctx, /* downstream */ false);
+ return do_xdp_forward_ether(ctx, UPSTREAM);
}
DEFINE_XDP_PROG("xdp/tether_upstream_rawip",
xdp_tether_upstream_rawip) {
- return do_xdp_forward_rawip(ctx, /* downstream */ false);
+ return do_xdp_forward_rawip(ctx, UPSTREAM);
}
LICENSE("Apache 2.0");
diff --git a/framework-t/src/android/net/NetworkStatsAccess.java b/framework-t/src/android/net/NetworkStatsAccess.java
index 0585756..23902dc 100644
--- a/framework-t/src/android/net/NetworkStatsAccess.java
+++ b/framework-t/src/android/net/NetworkStatsAccess.java
@@ -17,7 +17,6 @@
package android.net;
import static android.Manifest.permission.READ_NETWORK_USAGE_HISTORY;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static android.net.NetworkStats.UID_ALL;
import static android.net.TrafficStats.UID_REMOVED;
import static android.net.TrafficStats.UID_TETHERING;
@@ -33,6 +32,8 @@
import android.os.UserHandle;
import android.telephony.TelephonyManager;
+import com.android.net.module.util.PermissionUtils;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -100,6 +101,7 @@
* <li>Device owners.
* <li>Carrier-privileged applications.
* <li>The system UID.
+ * <li>NetworkStack application.
* </ul>
*/
int DEVICE = 3;
@@ -125,9 +127,9 @@
final int appId = UserHandle.getAppId(callingUid);
- final boolean isNetworkStack = context.checkPermission(
- android.Manifest.permission.NETWORK_STACK, callingPid, callingUid)
- == PERMISSION_GRANTED;
+ final boolean isNetworkStack = PermissionUtils.checkAnyPermissionOf(
+ context, callingPid, callingUid, android.Manifest.permission.NETWORK_STACK,
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
if (hasCarrierPrivileges || isDeviceOwner
|| appId == Process.SYSTEM_UID || isNetworkStack) {
diff --git a/framework-t/src/android/net/NetworkTemplate.java b/framework-t/src/android/net/NetworkTemplate.java
index 9d0476e..33bd884 100644
--- a/framework-t/src/android/net/NetworkTemplate.java
+++ b/framework-t/src/android/net/NetworkTemplate.java
@@ -184,6 +184,23 @@
}
}
+ private static Set<String> setOf(@Nullable final String item) {
+ if (item == null) {
+ // Set.of will throw if item is null
+ final Set<String> set = new HashSet<>();
+ set.add(null);
+ return Collections.unmodifiableSet(set);
+ } else {
+ return Set.of(item);
+ }
+ }
+
+ private static void throwAtLeastU() {
+ if (SdkLevel.isAtLeastU()) {
+ throw new UnsupportedOperationException("Method not supported on Android U or above");
+ }
+ }
+
/**
* Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with
* the given IMSI.
@@ -195,22 +212,8 @@
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.TIRAMISU,
publicAlternatives = "Use {@code Builder} instead.")
public static NetworkTemplate buildTemplateMobileAll(@NonNull String subscriberId) {
- final Set<String> set;
- // Prevent from crash for b/273963543, where the OEMs still call into this method
- // with null subscriberId and get crashed.
- final int firstSdk = Build.VERSION.DEVICE_INITIAL_SDK_INT;
- if (firstSdk > Build.VERSION_CODES.TIRAMISU && subscriberId == null) {
- throw new IllegalArgumentException("buildTemplateMobileAll does not accept null"
- + " subscriberId on Android U devices or above");
- }
- if (subscriberId == null) {
- set = new HashSet<>();
- set.add(null);
- } else {
- set = Set.of(subscriberId);
- }
return new NetworkTemplate.Builder(MATCH_MOBILE).setMeteredness(METERED_YES)
- .setSubscriberIds(set).build();
+ .setSubscriberIds(setOf(subscriberId)).build();
}
/**
@@ -274,10 +277,9 @@
// TODO(b/270089918): Remove this method. This can only be done after there are no more callers,
// including in OEM code which can access this by linking against the framework.
public static NetworkTemplate buildTemplateBluetooth() {
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException(
- "buildTemplateBluetooth is not supported on Android U devices or above");
- }
+ // TODO : this is part of hidden-o txt, does that mean it should be annotated with
+ // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps
+ // targeting O- crash on those devices.
return new NetworkTemplate.Builder(MATCH_BLUETOOTH).build();
}
@@ -290,10 +292,9 @@
// TODO(b/270089918): Remove this method. This can only be done after there are no more callers,
// including in OEM code which can access this by linking against the framework.
public static NetworkTemplate buildTemplateProxy() {
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException(
- "buildTemplateProxy is not supported on Android U devices or above");
- }
+ // TODO : this is part of hidden-o txt, does that mean it should be annotated with
+ // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps
+ // targeting O- crash on those devices.
return new NetworkTemplate(MATCH_PROXY, null, null);
}
@@ -305,12 +306,10 @@
// TODO(b/273963543): Remove this method. This can only be done after there are no more callers,
// including in OEM code which can access this by linking against the framework.
public static NetworkTemplate buildTemplateCarrierMetered(@NonNull String subscriberId) {
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException(
- "buildTemplateCarrierMetered is not supported on Android U devices or above");
- }
+ throwAtLeastU();
return new NetworkTemplate.Builder(MATCH_CARRIER)
- // Set.of will throw if subscriberId is null
+ // Set.of will throw if subscriberId is null, which is the historical
+ // behavior and should be preserved.
.setSubscriberIds(Set.of(subscriberId))
.setMeteredness(METERED_YES)
.build();
@@ -327,10 +326,7 @@
// including in OEM code which can access this by linking against the framework.
public static NetworkTemplate buildTemplateMobileWithRatType(@Nullable String subscriberId,
int ratType, int metered) {
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException("buildTemplateMobileWithRatType is not "
- + "supported on Android U devices or above");
- }
+ throwAtLeastU();
return new NetworkTemplate.Builder(MATCH_MOBILE)
.setSubscriberIds(TextUtils.isEmpty(subscriberId)
? Collections.emptySet()
@@ -340,7 +336,6 @@
.build();
}
-
/**
* Template to match {@link ConnectivityManager#TYPE_WIFI} networks with the
* given key of the wifi network.
@@ -352,12 +347,12 @@
// TODO(b/273963543): Remove this method. This can only be done after there are no more callers,
// including in OEM code which can access this by linking against the framework.
public static NetworkTemplate buildTemplateWifi(@NonNull String wifiNetworkKey) {
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException("buildTemplateWifi is not "
- + "supported on Android U devices or above");
- }
+ // TODO : this is part of hidden-o txt, does that mean it should be annotated with
+ // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps
+ // targeting O- crash on those devices.
return new NetworkTemplate.Builder(MATCH_WIFI)
- // Set.of will throw if wifiNetworkKey is null
+ // Set.of will throw if wifiNetworkKey is null, which is the historical
+ // behavior and should be preserved.
.setWifiNetworkKeys(Set.of(wifiNetworkKey))
.build();
}
@@ -379,14 +374,9 @@
// including in OEM code which can access this by linking against the framework.
public static NetworkTemplate buildTemplateWifi(@Nullable String wifiNetworkKey,
@Nullable String subscriberId) {
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException("buildTemplateWifi is not "
- + "supported on Android U devices or above");
- }
+ throwAtLeastU();
return new NetworkTemplate.Builder(MATCH_WIFI)
- .setSubscriberIds(subscriberId == null
- ? Collections.emptySet()
- : Set.of(subscriberId))
+ .setSubscriberIds(setOf(subscriberId))
.setWifiNetworkKeys(wifiNetworkKey == null
? Collections.emptySet()
: Set.of(wifiNetworkKey))
@@ -471,10 +461,6 @@
if (matchRule == 6 || matchRule == 7) {
Log.e(TAG, "Use MATCH_MOBILE with empty subscriberIds or MATCH_WIFI with empty "
+ "wifiNetworkKeys instead of template with matchRule=" + matchRule);
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException(
- "Wildcard templates are not supported on Android U devices or above");
- }
}
}
@@ -508,10 +494,9 @@
getMeterednessForBackwardsCompatibility(matchRule),
ROAMING_ALL, DEFAULT_NETWORK_ALL, NETWORK_TYPE_ALL,
OEM_MANAGED_ALL);
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException(
- "This constructor is not supported on Android U devices or above");
- }
+ // TODO : this is part of hidden-o txt, does that mean it should be annotated with
+ // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps
+ // targeting O- crash on those devices.
}
/** @hide */
@@ -526,10 +511,7 @@
this(getBackwardsCompatibleMatchRule(matchRule),
matchSubscriberIds == null ? new String[]{} : matchSubscriberIds,
matchWifiNetworkKeys, metered, roaming, defaultNetwork, ratType, oemManaged);
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException(
- "This constructor is not supported on Android U devices or above");
- }
+ throwAtLeastU();
}
/** @hide */
@@ -636,10 +618,9 @@
// including in OEM code which can access this by linking against the framework.
/** @hide */
public boolean isMatchRuleMobile() {
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException(
- "isMatchRuleMobile is not supported on Android U devices or above");
- }
+ // TODO : this is part of hidden-o txt, does that mean it should be annotated with
+ // @UnsupportedAppUsage(maxTargetSdk = O) ? If yes, can't throwAtLeastU() lest apps
+ // targeting O- crash on those devices.
switch (mMatchRule) {
case MATCH_MOBILE:
// Old MATCH_MOBILE_WILDCARD
@@ -981,10 +962,7 @@
// TODO(b/273963543): Remove this method. This can only be done after there are no more callers,
// including in OEM code which can access this by linking against the framework.
public static NetworkTemplate normalize(NetworkTemplate template, List<String[]> mergedList) {
- if (SdkLevel.isAtLeastU()) {
- throw new UnsupportedOperationException(
- "normalize is not supported on Android U devices or above");
- }
+ throwAtLeastU();
return normalizeImpl(template, mergedList);
}
diff --git a/framework-t/src/android/net/nsd/NsdManager.java b/framework-t/src/android/net/nsd/NsdManager.java
index 96f2f80..d119db6 100644
--- a/framework-t/src/android/net/nsd/NsdManager.java
+++ b/framework-t/src/android/net/nsd/NsdManager.java
@@ -281,6 +281,9 @@
EVENT_NAMES.put(UNREGISTER_SERVICE_CALLBACK, "UNREGISTER_SERVICE_CALLBACK");
EVENT_NAMES.put(UNREGISTER_SERVICE_CALLBACK_SUCCEEDED,
"UNREGISTER_SERVICE_CALLBACK_SUCCEEDED");
+ EVENT_NAMES.put(MDNS_DISCOVERY_MANAGER_EVENT, "MDNS_DISCOVERY_MANAGER_EVENT");
+ EVENT_NAMES.put(REGISTER_CLIENT, "REGISTER_CLIENT");
+ EVENT_NAMES.put(UNREGISTER_CLIENT, "UNREGISTER_CLIENT");
}
/** @hide */
diff --git a/framework/Android.bp b/framework/Android.bp
index 2d729c5..d7eaf9b 100644
--- a/framework/Android.bp
+++ b/framework/Android.bp
@@ -105,7 +105,10 @@
java_library {
name: "framework-connectivity-pre-jarjar",
- defaults: ["framework-connectivity-defaults"],
+ defaults: [
+ "framework-connectivity-defaults",
+ "CronetJavaPrejarjarDefaults",
+ ],
libs: [
// This cannot be in the defaults clause above because if it were, it would be used
// to generate the connectivity stubs. That would create a circular dependency
@@ -119,7 +122,10 @@
java_sdk_library {
name: "framework-connectivity",
- defaults: ["framework-connectivity-defaults"],
+ defaults: [
+ "framework-connectivity-defaults",
+ "CronetJavaDefaults",
+ ],
installable: true,
jarjar_rules: ":framework-connectivity-jarjar-rules",
permitted_packages: ["android.net"],
@@ -147,6 +153,7 @@
"//frameworks/opt/net/ethernet/tests:__subpackages__",
"//frameworks/opt/telephony/tests/telephonytests",
"//packages/modules/CaptivePortalLogin/tests",
+ "//packages/modules/Connectivity/Cronet/tests:__subpackages__",
"//packages/modules/Connectivity/Tethering/tests:__subpackages__",
"//packages/modules/Connectivity/tests:__subpackages__",
"//packages/modules/IPsec/tests/iketests",
@@ -183,6 +190,7 @@
"libnativehelper",
],
header_libs: [
+ "bpf_headers",
"dnsproxyd_protocol_headers",
],
stl: "none",
diff --git a/framework/api/current.txt b/framework/api/current.txt
index 672e3e2..6860c3c 100644
--- a/framework/api/current.txt
+++ b/framework/api/current.txt
@@ -525,3 +525,292 @@
}
+package android.net.http {
+
+ public abstract class BidirectionalStream {
+ ctor public BidirectionalStream();
+ method public abstract void cancel();
+ method public abstract void flush();
+ method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
+ method @NonNull public abstract String getHttpMethod();
+ method public abstract int getPriority();
+ method public abstract int getTrafficStatsTag();
+ method public abstract int getTrafficStatsUid();
+ method public abstract boolean hasTrafficStatsTag();
+ method public abstract boolean hasTrafficStatsUid();
+ method public abstract boolean isDelayRequestHeadersUntilFirstFlushEnabled();
+ method public abstract boolean isDone();
+ method public abstract void read(@NonNull java.nio.ByteBuffer);
+ method public abstract void start();
+ method public abstract void write(@NonNull java.nio.ByteBuffer, boolean);
+ field public static final int STREAM_PRIORITY_HIGHEST = 4; // 0x4
+ field public static final int STREAM_PRIORITY_IDLE = 0; // 0x0
+ field public static final int STREAM_PRIORITY_LOW = 2; // 0x2
+ field public static final int STREAM_PRIORITY_LOWEST = 1; // 0x1
+ field public static final int STREAM_PRIORITY_MEDIUM = 3; // 0x3
+ }
+
+ public abstract static class BidirectionalStream.Builder {
+ ctor public BidirectionalStream.Builder();
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder addHeader(@NonNull String, @NonNull String);
+ method @NonNull public abstract android.net.http.BidirectionalStream build();
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setDelayRequestHeadersUntilFirstFlushEnabled(boolean);
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setHttpMethod(@NonNull String);
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setPriority(int);
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsTag(int);
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder setTrafficStatsUid(int);
+ }
+
+ public static interface BidirectionalStream.Callback {
+ method public void onCanceled(@NonNull android.net.http.BidirectionalStream, @Nullable android.net.http.UrlResponseInfo);
+ method public void onFailed(@NonNull android.net.http.BidirectionalStream, @Nullable android.net.http.UrlResponseInfo, @NonNull android.net.http.HttpException);
+ method public void onReadCompleted(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer, boolean);
+ method public void onResponseHeadersReceived(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo);
+ method public void onResponseTrailersReceived(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull android.net.http.HeaderBlock);
+ method public void onStreamReady(@NonNull android.net.http.BidirectionalStream);
+ method public void onSucceeded(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo);
+ method public void onWriteCompleted(@NonNull android.net.http.BidirectionalStream, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer, boolean);
+ }
+
+ public abstract class CallbackException extends android.net.http.HttpException {
+ ctor protected CallbackException(@Nullable String, @Nullable Throwable);
+ }
+
+ public class ConnectionMigrationOptions {
+ method public int getAllowNonDefaultNetworkUsage();
+ method public int getDefaultNetworkMigration();
+ method public int getPathDegradationMigration();
+ field public static final int MIGRATION_OPTION_DISABLED = 2; // 0x2
+ field public static final int MIGRATION_OPTION_ENABLED = 1; // 0x1
+ field public static final int MIGRATION_OPTION_UNSPECIFIED = 0; // 0x0
+ }
+
+ public static final class ConnectionMigrationOptions.Builder {
+ ctor public ConnectionMigrationOptions.Builder();
+ method @NonNull public android.net.http.ConnectionMigrationOptions build();
+ method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setAllowNonDefaultNetworkUsage(int);
+ method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setDefaultNetworkMigration(int);
+ method @NonNull public android.net.http.ConnectionMigrationOptions.Builder setPathDegradationMigration(int);
+ }
+
+ public final class DnsOptions {
+ method public int getPersistHostCache();
+ method @Nullable public java.time.Duration getPersistHostCachePeriod();
+ method public int getPreestablishConnectionsToStaleDnsResults();
+ method public int getStaleDns();
+ method @Nullable public android.net.http.DnsOptions.StaleDnsOptions getStaleDnsOptions();
+ method public int getUseHttpStackDnsResolver();
+ field public static final int DNS_OPTION_DISABLED = 2; // 0x2
+ field public static final int DNS_OPTION_ENABLED = 1; // 0x1
+ field public static final int DNS_OPTION_UNSPECIFIED = 0; // 0x0
+ }
+
+ public static final class DnsOptions.Builder {
+ ctor public DnsOptions.Builder();
+ method @NonNull public android.net.http.DnsOptions build();
+ method @NonNull public android.net.http.DnsOptions.Builder setPersistHostCache(int);
+ method @NonNull public android.net.http.DnsOptions.Builder setPersistHostCachePeriod(@NonNull java.time.Duration);
+ method @NonNull public android.net.http.DnsOptions.Builder setPreestablishConnectionsToStaleDnsResults(int);
+ method @NonNull public android.net.http.DnsOptions.Builder setStaleDns(int);
+ method @NonNull public android.net.http.DnsOptions.Builder setStaleDnsOptions(@NonNull android.net.http.DnsOptions.StaleDnsOptions);
+ method @NonNull public android.net.http.DnsOptions.Builder setUseHttpStackDnsResolver(int);
+ }
+
+ public static class DnsOptions.StaleDnsOptions {
+ method public int getAllowCrossNetworkUsage();
+ method @Nullable public java.time.Duration getFreshLookupTimeout();
+ method @Nullable public java.time.Duration getMaxExpiredDelay();
+ method public int getUseStaleOnNameNotResolved();
+ }
+
+ public static final class DnsOptions.StaleDnsOptions.Builder {
+ ctor public DnsOptions.StaleDnsOptions.Builder();
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions build();
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setAllowCrossNetworkUsage(int);
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setFreshLookupTimeout(@NonNull java.time.Duration);
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setMaxExpiredDelay(@NonNull java.time.Duration);
+ method @NonNull public android.net.http.DnsOptions.StaleDnsOptions.Builder setUseStaleOnNameNotResolved(int);
+ }
+
+ public abstract class HeaderBlock {
+ ctor public HeaderBlock();
+ method @NonNull public abstract java.util.List<java.util.Map.Entry<java.lang.String,java.lang.String>> getAsList();
+ method @NonNull public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> getAsMap();
+ }
+
+ public abstract class HttpEngine {
+ method public void bindToNetwork(@Nullable android.net.Network);
+ method @NonNull public abstract java.net.URLStreamHandlerFactory createUrlStreamHandlerFactory();
+ method @NonNull public static String getVersionString();
+ method @NonNull public abstract android.net.http.BidirectionalStream.Builder newBidirectionalStreamBuilder(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.http.BidirectionalStream.Callback);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder newUrlRequestBuilder(@NonNull String, @NonNull java.util.concurrent.Executor, @NonNull android.net.http.UrlRequest.Callback);
+ method @NonNull public abstract java.net.URLConnection openConnection(@NonNull java.net.URL) throws java.io.IOException;
+ method public abstract void shutdown();
+ }
+
+ public static class HttpEngine.Builder {
+ ctor public HttpEngine.Builder(@NonNull android.content.Context);
+ method @NonNull public android.net.http.HttpEngine.Builder addPublicKeyPins(@NonNull String, @NonNull java.util.Set<byte[]>, boolean, @NonNull java.time.Instant);
+ method @NonNull public android.net.http.HttpEngine.Builder addQuicHint(@NonNull String, int, int);
+ method @NonNull public android.net.http.HttpEngine build();
+ method @NonNull public String getDefaultUserAgent();
+ method @NonNull public android.net.http.HttpEngine.Builder setConnectionMigrationOptions(@NonNull android.net.http.ConnectionMigrationOptions);
+ method @NonNull public android.net.http.HttpEngine.Builder setDnsOptions(@NonNull android.net.http.DnsOptions);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnableBrotli(boolean);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnableHttp2(boolean);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnableHttpCache(int, long);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnablePublicKeyPinningBypassForLocalTrustAnchors(boolean);
+ method @NonNull public android.net.http.HttpEngine.Builder setEnableQuic(boolean);
+ method @NonNull public android.net.http.HttpEngine.Builder setQuicOptions(@NonNull android.net.http.QuicOptions);
+ method @NonNull public android.net.http.HttpEngine.Builder setStoragePath(@NonNull String);
+ method @NonNull public android.net.http.HttpEngine.Builder setUserAgent(@NonNull String);
+ field public static final int HTTP_CACHE_DISABLED = 0; // 0x0
+ field public static final int HTTP_CACHE_DISK = 3; // 0x3
+ field public static final int HTTP_CACHE_DISK_NO_HTTP = 2; // 0x2
+ field public static final int HTTP_CACHE_IN_MEMORY = 1; // 0x1
+ }
+
+ public class HttpException extends java.io.IOException {
+ ctor public HttpException(@Nullable String, @Nullable Throwable);
+ }
+
+ public final class InlineExecutionProhibitedException extends java.util.concurrent.RejectedExecutionException {
+ ctor public InlineExecutionProhibitedException();
+ }
+
+ public abstract class NetworkException extends android.net.http.HttpException {
+ ctor public NetworkException(@Nullable String, @Nullable Throwable);
+ method public abstract int getErrorCode();
+ method public abstract boolean isImmediatelyRetryable();
+ field public static final int ERROR_ADDRESS_UNREACHABLE = 9; // 0x9
+ field public static final int ERROR_CONNECTION_CLOSED = 5; // 0x5
+ field public static final int ERROR_CONNECTION_REFUSED = 7; // 0x7
+ field public static final int ERROR_CONNECTION_RESET = 8; // 0x8
+ field public static final int ERROR_CONNECTION_TIMED_OUT = 6; // 0x6
+ field public static final int ERROR_HOSTNAME_NOT_RESOLVED = 1; // 0x1
+ field public static final int ERROR_INTERNET_DISCONNECTED = 2; // 0x2
+ field public static final int ERROR_NETWORK_CHANGED = 3; // 0x3
+ field public static final int ERROR_OTHER = 11; // 0xb
+ field public static final int ERROR_QUIC_PROTOCOL_FAILED = 10; // 0xa
+ field public static final int ERROR_TIMED_OUT = 4; // 0x4
+ }
+
+ public abstract class QuicException extends android.net.http.NetworkException {
+ ctor protected QuicException(@Nullable String, @Nullable Throwable);
+ }
+
+ public class QuicOptions {
+ method @NonNull public java.util.Set<java.lang.String> getAllowedQuicHosts();
+ method @Nullable public String getHandshakeUserAgent();
+ method @Nullable public java.time.Duration getIdleConnectionTimeout();
+ method public int getInMemoryServerConfigsCacheSize();
+ method public boolean hasInMemoryServerConfigsCacheSize();
+ }
+
+ public static final class QuicOptions.Builder {
+ ctor public QuicOptions.Builder();
+ method @NonNull public android.net.http.QuicOptions.Builder addAllowedQuicHost(@NonNull String);
+ method @NonNull public android.net.http.QuicOptions build();
+ method @NonNull public android.net.http.QuicOptions.Builder setHandshakeUserAgent(@NonNull String);
+ method @NonNull public android.net.http.QuicOptions.Builder setIdleConnectionTimeout(@NonNull java.time.Duration);
+ method @NonNull public android.net.http.QuicOptions.Builder setInMemoryServerConfigsCacheSize(int);
+ }
+
+ public abstract class UploadDataProvider implements java.io.Closeable {
+ ctor public UploadDataProvider();
+ method public void close() throws java.io.IOException;
+ method public abstract long getLength() throws java.io.IOException;
+ method public abstract void read(@NonNull android.net.http.UploadDataSink, @NonNull java.nio.ByteBuffer) throws java.io.IOException;
+ method public abstract void rewind(@NonNull android.net.http.UploadDataSink) throws java.io.IOException;
+ }
+
+ public abstract class UploadDataSink {
+ ctor public UploadDataSink();
+ method public abstract void onReadError(@NonNull Exception);
+ method public abstract void onReadSucceeded(boolean);
+ method public abstract void onRewindError(@NonNull Exception);
+ method public abstract void onRewindSucceeded();
+ }
+
+ public abstract class UrlRequest {
+ method public abstract void cancel();
+ method public abstract void followRedirect();
+ method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
+ method @Nullable public abstract String getHttpMethod();
+ method public abstract int getPriority();
+ method public abstract void getStatus(@NonNull android.net.http.UrlRequest.StatusListener);
+ method public abstract int getTrafficStatsTag();
+ method public abstract int getTrafficStatsUid();
+ method public abstract boolean hasTrafficStatsTag();
+ method public abstract boolean hasTrafficStatsUid();
+ method public abstract boolean isCacheDisabled();
+ method public abstract boolean isDirectExecutorAllowed();
+ method public abstract boolean isDone();
+ method public abstract void read(@NonNull java.nio.ByteBuffer);
+ method public abstract void start();
+ field public static final int REQUEST_PRIORITY_HIGHEST = 4; // 0x4
+ field public static final int REQUEST_PRIORITY_IDLE = 0; // 0x0
+ field public static final int REQUEST_PRIORITY_LOW = 2; // 0x2
+ field public static final int REQUEST_PRIORITY_LOWEST = 1; // 0x1
+ field public static final int REQUEST_PRIORITY_MEDIUM = 3; // 0x3
+ }
+
+ public abstract static class UrlRequest.Builder {
+ method @NonNull public abstract android.net.http.UrlRequest.Builder addHeader(@NonNull String, @NonNull String);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder bindToNetwork(@Nullable android.net.Network);
+ method @NonNull public abstract android.net.http.UrlRequest build();
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setCacheDisabled(boolean);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setDirectExecutorAllowed(boolean);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setHttpMethod(@NonNull String);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setPriority(int);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setTrafficStatsTag(int);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setTrafficStatsUid(int);
+ method @NonNull public abstract android.net.http.UrlRequest.Builder setUploadDataProvider(@NonNull android.net.http.UploadDataProvider, @NonNull java.util.concurrent.Executor);
+ }
+
+ public static interface UrlRequest.Callback {
+ method public void onCanceled(@NonNull android.net.http.UrlRequest, @Nullable android.net.http.UrlResponseInfo);
+ method public void onFailed(@NonNull android.net.http.UrlRequest, @Nullable android.net.http.UrlResponseInfo, @NonNull android.net.http.HttpException);
+ method public void onReadCompleted(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo, @NonNull java.nio.ByteBuffer) throws java.lang.Exception;
+ method public void onRedirectReceived(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo, @NonNull String) throws java.lang.Exception;
+ method public void onResponseStarted(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo) throws java.lang.Exception;
+ method public void onSucceeded(@NonNull android.net.http.UrlRequest, @NonNull android.net.http.UrlResponseInfo);
+ }
+
+ public static class UrlRequest.Status {
+ field public static final int CONNECTING = 10; // 0xa
+ field public static final int DOWNLOADING_PAC_FILE = 5; // 0x5
+ field public static final int ESTABLISHING_PROXY_TUNNEL = 8; // 0x8
+ field public static final int IDLE = 0; // 0x0
+ field public static final int INVALID = -1; // 0xffffffff
+ field public static final int READING_RESPONSE = 14; // 0xe
+ field public static final int RESOLVING_HOST = 9; // 0x9
+ field public static final int RESOLVING_HOST_IN_PAC_FILE = 7; // 0x7
+ field public static final int RESOLVING_PROXY_FOR_URL = 6; // 0x6
+ field public static final int SENDING_REQUEST = 12; // 0xc
+ field public static final int SSL_HANDSHAKE = 11; // 0xb
+ field public static final int WAITING_FOR_AVAILABLE_SOCKET = 2; // 0x2
+ field public static final int WAITING_FOR_CACHE = 4; // 0x4
+ field public static final int WAITING_FOR_DELEGATE = 3; // 0x3
+ field public static final int WAITING_FOR_RESPONSE = 13; // 0xd
+ field public static final int WAITING_FOR_STALLED_SOCKET_POOL = 1; // 0x1
+ }
+
+ public static interface UrlRequest.StatusListener {
+ method public void onStatus(int);
+ }
+
+ public abstract class UrlResponseInfo {
+ ctor public UrlResponseInfo();
+ method @NonNull public abstract android.net.http.HeaderBlock getHeaders();
+ method public abstract int getHttpStatusCode();
+ method @NonNull public abstract String getHttpStatusText();
+ method @NonNull public abstract String getNegotiatedProtocol();
+ method public abstract long getReceivedByteCount();
+ method @NonNull public abstract String getUrl();
+ method @NonNull public abstract java.util.List<java.lang.String> getUrlChain();
+ method public abstract boolean wasCached();
+ }
+
+}
+
diff --git a/framework/cronet_disabled/api/current.txt b/framework/cronet_disabled/api/current.txt
new file mode 100644
index 0000000..672e3e2
--- /dev/null
+++ b/framework/cronet_disabled/api/current.txt
@@ -0,0 +1,527 @@
+// Signature format: 2.0
+package android.net {
+
+ public class CaptivePortal implements android.os.Parcelable {
+ method public int describeContents();
+ method public void ignoreNetwork();
+ method public void reportCaptivePortalDismissed();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortal> CREATOR;
+ }
+
+ public class ConnectivityDiagnosticsManager {
+ method public void registerConnectivityDiagnosticsCallback(@NonNull android.net.NetworkRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ method public void unregisterConnectivityDiagnosticsCallback(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback);
+ }
+
+ public abstract static class ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback();
+ method public void onConnectivityReportAvailable(@NonNull android.net.ConnectivityDiagnosticsManager.ConnectivityReport);
+ method public void onDataStallSuspected(@NonNull android.net.ConnectivityDiagnosticsManager.DataStallReport);
+ method public void onNetworkConnectivityReported(@NonNull android.net.Network, boolean);
+ }
+
+ public static final class ConnectivityDiagnosticsManager.ConnectivityReport implements android.os.Parcelable {
+ ctor public ConnectivityDiagnosticsManager.ConnectivityReport(@NonNull android.net.Network, long, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+ method public int describeContents();
+ method @NonNull public android.os.PersistableBundle getAdditionalInfo();
+ method @NonNull public android.net.LinkProperties getLinkProperties();
+ method @NonNull public android.net.Network getNetwork();
+ method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+ method public long getReportTimestamp();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.ConnectivityReport> CREATOR;
+ field public static final String KEY_NETWORK_PROBES_ATTEMPTED_BITMASK = "networkProbesAttempted";
+ field public static final String KEY_NETWORK_PROBES_SUCCEEDED_BITMASK = "networkProbesSucceeded";
+ field public static final String KEY_NETWORK_VALIDATION_RESULT = "networkValidationResult";
+ field public static final int NETWORK_PROBE_DNS = 4; // 0x4
+ field public static final int NETWORK_PROBE_FALLBACK = 32; // 0x20
+ field public static final int NETWORK_PROBE_HTTP = 8; // 0x8
+ field public static final int NETWORK_PROBE_HTTPS = 16; // 0x10
+ field public static final int NETWORK_PROBE_PRIVATE_DNS = 64; // 0x40
+ field public static final int NETWORK_VALIDATION_RESULT_INVALID = 0; // 0x0
+ field public static final int NETWORK_VALIDATION_RESULT_PARTIALLY_VALID = 2; // 0x2
+ field public static final int NETWORK_VALIDATION_RESULT_SKIPPED = 3; // 0x3
+ field public static final int NETWORK_VALIDATION_RESULT_VALID = 1; // 0x1
+ }
+
+ public static final class ConnectivityDiagnosticsManager.DataStallReport implements android.os.Parcelable {
+ ctor public ConnectivityDiagnosticsManager.DataStallReport(@NonNull android.net.Network, long, int, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkCapabilities, @NonNull android.os.PersistableBundle);
+ method public int describeContents();
+ method public int getDetectionMethod();
+ method @NonNull public android.net.LinkProperties getLinkProperties();
+ method @NonNull public android.net.Network getNetwork();
+ method @NonNull public android.net.NetworkCapabilities getNetworkCapabilities();
+ method public long getReportTimestamp();
+ method @NonNull public android.os.PersistableBundle getStallDetails();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ConnectivityDiagnosticsManager.DataStallReport> CREATOR;
+ field public static final int DETECTION_METHOD_DNS_EVENTS = 1; // 0x1
+ field public static final int DETECTION_METHOD_TCP_METRICS = 2; // 0x2
+ field public static final String KEY_DNS_CONSECUTIVE_TIMEOUTS = "dnsConsecutiveTimeouts";
+ field public static final String KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS = "tcpMetricsCollectionPeriodMillis";
+ field public static final String KEY_TCP_PACKET_FAIL_RATE = "tcpPacketFailRate";
+ }
+
+ public class ConnectivityManager {
+ method public void addDefaultNetworkActiveListener(android.net.ConnectivityManager.OnNetworkActiveListener);
+ method public boolean bindProcessToNetwork(@Nullable android.net.Network);
+ method @NonNull public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull android.net.IpSecManager.UdpEncapsulationSocket, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network getActiveNetwork();
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getActiveNetworkInfo();
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo[] getAllNetworkInfo();
+ method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.Network[] getAllNetworks();
+ method @Deprecated public boolean getBackgroundDataSetting();
+ method @Nullable public android.net.Network getBoundNetworkForProcess();
+ method public int getConnectionOwnerUid(int, @NonNull java.net.InetSocketAddress, @NonNull java.net.InetSocketAddress);
+ method @Nullable public android.net.ProxyInfo getDefaultProxy();
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.LinkProperties getLinkProperties(@Nullable android.net.Network);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getMultipathPreference(@Nullable android.net.Network);
+ method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkCapabilities getNetworkCapabilities(@Nullable android.net.Network);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(int);
+ method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public android.net.NetworkInfo getNetworkInfo(@Nullable android.net.Network);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public int getNetworkPreference();
+ method @Nullable public byte[] getNetworkWatchlistConfigHash();
+ method @Deprecated @Nullable public static android.net.Network getProcessDefaultNetwork();
+ method public int getRestrictBackgroundStatus();
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public boolean isActiveNetworkMetered();
+ method public boolean isDefaultNetworkActive();
+ method @Deprecated public static boolean isNetworkTypeValid(int);
+ method public void registerBestMatchingNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerNetworkCallback(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
+ method public void releaseNetworkRequest(@NonNull android.app.PendingIntent);
+ method public void removeDefaultNetworkActiveListener(@NonNull android.net.ConnectivityManager.OnNetworkActiveListener);
+ method @Deprecated public void reportBadNetwork(@Nullable android.net.Network);
+ method public void reportNetworkConnectivity(@Nullable android.net.Network, boolean);
+ method public boolean requestBandwidthUpdate(@NonNull android.net.Network);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, int);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler, int);
+ method public void requestNetwork(@NonNull android.net.NetworkRequest, @NonNull android.app.PendingIntent);
+ method @Deprecated public void setNetworkPreference(int);
+ method @Deprecated public static boolean setProcessDefaultNetwork(@Nullable android.net.Network);
+ method public void unregisterNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback);
+ method public void unregisterNetworkCallback(@NonNull android.app.PendingIntent);
+ field @Deprecated public static final String ACTION_BACKGROUND_DATA_SETTING_CHANGED = "android.net.conn.BACKGROUND_DATA_SETTING_CHANGED";
+ field public static final String ACTION_CAPTIVE_PORTAL_SIGN_IN = "android.net.conn.CAPTIVE_PORTAL";
+ field public static final String ACTION_RESTRICT_BACKGROUND_CHANGED = "android.net.conn.RESTRICT_BACKGROUND_CHANGED";
+ field @Deprecated public static final String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
+ field @Deprecated public static final int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
+ field public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+ field public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
+ field @Deprecated public static final String EXTRA_EXTRA_INFO = "extraInfo";
+ field @Deprecated public static final String EXTRA_IS_FAILOVER = "isFailover";
+ field public static final String EXTRA_NETWORK = "android.net.extra.NETWORK";
+ field @Deprecated public static final String EXTRA_NETWORK_INFO = "networkInfo";
+ field public static final String EXTRA_NETWORK_REQUEST = "android.net.extra.NETWORK_REQUEST";
+ field @Deprecated public static final String EXTRA_NETWORK_TYPE = "networkType";
+ field public static final String EXTRA_NO_CONNECTIVITY = "noConnectivity";
+ field @Deprecated public static final String EXTRA_OTHER_NETWORK_INFO = "otherNetwork";
+ field public static final String EXTRA_REASON = "reason";
+ field public static final int MULTIPATH_PREFERENCE_HANDOVER = 1; // 0x1
+ field public static final int MULTIPATH_PREFERENCE_PERFORMANCE = 4; // 0x4
+ field public static final int MULTIPATH_PREFERENCE_RELIABILITY = 2; // 0x2
+ field public static final int RESTRICT_BACKGROUND_STATUS_DISABLED = 1; // 0x1
+ field public static final int RESTRICT_BACKGROUND_STATUS_ENABLED = 3; // 0x3
+ field public static final int RESTRICT_BACKGROUND_STATUS_WHITELISTED = 2; // 0x2
+ field @Deprecated public static final int TYPE_BLUETOOTH = 7; // 0x7
+ field @Deprecated public static final int TYPE_DUMMY = 8; // 0x8
+ field @Deprecated public static final int TYPE_ETHERNET = 9; // 0x9
+ field @Deprecated public static final int TYPE_MOBILE = 0; // 0x0
+ field @Deprecated public static final int TYPE_MOBILE_DUN = 4; // 0x4
+ field @Deprecated public static final int TYPE_MOBILE_HIPRI = 5; // 0x5
+ field @Deprecated public static final int TYPE_MOBILE_MMS = 2; // 0x2
+ field @Deprecated public static final int TYPE_MOBILE_SUPL = 3; // 0x3
+ field @Deprecated public static final int TYPE_VPN = 17; // 0x11
+ field @Deprecated public static final int TYPE_WIFI = 1; // 0x1
+ field @Deprecated public static final int TYPE_WIMAX = 6; // 0x6
+ }
+
+ public static class ConnectivityManager.NetworkCallback {
+ ctor public ConnectivityManager.NetworkCallback();
+ ctor public ConnectivityManager.NetworkCallback(int);
+ method public void onAvailable(@NonNull android.net.Network);
+ method public void onBlockedStatusChanged(@NonNull android.net.Network, boolean);
+ method public void onCapabilitiesChanged(@NonNull android.net.Network, @NonNull android.net.NetworkCapabilities);
+ method public void onLinkPropertiesChanged(@NonNull android.net.Network, @NonNull android.net.LinkProperties);
+ method public void onLosing(@NonNull android.net.Network, int);
+ method public void onLost(@NonNull android.net.Network);
+ method public void onUnavailable();
+ field public static final int FLAG_INCLUDE_LOCATION_INFO = 1; // 0x1
+ }
+
+ public static interface ConnectivityManager.OnNetworkActiveListener {
+ method public void onNetworkActive();
+ }
+
+ public class DhcpInfo implements android.os.Parcelable {
+ ctor public DhcpInfo();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpInfo> CREATOR;
+ field public int dns1;
+ field public int dns2;
+ field public int gateway;
+ field public int ipAddress;
+ field public int leaseDuration;
+ field public int netmask;
+ field public int serverAddress;
+ }
+
+ public final class DnsResolver {
+ method @NonNull public static android.net.DnsResolver getInstance();
+ method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
+ method public void query(@Nullable android.net.Network, @NonNull String, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super java.util.List<java.net.InetAddress>>);
+ method public void rawQuery(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
+ method public void rawQuery(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.Callback<? super byte[]>);
+ field public static final int CLASS_IN = 1; // 0x1
+ field public static final int ERROR_PARSE = 0; // 0x0
+ field public static final int ERROR_SYSTEM = 1; // 0x1
+ field public static final int FLAG_EMPTY = 0; // 0x0
+ field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
+ field public static final int FLAG_NO_CACHE_STORE = 2; // 0x2
+ field public static final int FLAG_NO_RETRY = 1; // 0x1
+ field public static final int TYPE_A = 1; // 0x1
+ field public static final int TYPE_AAAA = 28; // 0x1c
+ }
+
+ public static interface DnsResolver.Callback<T> {
+ method public void onAnswer(@NonNull T, int);
+ method public void onError(@NonNull android.net.DnsResolver.DnsException);
+ }
+
+ public static class DnsResolver.DnsException extends java.lang.Exception {
+ ctor public DnsResolver.DnsException(int, @Nullable Throwable);
+ field public final int code;
+ }
+
+ public class InetAddresses {
+ method public static boolean isNumericAddress(@NonNull String);
+ method @NonNull public static java.net.InetAddress parseNumericAddress(@NonNull String);
+ }
+
+ public final class IpConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method @Nullable public android.net.ProxyInfo getHttpProxy();
+ method @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.IpConfiguration> CREATOR;
+ }
+
+ public static final class IpConfiguration.Builder {
+ ctor public IpConfiguration.Builder();
+ method @NonNull public android.net.IpConfiguration build();
+ method @NonNull public android.net.IpConfiguration.Builder setHttpProxy(@Nullable android.net.ProxyInfo);
+ method @NonNull public android.net.IpConfiguration.Builder setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ }
+
+ public final class IpPrefix implements android.os.Parcelable {
+ ctor public IpPrefix(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
+ method public boolean contains(@NonNull java.net.InetAddress);
+ method public int describeContents();
+ method @NonNull public java.net.InetAddress getAddress();
+ method @IntRange(from=0, to=128) public int getPrefixLength();
+ method @NonNull public byte[] getRawAddress();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
+ }
+
+ public class LinkAddress implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.net.InetAddress getAddress();
+ method public int getFlags();
+ method @IntRange(from=0, to=128) public int getPrefixLength();
+ method public int getScope();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR;
+ }
+
+ public final class LinkProperties implements android.os.Parcelable {
+ ctor public LinkProperties();
+ method public boolean addRoute(@NonNull android.net.RouteInfo);
+ method public void clear();
+ method public int describeContents();
+ method @Nullable public java.net.Inet4Address getDhcpServerAddress();
+ method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+ method @Nullable public String getDomains();
+ method @Nullable public android.net.ProxyInfo getHttpProxy();
+ method @Nullable public String getInterfaceName();
+ method @NonNull public java.util.List<android.net.LinkAddress> getLinkAddresses();
+ method public int getMtu();
+ method @Nullable public android.net.IpPrefix getNat64Prefix();
+ method @Nullable public String getPrivateDnsServerName();
+ method @NonNull public java.util.List<android.net.RouteInfo> getRoutes();
+ method public boolean isPrivateDnsActive();
+ method public boolean isWakeOnLanSupported();
+ method public void setDhcpServerAddress(@Nullable java.net.Inet4Address);
+ method public void setDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
+ method public void setDomains(@Nullable String);
+ method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+ method public void setInterfaceName(@Nullable String);
+ method public void setLinkAddresses(@NonNull java.util.Collection<android.net.LinkAddress>);
+ method public void setMtu(int);
+ method public void setNat64Prefix(@Nullable android.net.IpPrefix);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR;
+ }
+
+ public final class MacAddress implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public static android.net.MacAddress fromBytes(@NonNull byte[]);
+ method @NonNull public static android.net.MacAddress fromString(@NonNull String);
+ method public int getAddressType();
+ method @Nullable public java.net.Inet6Address getLinkLocalIpv6FromEui48Mac();
+ method public boolean isLocallyAssigned();
+ method public boolean matches(@NonNull android.net.MacAddress, @NonNull android.net.MacAddress);
+ method @NonNull public byte[] toByteArray();
+ method @NonNull public String toOuiString();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.net.MacAddress BROADCAST_ADDRESS;
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
+ field public static final int TYPE_BROADCAST = 3; // 0x3
+ field public static final int TYPE_MULTICAST = 2; // 0x2
+ field public static final int TYPE_UNICAST = 1; // 0x1
+ }
+
+ public class Network implements android.os.Parcelable {
+ method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException;
+ method public void bindSocket(java.net.Socket) throws java.io.IOException;
+ method public void bindSocket(java.io.FileDescriptor) throws java.io.IOException;
+ method public int describeContents();
+ method public static android.net.Network fromNetworkHandle(long);
+ method public java.net.InetAddress[] getAllByName(String) throws java.net.UnknownHostException;
+ method public java.net.InetAddress getByName(String) throws java.net.UnknownHostException;
+ method public long getNetworkHandle();
+ method public javax.net.SocketFactory getSocketFactory();
+ method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException;
+ method public java.net.URLConnection openConnection(java.net.URL, java.net.Proxy) throws java.io.IOException;
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.Network> CREATOR;
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ ctor public NetworkCapabilities();
+ ctor public NetworkCapabilities(android.net.NetworkCapabilities);
+ method public int describeContents();
+ method @NonNull public int[] getCapabilities();
+ method @NonNull public int[] getEnterpriseIds();
+ method public int getLinkDownstreamBandwidthKbps();
+ method public int getLinkUpstreamBandwidthKbps();
+ method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+ method public int getOwnerUid();
+ method public int getSignalStrength();
+ method @Nullable public android.net.TransportInfo getTransportInfo();
+ method public boolean hasCapability(int);
+ method public boolean hasEnterpriseId(int);
+ method public boolean hasTransport(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
+ field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
+ field public static final int NET_CAPABILITY_CBS = 5; // 0x5
+ field public static final int NET_CAPABILITY_DUN = 2; // 0x2
+ field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
+ field public static final int NET_CAPABILITY_ENTERPRISE = 29; // 0x1d
+ field public static final int NET_CAPABILITY_FOREGROUND = 19; // 0x13
+ field public static final int NET_CAPABILITY_FOTA = 3; // 0x3
+ field public static final int NET_CAPABILITY_HEAD_UNIT = 32; // 0x20
+ field public static final int NET_CAPABILITY_IA = 7; // 0x7
+ field public static final int NET_CAPABILITY_IMS = 4; // 0x4
+ field public static final int NET_CAPABILITY_INTERNET = 12; // 0xc
+ field public static final int NET_CAPABILITY_MCX = 23; // 0x17
+ field public static final int NET_CAPABILITY_MMS = 0; // 0x0
+ field public static final int NET_CAPABILITY_MMTEL = 33; // 0x21
+ field public static final int NET_CAPABILITY_NOT_CONGESTED = 20; // 0x14
+ field public static final int NET_CAPABILITY_NOT_METERED = 11; // 0xb
+ field public static final int NET_CAPABILITY_NOT_RESTRICTED = 13; // 0xd
+ field public static final int NET_CAPABILITY_NOT_ROAMING = 18; // 0x12
+ field public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; // 0x15
+ field public static final int NET_CAPABILITY_NOT_VPN = 15; // 0xf
+ field public static final int NET_CAPABILITY_PRIORITIZE_BANDWIDTH = 35; // 0x23
+ field public static final int NET_CAPABILITY_PRIORITIZE_LATENCY = 34; // 0x22
+ field public static final int NET_CAPABILITY_RCS = 8; // 0x8
+ field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
+ field public static final int NET_CAPABILITY_TEMPORARILY_NOT_METERED = 25; // 0x19
+ field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
+ field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
+ field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
+ field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
+ field public static final int NET_ENTERPRISE_ID_1 = 1; // 0x1
+ field public static final int NET_ENTERPRISE_ID_2 = 2; // 0x2
+ field public static final int NET_ENTERPRISE_ID_3 = 3; // 0x3
+ field public static final int NET_ENTERPRISE_ID_4 = 4; // 0x4
+ field public static final int NET_ENTERPRISE_ID_5 = 5; // 0x5
+ field public static final int SIGNAL_STRENGTH_UNSPECIFIED = -2147483648; // 0x80000000
+ field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
+ field public static final int TRANSPORT_CELLULAR = 0; // 0x0
+ field public static final int TRANSPORT_ETHERNET = 3; // 0x3
+ field public static final int TRANSPORT_LOWPAN = 6; // 0x6
+ field public static final int TRANSPORT_THREAD = 9; // 0x9
+ field public static final int TRANSPORT_USB = 8; // 0x8
+ field public static final int TRANSPORT_VPN = 4; // 0x4
+ field public static final int TRANSPORT_WIFI = 1; // 0x1
+ field public static final int TRANSPORT_WIFI_AWARE = 5; // 0x5
+ }
+
+ @Deprecated public class NetworkInfo implements android.os.Parcelable {
+ ctor @Deprecated public NetworkInfo(int, int, @Nullable String, @Nullable String);
+ method @Deprecated public int describeContents();
+ method @Deprecated @NonNull public android.net.NetworkInfo.DetailedState getDetailedState();
+ method @Deprecated public String getExtraInfo();
+ method @Deprecated public String getReason();
+ method @Deprecated public android.net.NetworkInfo.State getState();
+ method @Deprecated public int getSubtype();
+ method @Deprecated public String getSubtypeName();
+ method @Deprecated public int getType();
+ method @Deprecated public String getTypeName();
+ method @Deprecated public boolean isAvailable();
+ method @Deprecated public boolean isConnected();
+ method @Deprecated public boolean isConnectedOrConnecting();
+ method @Deprecated public boolean isFailover();
+ method @Deprecated public boolean isRoaming();
+ method @Deprecated public void setDetailedState(@NonNull android.net.NetworkInfo.DetailedState, @Nullable String, @Nullable String);
+ method @Deprecated public void writeToParcel(android.os.Parcel, int);
+ field @Deprecated @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkInfo> CREATOR;
+ }
+
+ @Deprecated public enum NetworkInfo.DetailedState {
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState AUTHENTICATING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState BLOCKED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CAPTIVE_PORTAL_CHECK;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState CONNECTING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState DISCONNECTING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState FAILED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState IDLE;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState OBTAINING_IPADDR;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SCANNING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState SUSPENDED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.DetailedState VERIFYING_POOR_LINK;
+ }
+
+ @Deprecated public enum NetworkInfo.State {
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State CONNECTING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State DISCONNECTING;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State SUSPENDED;
+ enum_constant @Deprecated public static final android.net.NetworkInfo.State UNKNOWN;
+ }
+
+ public class NetworkRequest implements android.os.Parcelable {
+ method public boolean canBeSatisfiedBy(@Nullable android.net.NetworkCapabilities);
+ method public int describeContents();
+ method @NonNull public int[] getCapabilities();
+ method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
+ method @NonNull public int[] getTransportTypes();
+ method public boolean hasCapability(int);
+ method public boolean hasTransport(int);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR;
+ }
+
+ public static class NetworkRequest.Builder {
+ ctor public NetworkRequest.Builder();
+ ctor public NetworkRequest.Builder(@NonNull android.net.NetworkRequest);
+ method public android.net.NetworkRequest.Builder addCapability(int);
+ method public android.net.NetworkRequest.Builder addTransportType(int);
+ method public android.net.NetworkRequest build();
+ method @NonNull public android.net.NetworkRequest.Builder clearCapabilities();
+ method public android.net.NetworkRequest.Builder removeCapability(int);
+ method public android.net.NetworkRequest.Builder removeTransportType(int);
+ method @NonNull public android.net.NetworkRequest.Builder setIncludeOtherUidNetworks(boolean);
+ method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
+ method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
+ }
+
+ public class ParseException extends java.lang.RuntimeException {
+ ctor public ParseException(@NonNull String);
+ ctor public ParseException(@NonNull String, @NonNull Throwable);
+ field public String response;
+ }
+
+ public class ProxyInfo implements android.os.Parcelable {
+ ctor public ProxyInfo(@Nullable android.net.ProxyInfo);
+ method public static android.net.ProxyInfo buildDirectProxy(String, int);
+ method public static android.net.ProxyInfo buildDirectProxy(String, int, java.util.List<java.lang.String>);
+ method public static android.net.ProxyInfo buildPacProxy(android.net.Uri);
+ method @NonNull public static android.net.ProxyInfo buildPacProxy(@NonNull android.net.Uri, int);
+ method public int describeContents();
+ method public String[] getExclusionList();
+ method public String getHost();
+ method public android.net.Uri getPacFileUrl();
+ method public int getPort();
+ method public boolean isValid();
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR;
+ }
+
+ public final class RouteInfo implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.IpPrefix getDestination();
+ method @Nullable public java.net.InetAddress getGateway();
+ method @Nullable public String getInterface();
+ method public int getType();
+ method public boolean hasGateway();
+ method public boolean isDefaultRoute();
+ method public boolean matches(java.net.InetAddress);
+ method public void writeToParcel(android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR;
+ field public static final int RTN_THROW = 9; // 0x9
+ field public static final int RTN_UNICAST = 1; // 0x1
+ field public static final int RTN_UNREACHABLE = 7; // 0x7
+ }
+
+ public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+ method public final void close();
+ method public final void start(@IntRange(from=0xa, to=0xe10) int);
+ method public final void stop();
+ field public static final int ERROR_HARDWARE_ERROR = -31; // 0xffffffe1
+ field public static final int ERROR_INSUFFICIENT_RESOURCES = -32; // 0xffffffe0
+ field public static final int ERROR_INVALID_INTERVAL = -24; // 0xffffffe8
+ field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
+ field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
+ field public static final int ERROR_INVALID_NETWORK = -20; // 0xffffffec
+ field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
+ field public static final int ERROR_INVALID_SOCKET = -25; // 0xffffffe7
+ field public static final int ERROR_SOCKET_NOT_IDLE = -26; // 0xffffffe6
+ field public static final int ERROR_UNSUPPORTED = -30; // 0xffffffe2
+ }
+
+ public static class SocketKeepalive.Callback {
+ ctor public SocketKeepalive.Callback();
+ method public void onDataReceived();
+ method public void onError(int);
+ method public void onStarted();
+ method public void onStopped();
+ }
+
+ public final class StaticIpConfiguration implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.List<java.net.InetAddress> getDnsServers();
+ method @Nullable public String getDomains();
+ method @Nullable public java.net.InetAddress getGateway();
+ method @NonNull public android.net.LinkAddress getIpAddress();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.StaticIpConfiguration> CREATOR;
+ }
+
+ public static final class StaticIpConfiguration.Builder {
+ ctor public StaticIpConfiguration.Builder();
+ method @NonNull public android.net.StaticIpConfiguration build();
+ method @NonNull public android.net.StaticIpConfiguration.Builder setDnsServers(@NonNull Iterable<java.net.InetAddress>);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setDomains(@Nullable String);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setGateway(@Nullable java.net.InetAddress);
+ method @NonNull public android.net.StaticIpConfiguration.Builder setIpAddress(@NonNull android.net.LinkAddress);
+ }
+
+ public interface TransportInfo {
+ }
+
+}
+
diff --git a/framework/cronet_disabled/api/lint-baseline.txt b/framework/cronet_disabled/api/lint-baseline.txt
new file mode 100644
index 0000000..2f4004a
--- /dev/null
+++ b/framework/cronet_disabled/api/lint-baseline.txt
@@ -0,0 +1,4 @@
+// Baseline format: 1.0
+VisiblySynchronized: android.net.NetworkInfo#toString():
+ Internal locks must not be exposed (synchronizing on this or class is still
+ externally observable): method android.net.NetworkInfo.toString()
diff --git a/framework/cronet_disabled/api/module-lib-current.txt b/framework/cronet_disabled/api/module-lib-current.txt
new file mode 100644
index 0000000..193bd92
--- /dev/null
+++ b/framework/cronet_disabled/api/module-lib-current.txt
@@ -0,0 +1,239 @@
+// Signature format: 2.0
+package android.net {
+
+ public final class ConnectivityFrameworkInitializer {
+ method public static void registerServiceWrappers();
+ }
+
+ public class ConnectivityManager {
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void addUidToMeteredNetworkAllowList(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void addUidToMeteredNetworkDenyList(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void factoryReset();
+ method @NonNull @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public java.util.List<android.net.NetworkStateSnapshot> getAllNetworkStateSnapshots();
+ method @Nullable public android.net.ProxyInfo getGlobalProxy();
+ method @NonNull public static android.util.Range<java.lang.Integer> getIpSecNetIdRange();
+ method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.LinkProperties getRedactedLinkPropertiesForPackage(@NonNull android.net.LinkProperties, int, @NonNull String);
+ method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public android.net.NetworkCapabilities getRedactedNetworkCapabilitiesForPackage(@NonNull android.net.NetworkCapabilities, int, @NonNull String);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void registerDefaultNetworkCallbackForUid(int, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS}) public void registerSystemDefaultNetworkCallback(@NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkAllowList(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void removeUidFromMeteredNetworkDenyList(int);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void replaceFirewallChain(int, @NonNull int[]);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void requestBackgroundNetwork(@NonNull android.net.NetworkRequest, @NonNull android.net.ConnectivityManager.NetworkCallback, @NonNull android.os.Handler);
+ method @Deprecated public boolean requestRouteToHostAddress(int, java.net.InetAddress);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptPartialConnectivity(@NonNull android.net.Network, boolean, boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAcceptUnvalidated(@NonNull android.net.Network, boolean, boolean);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setAvoidUnvalidated(@NonNull android.net.Network);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setFirewallChainEnabled(int, boolean);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setGlobalProxy(@Nullable android.net.ProxyInfo);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setLegacyLockdownVpnEnabled(boolean);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreference(@NonNull android.os.UserHandle, int, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void setProfileNetworkPreferences(@NonNull android.os.UserHandle, @NonNull java.util.List<android.net.ProfileNetworkPreference>, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setRequireVpnForUids(boolean, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void setUidFirewallRule(int, int, int);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK, android.Manifest.permission.NETWORK_SETTINGS}) public void setVpnDefaultForUids(@NonNull String, @NonNull java.util.Collection<android.util.Range<java.lang.Integer>>);
+ method @RequiresPermission(anyOf={android.Manifest.permission.MANAGE_TEST_NETWORKS, android.Manifest.permission.NETWORK_STACK}) public void simulateDataStall(int, long, @NonNull android.net.Network, @NonNull android.os.PersistableBundle);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_STACK, android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}) public void startCaptivePortalApp(@NonNull android.net.Network);
+ method public void systemReady();
+ field public static final String ACTION_CLEAR_DNS_CACHE = "android.net.action.CLEAR_DNS_CACHE";
+ field public static final String ACTION_PROMPT_LOST_VALIDATION = "android.net.action.PROMPT_LOST_VALIDATION";
+ field public static final String ACTION_PROMPT_PARTIAL_CONNECTIVITY = "android.net.action.PROMPT_PARTIAL_CONNECTIVITY";
+ field public static final String ACTION_PROMPT_UNVALIDATED = "android.net.action.PROMPT_UNVALIDATED";
+ field public static final int BLOCKED_METERED_REASON_ADMIN_DISABLED = 262144; // 0x40000
+ field public static final int BLOCKED_METERED_REASON_DATA_SAVER = 65536; // 0x10000
+ field public static final int BLOCKED_METERED_REASON_MASK = -65536; // 0xffff0000
+ field public static final int BLOCKED_METERED_REASON_USER_RESTRICTED = 131072; // 0x20000
+ field public static final int BLOCKED_REASON_APP_STANDBY = 4; // 0x4
+ field public static final int BLOCKED_REASON_BATTERY_SAVER = 1; // 0x1
+ field public static final int BLOCKED_REASON_DOZE = 2; // 0x2
+ field public static final int BLOCKED_REASON_LOCKDOWN_VPN = 16; // 0x10
+ field public static final int BLOCKED_REASON_LOW_POWER_STANDBY = 32; // 0x20
+ field public static final int BLOCKED_REASON_NONE = 0; // 0x0
+ field public static final int BLOCKED_REASON_RESTRICTED_MODE = 8; // 0x8
+ field public static final int FIREWALL_CHAIN_DOZABLE = 1; // 0x1
+ field public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5; // 0x5
+ field public static final int FIREWALL_CHAIN_OEM_DENY_1 = 7; // 0x7
+ field public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8; // 0x8
+ field public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9; // 0x9
+ field public static final int FIREWALL_CHAIN_POWERSAVE = 3; // 0x3
+ field public static final int FIREWALL_CHAIN_RESTRICTED = 4; // 0x4
+ field public static final int FIREWALL_CHAIN_STANDBY = 2; // 0x2
+ field public static final int FIREWALL_RULE_ALLOW = 1; // 0x1
+ field public static final int FIREWALL_RULE_DEFAULT = 0; // 0x0
+ field public static final int FIREWALL_RULE_DENY = 2; // 0x2
+ field public static final int PROFILE_NETWORK_PREFERENCE_DEFAULT = 0; // 0x0
+ field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE = 1; // 0x1
+ field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_BLOCKING = 3; // 0x3
+ field public static final int PROFILE_NETWORK_PREFERENCE_ENTERPRISE_NO_FALLBACK = 2; // 0x2
+ }
+
+ public static class ConnectivityManager.NetworkCallback {
+ method public void onBlockedStatusChanged(@NonNull android.net.Network, int);
+ }
+
+ public class ConnectivitySettingsManager {
+ method public static void clearGlobalProxy(@NonNull android.content.Context);
+ method @Nullable public static String getCaptivePortalHttpUrl(@NonNull android.content.Context);
+ method public static int getCaptivePortalMode(@NonNull android.content.Context, int);
+ method @NonNull public static java.time.Duration getConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method @NonNull public static android.util.Range<java.lang.Integer> getDnsResolverSampleRanges(@NonNull android.content.Context);
+ method @NonNull public static java.time.Duration getDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static int getDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, int);
+ method @Nullable public static android.net.ProxyInfo getGlobalProxy(@NonNull android.content.Context);
+ method public static long getIngressRateLimitInBytesPerSecond(@NonNull android.content.Context);
+ method @NonNull public static java.time.Duration getMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static boolean getMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+ method @NonNull public static java.util.Set<java.lang.Integer> getMobileDataPreferredUids(@NonNull android.content.Context);
+ method public static int getNetworkAvoidBadWifi(@NonNull android.content.Context);
+ method @Nullable public static String getNetworkMeteredMultipathPreference(@NonNull android.content.Context);
+ method public static int getNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, int);
+ method @NonNull public static java.time.Duration getNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method @NonNull public static String getPrivateDnsDefaultMode(@NonNull android.content.Context);
+ method @Nullable public static String getPrivateDnsHostname(@NonNull android.content.Context);
+ method public static int getPrivateDnsMode(@NonNull android.content.Context);
+ method @NonNull public static java.util.Set<java.lang.Integer> getUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context);
+ method public static boolean getWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+ method @NonNull public static java.time.Duration getWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setCaptivePortalHttpUrl(@NonNull android.content.Context, @Nullable String);
+ method public static void setCaptivePortalMode(@NonNull android.content.Context, int);
+ method public static void setConnectivityKeepPendingIntentDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setDnsResolverSampleRanges(@NonNull android.content.Context, @NonNull android.util.Range<java.lang.Integer>);
+ method public static void setDnsResolverSampleValidityDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setDnsResolverSuccessThresholdPercent(@NonNull android.content.Context, @IntRange(from=0, to=100) int);
+ method public static void setGlobalProxy(@NonNull android.content.Context, @NonNull android.net.ProxyInfo);
+ method public static void setIngressRateLimitInBytesPerSecond(@NonNull android.content.Context, @IntRange(from=-1L, to=4294967295L) long);
+ method public static void setMobileDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setMobileDataAlwaysOn(@NonNull android.content.Context, boolean);
+ method public static void setMobileDataPreferredUids(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
+ method public static void setNetworkAvoidBadWifi(@NonNull android.content.Context, int);
+ method public static void setNetworkMeteredMultipathPreference(@NonNull android.content.Context, @NonNull String);
+ method public static void setNetworkSwitchNotificationMaximumDailyCount(@NonNull android.content.Context, @IntRange(from=0) int);
+ method public static void setNetworkSwitchNotificationRateDuration(@NonNull android.content.Context, @NonNull java.time.Duration);
+ method public static void setPrivateDnsDefaultMode(@NonNull android.content.Context, @NonNull int);
+ method public static void setPrivateDnsHostname(@NonNull android.content.Context, @Nullable String);
+ method public static void setPrivateDnsMode(@NonNull android.content.Context, int);
+ method public static void setUidsAllowedOnRestrictedNetworks(@NonNull android.content.Context, @NonNull java.util.Set<java.lang.Integer>);
+ method public static void setWifiAlwaysRequested(@NonNull android.content.Context, boolean);
+ method public static void setWifiDataActivityTimeout(@NonNull android.content.Context, @NonNull java.time.Duration);
+ field public static final int CAPTIVE_PORTAL_MODE_AVOID = 2; // 0x2
+ field public static final int CAPTIVE_PORTAL_MODE_IGNORE = 0; // 0x0
+ field public static final int CAPTIVE_PORTAL_MODE_PROMPT = 1; // 0x1
+ field public static final int NETWORK_AVOID_BAD_WIFI_AVOID = 2; // 0x2
+ field public static final int NETWORK_AVOID_BAD_WIFI_IGNORE = 0; // 0x0
+ field public static final int NETWORK_AVOID_BAD_WIFI_PROMPT = 1; // 0x1
+ field public static final int PRIVATE_DNS_MODE_OFF = 1; // 0x1
+ field public static final int PRIVATE_DNS_MODE_OPPORTUNISTIC = 2; // 0x2
+ field public static final int PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = 3; // 0x3
+ }
+
+ public final class DhcpOption implements android.os.Parcelable {
+ ctor public DhcpOption(byte, @Nullable byte[]);
+ method public int describeContents();
+ method public byte getType();
+ method @Nullable public byte[] getValue();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.DhcpOption> CREATOR;
+ }
+
+ public final class NetworkAgentConfig implements android.os.Parcelable {
+ method @Nullable public String getSubscriberId();
+ method public boolean isBypassableVpn();
+ method public boolean isVpnValidationRequired();
+ }
+
+ public static final class NetworkAgentConfig.Builder {
+ method @NonNull public android.net.NetworkAgentConfig.Builder setBypassableVpn(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLocalRoutesExcludedForVpn(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setSubscriberId(@Nullable String);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setVpnRequiresValidation(boolean);
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public java.util.Set<java.lang.Integer> getAllowedUids();
+ method @Nullable public java.util.Set<android.util.Range<java.lang.Integer>> getUids();
+ method public boolean hasForbiddenCapability(int);
+ field public static final long REDACT_ALL = -1L; // 0xffffffffffffffffL
+ field public static final long REDACT_FOR_ACCESS_FINE_LOCATION = 1L; // 0x1L
+ field public static final long REDACT_FOR_LOCAL_MAC_ADDRESS = 2L; // 0x2L
+ field public static final long REDACT_FOR_NETWORK_SETTINGS = 4L; // 0x4L
+ field public static final long REDACT_NONE = 0L; // 0x0L
+ field public static final int TRANSPORT_TEST = 7; // 0x7
+ }
+
+ public static final class NetworkCapabilities.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAllowedUids(@NonNull java.util.Set<java.lang.Integer>);
+ method @NonNull public android.net.NetworkCapabilities.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
+ }
+
+ public class NetworkRequest implements android.os.Parcelable {
+ method @NonNull public int[] getEnterpriseIds();
+ method @NonNull public int[] getForbiddenCapabilities();
+ method public boolean hasEnterpriseId(int);
+ method public boolean hasForbiddenCapability(int);
+ }
+
+ public static class NetworkRequest.Builder {
+ method @NonNull public android.net.NetworkRequest.Builder addForbiddenCapability(int);
+ method @NonNull public android.net.NetworkRequest.Builder removeForbiddenCapability(int);
+ method @NonNull public android.net.NetworkRequest.Builder setUids(@Nullable java.util.Set<android.util.Range<java.lang.Integer>>);
+ }
+
+ public final class ProfileNetworkPreference implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public int[] getExcludedUids();
+ method @NonNull public int[] getIncludedUids();
+ method public int getPreference();
+ method public int getPreferenceEnterpriseId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.ProfileNetworkPreference> CREATOR;
+ }
+
+ public static final class ProfileNetworkPreference.Builder {
+ ctor public ProfileNetworkPreference.Builder();
+ method @NonNull public android.net.ProfileNetworkPreference build();
+ method @NonNull public android.net.ProfileNetworkPreference.Builder setExcludedUids(@NonNull int[]);
+ method @NonNull public android.net.ProfileNetworkPreference.Builder setIncludedUids(@NonNull int[]);
+ method @NonNull public android.net.ProfileNetworkPreference.Builder setPreference(int);
+ method @NonNull public android.net.ProfileNetworkPreference.Builder setPreferenceEnterpriseId(int);
+ }
+
+ public final class TestNetworkInterface implements android.os.Parcelable {
+ ctor public TestNetworkInterface(@NonNull android.os.ParcelFileDescriptor, @NonNull String);
+ method public int describeContents();
+ method @NonNull public android.os.ParcelFileDescriptor getFileDescriptor();
+ method @NonNull public String getInterfaceName();
+ method @Nullable public android.net.MacAddress getMacAddress();
+ method public int getMtu();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkInterface> CREATOR;
+ }
+
+ public class TestNetworkManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public android.net.TestNetworkInterface createTapInterface();
+ method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public android.net.TestNetworkInterface createTunInterface(@NonNull java.util.Collection<android.net.LinkAddress>);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public void setupTestNetwork(@NonNull String, @NonNull android.os.IBinder);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_TEST_NETWORKS) public void teardownTestNetwork(@NonNull android.net.Network);
+ field public static final String TEST_TAP_PREFIX = "testtap";
+ }
+
+ public final class TestNetworkSpecifier extends android.net.NetworkSpecifier implements android.os.Parcelable {
+ ctor public TestNetworkSpecifier(@NonNull String);
+ method public int describeContents();
+ method @Nullable public String getInterfaceName();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TestNetworkSpecifier> CREATOR;
+ }
+
+ public interface TransportInfo {
+ method public default long getApplicableRedactions();
+ method @NonNull public default android.net.TransportInfo makeCopy(long);
+ }
+
+ public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+ ctor @Deprecated public VpnTransportInfo(int, @Nullable String);
+ method @Nullable public String getSessionId();
+ method @NonNull public android.net.VpnTransportInfo makeCopy(long);
+ }
+
+}
+
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/module-lib-removed.txt b/framework/cronet_disabled/api/module-lib-removed.txt
similarity index 100%
rename from Tethering/common/TetheringLib/cronet_enabled/api/module-lib-removed.txt
rename to framework/cronet_disabled/api/module-lib-removed.txt
diff --git a/framework/cronet_disabled/api/removed.txt b/framework/cronet_disabled/api/removed.txt
new file mode 100644
index 0000000..303a1e6
--- /dev/null
+++ b/framework/cronet_disabled/api/removed.txt
@@ -0,0 +1,11 @@
+// Signature format: 2.0
+package android.net {
+
+ public class ConnectivityManager {
+ method @Deprecated public boolean requestRouteToHost(int, int);
+ method @Deprecated public int startUsingNetworkFeature(int, String);
+ method @Deprecated public int stopUsingNetworkFeature(int, String);
+ }
+
+}
+
diff --git a/framework/cronet_disabled/api/system-current.txt b/framework/cronet_disabled/api/system-current.txt
new file mode 100644
index 0000000..4a2ed8a
--- /dev/null
+++ b/framework/cronet_disabled/api/system-current.txt
@@ -0,0 +1,544 @@
+// Signature format: 2.0
+package android.net {
+
+ public class CaptivePortal implements android.os.Parcelable {
+ method @Deprecated public void logEvent(int, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_STACK) public void reevaluateNetwork();
+ method public void useNetwork();
+ field public static final int APP_REQUEST_REEVALUATION_REQUIRED = 100; // 0x64
+ field public static final int APP_RETURN_DISMISSED = 0; // 0x0
+ field public static final int APP_RETURN_UNWANTED = 1; // 0x1
+ field public static final int APP_RETURN_WANTED_AS_IS = 2; // 0x2
+ }
+
+ public final class CaptivePortalData implements android.os.Parcelable {
+ method public int describeContents();
+ method public long getByteLimit();
+ method public long getExpiryTimeMillis();
+ method public long getRefreshTimeMillis();
+ method @Nullable public android.net.Uri getUserPortalUrl();
+ method public int getUserPortalUrlSource();
+ method @Nullable public CharSequence getVenueFriendlyName();
+ method @Nullable public android.net.Uri getVenueInfoUrl();
+ method public int getVenueInfoUrlSource();
+ method public boolean isCaptive();
+ method public boolean isSessionExtendable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field public static final int CAPTIVE_PORTAL_DATA_SOURCE_OTHER = 0; // 0x0
+ field public static final int CAPTIVE_PORTAL_DATA_SOURCE_PASSPOINT = 1; // 0x1
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.CaptivePortalData> CREATOR;
+ }
+
+ public static class CaptivePortalData.Builder {
+ ctor public CaptivePortalData.Builder();
+ ctor public CaptivePortalData.Builder(@Nullable android.net.CaptivePortalData);
+ method @NonNull public android.net.CaptivePortalData build();
+ method @NonNull public android.net.CaptivePortalData.Builder setBytesRemaining(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setCaptive(boolean);
+ method @NonNull public android.net.CaptivePortalData.Builder setExpiryTime(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setRefreshTime(long);
+ method @NonNull public android.net.CaptivePortalData.Builder setSessionExtendable(boolean);
+ method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri);
+ method @NonNull public android.net.CaptivePortalData.Builder setUserPortalUrl(@Nullable android.net.Uri, int);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueFriendlyName(@Nullable CharSequence);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri);
+ method @NonNull public android.net.CaptivePortalData.Builder setVenueInfoUrl(@Nullable android.net.Uri, int);
+ }
+
+ public class ConnectivityManager {
+ method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull android.os.ParcelFileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+ method @NonNull @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS) public String getCaptivePortalServerUrl();
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEntitlementResultListener);
+ method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public int registerNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void registerQosCallback(@NonNull android.net.QosSocketInfo, @NonNull java.util.concurrent.Executor, @NonNull android.net.QosCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+ method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void requestNetwork(@NonNull android.net.NetworkRequest, int, int, @NonNull android.os.Handler, @NonNull android.net.ConnectivityManager.NetworkCallback);
+ method @RequiresPermission(anyOf={android.Manifest.permission.NETWORK_AIRPLANE_MODE, android.Manifest.permission.NETWORK_SETTINGS, android.Manifest.permission.NETWORK_SETUP_WIZARD, android.Manifest.permission.NETWORK_STACK}) public void setAirplaneMode(boolean);
+ method @RequiresPermission(android.Manifest.permission.CONTROL_OEM_PAID_NETWORK_PREFERENCE) public void setOemNetworkPreference(@NonNull android.net.OemNetworkPreferences, @Nullable java.util.concurrent.Executor, @Nullable Runnable);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public boolean shouldAvoidBadWifi();
+ method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(@NonNull android.net.Network, @NonNull android.os.Bundle);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
+ method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_FACTORY}) public void unregisterNetworkProvider(@NonNull android.net.NetworkProvider);
+ method public void unregisterQosCallback(@NonNull android.net.QosCallback);
+ method @Deprecated @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void unregisterTetheringEventCallback(@NonNull android.net.ConnectivityManager.OnTetheringEventCallback);
+ field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
+ field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
+ field public static final int TETHERING_BLUETOOTH = 2; // 0x2
+ field public static final int TETHERING_USB = 1; // 0x1
+ field public static final int TETHERING_WIFI = 0; // 0x0
+ field @Deprecated public static final int TETHER_ERROR_ENTITLEMENT_UNKONWN = 13; // 0xd
+ field @Deprecated public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
+ field @Deprecated public static final int TETHER_ERROR_PROVISION_FAILED = 11; // 0xb
+ field public static final int TYPE_NONE = -1; // 0xffffffff
+ field @Deprecated public static final int TYPE_PROXY = 16; // 0x10
+ field @Deprecated public static final int TYPE_WIFI_P2P = 13; // 0xd
+ }
+
+ @Deprecated public abstract static class ConnectivityManager.OnStartTetheringCallback {
+ ctor @Deprecated public ConnectivityManager.OnStartTetheringCallback();
+ method @Deprecated public void onTetheringFailed();
+ method @Deprecated public void onTetheringStarted();
+ }
+
+ @Deprecated public static interface ConnectivityManager.OnTetheringEntitlementResultListener {
+ method @Deprecated public void onTetheringEntitlementResult(int);
+ }
+
+ @Deprecated public abstract static class ConnectivityManager.OnTetheringEventCallback {
+ ctor @Deprecated public ConnectivityManager.OnTetheringEventCallback();
+ method @Deprecated public void onUpstreamChanged(@Nullable android.net.Network);
+ }
+
+ public final class DscpPolicy implements android.os.Parcelable {
+ method @Nullable public java.net.InetAddress getDestinationAddress();
+ method @Nullable public android.util.Range<java.lang.Integer> getDestinationPortRange();
+ method public int getDscpValue();
+ method public int getPolicyId();
+ method public int getProtocol();
+ method @Nullable public java.net.InetAddress getSourceAddress();
+ method public int getSourcePort();
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.DscpPolicy> CREATOR;
+ field public static final int PROTOCOL_ANY = -1; // 0xffffffff
+ field public static final int SOURCE_PORT_ANY = -1; // 0xffffffff
+ }
+
+ public static final class DscpPolicy.Builder {
+ ctor public DscpPolicy.Builder(int, int);
+ method @NonNull public android.net.DscpPolicy build();
+ method @NonNull public android.net.DscpPolicy.Builder setDestinationAddress(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.DscpPolicy.Builder setDestinationPortRange(@NonNull android.util.Range<java.lang.Integer>);
+ method @NonNull public android.net.DscpPolicy.Builder setProtocol(int);
+ method @NonNull public android.net.DscpPolicy.Builder setSourceAddress(@NonNull java.net.InetAddress);
+ method @NonNull public android.net.DscpPolicy.Builder setSourcePort(int);
+ }
+
+ public final class InvalidPacketException extends java.lang.Exception {
+ ctor public InvalidPacketException(int);
+ method public int getError();
+ field public static final int ERROR_INVALID_IP_ADDRESS = -21; // 0xffffffeb
+ field public static final int ERROR_INVALID_LENGTH = -23; // 0xffffffe9
+ field public static final int ERROR_INVALID_PORT = -22; // 0xffffffea
+ }
+
+ public final class IpConfiguration implements android.os.Parcelable {
+ ctor public IpConfiguration();
+ ctor public IpConfiguration(@NonNull android.net.IpConfiguration);
+ method @NonNull public android.net.IpConfiguration.IpAssignment getIpAssignment();
+ method @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
+ method public void setHttpProxy(@Nullable android.net.ProxyInfo);
+ method public void setIpAssignment(@NonNull android.net.IpConfiguration.IpAssignment);
+ method public void setProxySettings(@NonNull android.net.IpConfiguration.ProxySettings);
+ method public void setStaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ }
+
+ public enum IpConfiguration.IpAssignment {
+ enum_constant public static final android.net.IpConfiguration.IpAssignment DHCP;
+ enum_constant public static final android.net.IpConfiguration.IpAssignment STATIC;
+ enum_constant public static final android.net.IpConfiguration.IpAssignment UNASSIGNED;
+ }
+
+ public enum IpConfiguration.ProxySettings {
+ enum_constant public static final android.net.IpConfiguration.ProxySettings NONE;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings PAC;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings STATIC;
+ enum_constant public static final android.net.IpConfiguration.ProxySettings UNASSIGNED;
+ }
+
+ public final class IpPrefix implements android.os.Parcelable {
+ ctor public IpPrefix(@NonNull String);
+ }
+
+ public class KeepalivePacketData {
+ ctor protected KeepalivePacketData(@NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull java.net.InetAddress, @IntRange(from=0, to=65535) int, @NonNull byte[]) throws android.net.InvalidPacketException;
+ method @NonNull public java.net.InetAddress getDstAddress();
+ method public int getDstPort();
+ method @NonNull public byte[] getPacket();
+ method @NonNull public java.net.InetAddress getSrcAddress();
+ method public int getSrcPort();
+ }
+
+ public class LinkAddress implements android.os.Parcelable {
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int, int, int, long, long);
+ ctor public LinkAddress(@NonNull java.net.InetAddress, @IntRange(from=0, to=128) int);
+ ctor public LinkAddress(@NonNull String);
+ ctor public LinkAddress(@NonNull String, int, int);
+ method public long getDeprecationTime();
+ method public long getExpirationTime();
+ method public boolean isGlobalPreferred();
+ method public boolean isIpv4();
+ method public boolean isIpv6();
+ method public boolean isSameAddressAs(@Nullable android.net.LinkAddress);
+ field public static final long LIFETIME_PERMANENT = 9223372036854775807L; // 0x7fffffffffffffffL
+ field public static final long LIFETIME_UNKNOWN = -1L; // 0xffffffffffffffffL
+ }
+
+ public final class LinkProperties implements android.os.Parcelable {
+ ctor public LinkProperties(@Nullable android.net.LinkProperties);
+ ctor public LinkProperties(@Nullable android.net.LinkProperties, boolean);
+ method public boolean addDnsServer(@NonNull java.net.InetAddress);
+ method public boolean addLinkAddress(@NonNull android.net.LinkAddress);
+ method public boolean addPcscfServer(@NonNull java.net.InetAddress);
+ method @NonNull public java.util.List<java.net.InetAddress> getAddresses();
+ method @NonNull public java.util.List<java.lang.String> getAllInterfaceNames();
+ method @NonNull public java.util.List<android.net.LinkAddress> getAllLinkAddresses();
+ method @NonNull public java.util.List<android.net.RouteInfo> getAllRoutes();
+ method @Nullable public android.net.Uri getCaptivePortalApiUrl();
+ method @Nullable public android.net.CaptivePortalData getCaptivePortalData();
+ method @NonNull public java.util.List<java.net.InetAddress> getPcscfServers();
+ method @Nullable public String getTcpBufferSizes();
+ method @NonNull public java.util.List<java.net.InetAddress> getValidatedPrivateDnsServers();
+ method public boolean hasGlobalIpv6Address();
+ method public boolean hasIpv4Address();
+ method public boolean hasIpv4DefaultRoute();
+ method public boolean hasIpv4DnsServer();
+ method public boolean hasIpv6DefaultRoute();
+ method public boolean hasIpv6DnsServer();
+ method public boolean isIpv4Provisioned();
+ method public boolean isIpv6Provisioned();
+ method public boolean isProvisioned();
+ method public boolean isReachable(@NonNull java.net.InetAddress);
+ method public boolean removeDnsServer(@NonNull java.net.InetAddress);
+ method public boolean removeLinkAddress(@NonNull android.net.LinkAddress);
+ method public boolean removeRoute(@NonNull android.net.RouteInfo);
+ method public void setCaptivePortalApiUrl(@Nullable android.net.Uri);
+ method public void setCaptivePortalData(@Nullable android.net.CaptivePortalData);
+ method public void setPcscfServers(@NonNull java.util.Collection<java.net.InetAddress>);
+ method public void setPrivateDnsServerName(@Nullable String);
+ method public void setTcpBufferSizes(@Nullable String);
+ method public void setUsePrivateDns(boolean);
+ method public void setValidatedPrivateDnsServers(@NonNull java.util.Collection<java.net.InetAddress>);
+ }
+
+ public final class NattKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
+ ctor public NattKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[]) throws android.net.InvalidPacketException;
+ method public int describeContents();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NattKeepalivePacketData> CREATOR;
+ }
+
+ public class Network implements android.os.Parcelable {
+ ctor public Network(@NonNull android.net.Network);
+ method public int getNetId();
+ method @NonNull public android.net.Network getPrivateDnsBypassingCopy();
+ }
+
+ public abstract class NetworkAgent {
+ ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ method @Nullable public android.net.Network getNetwork();
+ method public void markConnected();
+ method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
+ method public void onAutomaticReconnectDisabled();
+ method public void onBandwidthUpdateRequested();
+ method public void onDscpPolicyStatusUpdated(int, int);
+ method public void onNetworkCreated();
+ method public void onNetworkDestroyed();
+ method public void onNetworkUnwanted();
+ method public void onQosCallbackRegistered(int, @NonNull android.net.QosFilter);
+ method public void onQosCallbackUnregistered(int);
+ method public void onRemoveKeepalivePacketFilter(int);
+ method public void onSaveAcceptUnvalidated(boolean);
+ method public void onSignalStrengthThresholdsUpdated(@NonNull int[]);
+ method public void onStartSocketKeepalive(int, @NonNull java.time.Duration, @NonNull android.net.KeepalivePacketData);
+ method public void onStopSocketKeepalive(int);
+ method public void onValidationStatus(int, @Nullable android.net.Uri);
+ method @NonNull public android.net.Network register();
+ method public void sendAddDscpPolicy(@NonNull android.net.DscpPolicy);
+ method public void sendLinkProperties(@NonNull android.net.LinkProperties);
+ method public void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
+ method public void sendNetworkScore(@NonNull android.net.NetworkScore);
+ method public void sendNetworkScore(@IntRange(from=0, to=99) int);
+ method public final void sendQosCallbackError(int, int);
+ method public final void sendQosSessionAvailable(int, int, @NonNull android.net.QosSessionAttributes);
+ method public final void sendQosSessionLost(int, int, int);
+ method public void sendRemoveAllDscpPolicies();
+ method public void sendRemoveDscpPolicy(int);
+ method public final void sendSocketKeepaliveEvent(int, int);
+ method @Deprecated public void setLegacySubtype(int, @NonNull String);
+ method public void setLingerDuration(@NonNull java.time.Duration);
+ method public void setTeardownDelayMillis(@IntRange(from=0, to=0x1388) int);
+ method public void setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
+ method public void unregister();
+ method public void unregisterAfterReplacement(@IntRange(from=0, to=0x1388) int);
+ field public static final int DSCP_POLICY_STATUS_DELETED = 4; // 0x4
+ field public static final int DSCP_POLICY_STATUS_INSUFFICIENT_PROCESSING_RESOURCES = 3; // 0x3
+ field public static final int DSCP_POLICY_STATUS_POLICY_NOT_FOUND = 5; // 0x5
+ field public static final int DSCP_POLICY_STATUS_REQUESTED_CLASSIFIER_NOT_SUPPORTED = 2; // 0x2
+ field public static final int DSCP_POLICY_STATUS_REQUEST_DECLINED = 1; // 0x1
+ field public static final int DSCP_POLICY_STATUS_SUCCESS = 0; // 0x0
+ field public static final int VALIDATION_STATUS_NOT_VALID = 2; // 0x2
+ field public static final int VALIDATION_STATUS_VALID = 1; // 0x1
+ }
+
+ public final class NetworkAgentConfig implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getLegacyType();
+ method @NonNull public String getLegacyTypeName();
+ method public boolean isExplicitlySelected();
+ method public boolean isPartialConnectivityAcceptable();
+ method public boolean isUnvalidatedConnectivityAcceptable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkAgentConfig> CREATOR;
+ }
+
+ public static final class NetworkAgentConfig.Builder {
+ ctor public NetworkAgentConfig.Builder();
+ method @NonNull public android.net.NetworkAgentConfig build();
+ method @NonNull public android.net.NetworkAgentConfig.Builder setExplicitlySelected(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyExtraInfo(@NonNull String);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubType(int);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacySubTypeName(@NonNull String);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyType(int);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setLegacyTypeName(@NonNull String);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setNat64DetectionEnabled(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setPartialConnectivityAcceptable(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setProvisioningNotificationEnabled(boolean);
+ method @NonNull public android.net.NetworkAgentConfig.Builder setUnvalidatedConnectivityAcceptable(boolean);
+ }
+
+ public final class NetworkCapabilities implements android.os.Parcelable {
+ method @NonNull public int[] getAdministratorUids();
+ method @Nullable public static String getCapabilityCarrierName(int);
+ method @Nullable public String getSsid();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubscriptionIds();
+ method @NonNull public int[] getTransportTypes();
+ method @Nullable public java.util.List<android.net.Network> getUnderlyingNetworks();
+ method public boolean isPrivateDnsBroken();
+ method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
+ field public static final int NET_CAPABILITY_BIP = 31; // 0x1f
+ field public static final int NET_CAPABILITY_NOT_VCN_MANAGED = 28; // 0x1c
+ field public static final int NET_CAPABILITY_OEM_PAID = 22; // 0x16
+ field public static final int NET_CAPABILITY_OEM_PRIVATE = 26; // 0x1a
+ field public static final int NET_CAPABILITY_PARTIAL_CONNECTIVITY = 24; // 0x18
+ field public static final int NET_CAPABILITY_VEHICLE_INTERNAL = 27; // 0x1b
+ field public static final int NET_CAPABILITY_VSIM = 30; // 0x1e
+ }
+
+ public static final class NetworkCapabilities.Builder {
+ ctor public NetworkCapabilities.Builder();
+ ctor public NetworkCapabilities.Builder(@NonNull android.net.NetworkCapabilities);
+ method @NonNull public android.net.NetworkCapabilities.Builder addCapability(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder addEnterpriseId(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder addTransportType(int);
+ method @NonNull public android.net.NetworkCapabilities build();
+ method @NonNull public android.net.NetworkCapabilities.Builder removeCapability(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder removeEnterpriseId(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder removeTransportType(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setAdministratorUids(@NonNull int[]);
+ method @NonNull public android.net.NetworkCapabilities.Builder setLinkDownstreamBandwidthKbps(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder setLinkUpstreamBandwidthKbps(int);
+ method @NonNull public android.net.NetworkCapabilities.Builder setNetworkSpecifier(@Nullable android.net.NetworkSpecifier);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setOwnerUid(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorPackageName(@Nullable String);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setRequestorUid(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkCapabilities.Builder setSignalStrength(int);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
+ method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
+ method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
+ method @NonNull public static android.net.NetworkCapabilities.Builder withoutDefaultCapabilities();
+ }
+
+ public class NetworkProvider {
+ ctor public NetworkProvider(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void declareNetworkRequestUnfulfillable(@NonNull android.net.NetworkRequest);
+ method public int getProviderId();
+ method public void onNetworkRequestWithdrawn(@NonNull android.net.NetworkRequest);
+ method public void onNetworkRequested(@NonNull android.net.NetworkRequest, @IntRange(from=0, to=99) int, int);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void registerNetworkOffer(@NonNull android.net.NetworkScore, @NonNull android.net.NetworkCapabilities, @NonNull java.util.concurrent.Executor, @NonNull android.net.NetworkProvider.NetworkOfferCallback);
+ method @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public void unregisterNetworkOffer(@NonNull android.net.NetworkProvider.NetworkOfferCallback);
+ field public static final int ID_NONE = -1; // 0xffffffff
+ }
+
+ public static interface NetworkProvider.NetworkOfferCallback {
+ method public void onNetworkNeeded(@NonNull android.net.NetworkRequest);
+ method public void onNetworkUnneeded(@NonNull android.net.NetworkRequest);
+ }
+
+ public class NetworkReleasedException extends java.lang.Exception {
+ ctor public NetworkReleasedException();
+ }
+
+ public class NetworkRequest implements android.os.Parcelable {
+ method @Nullable public String getRequestorPackageName();
+ method public int getRequestorUid();
+ }
+
+ public static class NetworkRequest.Builder {
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
+ method @NonNull public android.net.NetworkRequest.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
+ }
+
+ public final class NetworkScore implements android.os.Parcelable {
+ method public int describeContents();
+ method public int getKeepConnectedReason();
+ method public int getLegacyInt();
+ method public boolean isExiting();
+ method public boolean isTransportPrimary();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+ field public static final int KEEP_CONNECTED_FOR_HANDOVER = 1; // 0x1
+ field public static final int KEEP_CONNECTED_NONE = 0; // 0x0
+ }
+
+ public static final class NetworkScore.Builder {
+ ctor public NetworkScore.Builder();
+ method @NonNull public android.net.NetworkScore build();
+ method @NonNull public android.net.NetworkScore.Builder setExiting(boolean);
+ method @NonNull public android.net.NetworkScore.Builder setKeepConnectedReason(int);
+ method @NonNull public android.net.NetworkScore.Builder setLegacyInt(int);
+ method @NonNull public android.net.NetworkScore.Builder setTransportPrimary(boolean);
+ }
+
+ public final class OemNetworkPreferences implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public java.util.Map<java.lang.String,java.lang.Integer> getNetworkPreferences();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.OemNetworkPreferences> CREATOR;
+ field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID = 1; // 0x1
+ field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_NO_FALLBACK = 2; // 0x2
+ field public static final int OEM_NETWORK_PREFERENCE_OEM_PAID_ONLY = 3; // 0x3
+ field public static final int OEM_NETWORK_PREFERENCE_OEM_PRIVATE_ONLY = 4; // 0x4
+ field public static final int OEM_NETWORK_PREFERENCE_UNINITIALIZED = 0; // 0x0
+ }
+
+ public static final class OemNetworkPreferences.Builder {
+ ctor public OemNetworkPreferences.Builder();
+ ctor public OemNetworkPreferences.Builder(@NonNull android.net.OemNetworkPreferences);
+ method @NonNull public android.net.OemNetworkPreferences.Builder addNetworkPreference(@NonNull String, int);
+ method @NonNull public android.net.OemNetworkPreferences build();
+ method @NonNull public android.net.OemNetworkPreferences.Builder clearNetworkPreference(@NonNull String);
+ }
+
+ public abstract class QosCallback {
+ ctor public QosCallback();
+ method public void onError(@NonNull android.net.QosCallbackException);
+ method public void onQosSessionAvailable(@NonNull android.net.QosSession, @NonNull android.net.QosSessionAttributes);
+ method public void onQosSessionLost(@NonNull android.net.QosSession);
+ }
+
+ public static class QosCallback.QosCallbackRegistrationException extends java.lang.RuntimeException {
+ }
+
+ public final class QosCallbackException extends java.lang.Exception {
+ ctor public QosCallbackException(@NonNull String);
+ ctor public QosCallbackException(@NonNull Throwable);
+ }
+
+ public abstract class QosFilter {
+ method @NonNull public abstract android.net.Network getNetwork();
+ method public abstract boolean matchesLocalAddress(@NonNull java.net.InetAddress, int, int);
+ method public boolean matchesProtocol(int);
+ method public abstract boolean matchesRemoteAddress(@NonNull java.net.InetAddress, int, int);
+ }
+
+ public final class QosSession implements android.os.Parcelable {
+ ctor public QosSession(int, int);
+ method public int describeContents();
+ method public int getSessionId();
+ method public int getSessionType();
+ method public long getUniqueId();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSession> CREATOR;
+ field public static final int TYPE_EPS_BEARER = 1; // 0x1
+ field public static final int TYPE_NR_BEARER = 2; // 0x2
+ }
+
+ public interface QosSessionAttributes {
+ }
+
+ public final class QosSocketInfo implements android.os.Parcelable {
+ ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.Socket) throws java.io.IOException;
+ ctor public QosSocketInfo(@NonNull android.net.Network, @NonNull java.net.DatagramSocket) throws java.io.IOException;
+ method public int describeContents();
+ method @NonNull public java.net.InetSocketAddress getLocalSocketAddress();
+ method @NonNull public android.net.Network getNetwork();
+ method @Nullable public java.net.InetSocketAddress getRemoteSocketAddress();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.QosSocketInfo> CREATOR;
+ }
+
+ public final class RouteInfo implements android.os.Parcelable {
+ ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int);
+ ctor public RouteInfo(@Nullable android.net.IpPrefix, @Nullable java.net.InetAddress, @Nullable String, int, int);
+ method public int getMtu();
+ }
+
+ public abstract class SocketKeepalive implements java.lang.AutoCloseable {
+ method public final void start(@IntRange(from=0xa, to=0xe10) int, int, @Nullable android.net.Network);
+ field public static final int ERROR_NO_SUCH_SLOT = -33; // 0xffffffdf
+ field public static final int FLAG_AUTOMATIC_ON_OFF = 1; // 0x1
+ field public static final int SUCCESS = 0; // 0x0
+ }
+
+ public class SocketLocalAddressChangedException extends java.lang.Exception {
+ ctor public SocketLocalAddressChangedException();
+ }
+
+ public class SocketNotBoundException extends java.lang.Exception {
+ ctor public SocketNotBoundException();
+ }
+
+ public class SocketNotConnectedException extends java.lang.Exception {
+ ctor public SocketNotConnectedException();
+ }
+
+ public class SocketRemoteAddressChangedException extends java.lang.Exception {
+ ctor public SocketRemoteAddressChangedException();
+ }
+
+ public final class StaticIpConfiguration implements android.os.Parcelable {
+ ctor public StaticIpConfiguration();
+ ctor public StaticIpConfiguration(@Nullable android.net.StaticIpConfiguration);
+ method public void addDnsServer(@NonNull java.net.InetAddress);
+ method public void clear();
+ method @NonNull public java.util.List<android.net.RouteInfo> getRoutes(@Nullable String);
+ }
+
+ public final class TcpKeepalivePacketData extends android.net.KeepalivePacketData implements android.os.Parcelable {
+ ctor public TcpKeepalivePacketData(@NonNull java.net.InetAddress, int, @NonNull java.net.InetAddress, int, @NonNull byte[], int, int, int, int, int, int) throws android.net.InvalidPacketException;
+ method public int describeContents();
+ method public int getIpTos();
+ method public int getIpTtl();
+ method public int getTcpAck();
+ method public int getTcpSeq();
+ method public int getTcpWindow();
+ method public int getTcpWindowScale();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.TcpKeepalivePacketData> CREATOR;
+ }
+
+ public final class VpnTransportInfo implements android.os.Parcelable android.net.TransportInfo {
+ ctor public VpnTransportInfo(int, @Nullable String, boolean, boolean);
+ method public boolean areLongLivedTcpConnectionsExpensive();
+ method public int describeContents();
+ method public int getType();
+ method public boolean isBypassable();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.VpnTransportInfo> CREATOR;
+ }
+
+}
+
+package android.net.apf {
+
+ public final class ApfCapabilities implements android.os.Parcelable {
+ ctor public ApfCapabilities(int, int, int);
+ method public int describeContents();
+ method public static boolean getApfDrop8023Frames();
+ method @NonNull public static int[] getApfEtherTypeBlackList();
+ method public boolean hasDataAccess();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.net.apf.ApfCapabilities> CREATOR;
+ field public final int apfPacketFormat;
+ field public final int apfVersionSupported;
+ field public final int maximumApfProgramSize;
+ }
+
+}
+
diff --git a/framework/cronet_disabled/api/system-lint-baseline.txt b/framework/cronet_disabled/api/system-lint-baseline.txt
new file mode 100644
index 0000000..9a97707
--- /dev/null
+++ b/framework/cronet_disabled/api/system-lint-baseline.txt
@@ -0,0 +1 @@
+// Baseline format: 1.0
diff --git a/Tethering/common/TetheringLib/cronet_enabled/api/system-removed.txt b/framework/cronet_disabled/api/system-removed.txt
similarity index 100%
rename from Tethering/common/TetheringLib/cronet_enabled/api/system-removed.txt
rename to framework/cronet_disabled/api/system-removed.txt
diff --git a/framework/jarjar-excludes.txt b/framework/jarjar-excludes.txt
index 1311765..9b48d57 100644
--- a/framework/jarjar-excludes.txt
+++ b/framework/jarjar-excludes.txt
@@ -23,3 +23,8 @@
# TODO (b/217115866): add jarjar rules for Nearby
android\.nearby\..+
+
+# Don't touch anything that's already under android.net.http (cronet)
+# This is required since android.net.http contains api classes and hidden classes.
+# TODO: Remove this after hidden classes are moved to different package
+android\.net\.http\..+
\ No newline at end of file
diff --git a/framework/jni/android_net_NetworkUtils.cpp b/framework/jni/android_net_NetworkUtils.cpp
index 38e0059..ca297e5 100644
--- a/framework/jni/android_net_NetworkUtils.cpp
+++ b/framework/jni/android_net_NetworkUtils.cpp
@@ -23,6 +23,7 @@
#include <netinet/in.h>
#include <string.h>
+#include <bpf/BpfClassic.h>
#include <DnsProxydProtocol.h> // NETID_USE_LOCAL_NAMESERVERS
#include <nativehelper/JNIPlatformHelp.h>
#include <utils/Log.h>
@@ -55,11 +56,10 @@
static void android_net_utils_attachDropAllBPFFilter(JNIEnv *env, jclass clazz, jobject javaFd)
{
- struct sock_filter filter_code[] = {
- // Reject all.
- BPF_STMT(BPF_RET | BPF_K, 0)
+ static struct sock_filter filter_code[] = {
+ BPF_REJECT,
};
- struct sock_fprog filter = {
+ static const struct sock_fprog filter = {
sizeof(filter_code) / sizeof(filter_code[0]),
filter_code,
};
diff --git a/framework/src/android/net/LinkAddress.java b/framework/src/android/net/LinkAddress.java
index d48b8c7..90f55b3 100644
--- a/framework/src/android/net/LinkAddress.java
+++ b/framework/src/android/net/LinkAddress.java
@@ -487,17 +487,23 @@
*/
@SystemApi
public boolean isGlobalPreferred() {
- /**
- * Note that addresses flagged as IFA_F_OPTIMISTIC are
- * simultaneously flagged as IFA_F_TENTATIVE (when the tentative
- * state has cleared either DAD has succeeded or failed, and both
- * flags are cleared regardless).
- */
- int flags = getFlags();
return (scope == RT_SCOPE_UNIVERSE
&& !isIpv6ULA()
- && (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
- && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L));
+ && isPreferred());
+ }
+
+ /**
+ * Checks if the address is a preferred address.
+ *
+ * @hide
+ */
+ public boolean isPreferred() {
+ // Note that addresses flagged as IFA_F_OPTIMISTIC are simultaneously flagged as
+ // IFA_F_TENTATIVE (when the tentative state has cleared either DAD has succeeded or
+ // failed, and both flags are cleared regardless).
+ int flags = getFlags();
+ return (flags & (IFA_F_DADFAILED | IFA_F_DEPRECATED)) == 0L
+ && ((flags & IFA_F_TENTATIVE) == 0L || (flags & IFA_F_OPTIMISTIC) != 0L);
}
/**
diff --git a/framework/src/android/net/NetworkAgent.java b/framework/src/android/net/NetworkAgent.java
index 8fe20de..177f7e3 100644
--- a/framework/src/android/net/NetworkAgent.java
+++ b/framework/src/android/net/NetworkAgent.java
@@ -281,9 +281,8 @@
*
* arg1 = the hardware slot number of the keepalive to start
* arg2 = interval in seconds
- * obj = AutomaticKeepaliveInfo object
+ * obj = KeepalivePacketData object describing the data to be sent
*
- * Also used internally by ConnectivityService / KeepaliveTracker, with different semantics.
* @hide
*/
public static final int CMD_START_SOCKET_KEEPALIVE = BASE + 11;
@@ -436,6 +435,14 @@
public static final int CMD_DSCP_POLICY_STATUS = BASE + 28;
/**
+ * Sent by the NetworkAgent to ConnectivityService to notify that this network is expected to be
+ * replaced within the specified time by a similar network.
+ * arg1 = timeout in milliseconds
+ * @hide
+ */
+ public static final int EVENT_UNREGISTER_AFTER_REPLACEMENT = BASE + 29;
+
+ /**
* DSCP policy was successfully added.
*/
public static final int DSCP_POLICY_STATUS_SUCCESS = 0;
@@ -477,27 +484,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface DscpPolicyStatus {}
- /**
- * Sent by the NetworkAgent to ConnectivityService to notify that this network is expected to be
- * replaced within the specified time by a similar network.
- * arg1 = timeout in milliseconds
- * @hide
- */
- public static final int EVENT_UNREGISTER_AFTER_REPLACEMENT = BASE + 29;
-
- /**
- * Sent by AutomaticOnOffKeepaliveTracker periodically (when relevant) to trigger monitor
- * automatic keepalive request.
- *
- * NATT keepalives have an automatic mode where the system only sends keepalive packets when
- * TCP sockets are open over a VPN. The system will check periodically for presence of
- * such open sockets, and this message is what triggers the re-evaluation.
- *
- * obj = A Binder object associated with the keepalive.
- * @hide
- */
- public static final int CMD_MONITOR_AUTOMATIC_KEEPALIVE = BASE + 30;
-
private static NetworkInfo getLegacyNetworkInfo(final NetworkAgentConfig config) {
final NetworkInfo ni = new NetworkInfo(config.legacyType, config.legacySubType,
config.legacyTypeName, config.legacySubTypeName);
diff --git a/framework/src/android/net/TestNetworkManager.java b/framework/src/android/net/TestNetworkManager.java
index b64299f..416c6de 100644
--- a/framework/src/android/net/TestNetworkManager.java
+++ b/framework/src/android/net/TestNetworkManager.java
@@ -260,7 +260,7 @@
/**
* Create a tap interface with or without carrier for testing purposes.
*
- * Note: setting carrierUp = false is not supported until kernel version 5.0.
+ * Note: setting carrierUp = false is not supported until kernel version 6.0.
*
* @param carrierUp whether the created interface has a carrier or not.
* @param bringUp whether to bring up the interface before returning it.
@@ -280,6 +280,8 @@
/**
* Create a tap interface for testing purposes.
*
+ * Note: setting carrierUp = false is not supported until kernel version 6.0.
+ *
* @param carrierUp whether the created interface has a carrier or not.
* @param bringUp whether to bring up the interface before returning it.
* @param disableIpv6ProvisioningDelay whether to disable DAD and RS delay.
diff --git a/nearby/tests/multidevices/README.md b/nearby/tests/multidevices/README.md
index b64667c..9d086de 100644
--- a/nearby/tests/multidevices/README.md
+++ b/nearby/tests/multidevices/README.md
@@ -43,14 +43,24 @@
* Adjust Bluetooth profile configurations. \
The Fast Pair provider simulator is an opposite role to the seeker. It needs
to enable/disable the following Bluetooth profile:
- * Disable A2DP (profile_supported_a2dp)
- * Disable the AVRCP controller (profile_supported_avrcp_controller)
- * Enable A2DP sink (profile_supported_a2dp_sink)
- * Enable the HFP client connection service (profile_supported_hfpclient,
- hfp_client_connection_service_enabled)
- * Enable the AVRCP target (profile_supported_avrcp_target)
- * Enable the automatic audio focus request
- (a2dp_sink_automatically_request_audio_focus)
+ * Disable A2DP source (bluetooth.profile.a2dp.source.enabled)
+ * Enable A2DP sink (bluetooth.profile.a2dp.sink.enabled)
+ * Disable the AVRCP controller (bluetooth.profile.avrcp.controller.enabled)
+ * Enable the AVRCP target (bluetooth.profile.avrcp.target.enabled)
+ * Enable the HFP service (bluetooth.profile.hfp.ag.enabled, bluetooth.profile.hfp.hf.enabled)
+
+```makefile
+# The Bluetooth profiles that Fast Pair provider simulator expect to have enabled.
+PRODUCT_PRODUCT_PROPERTIES += \
+ bluetooth.device.default_name=FastPairProviderSimulator \
+ bluetooth.profile.a2dp.source.enabled=false \
+ bluetooth.profile.a2dp.sink.enabled=true \
+ bluetooth.profile.avrcp.controller.enabled=false \
+ bluetooth.profile.avrcp.target.enabled=true \
+ bluetooth.profile.hfp.ag.enabled=true \
+ bluetooth.profile.hfp.hf.enabled=true
+```
+
* Adjust Bluetooth TX power limitation in Bluetooth module and disable the
Fast Pair in Google Play service (aka GMS)
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java
index e916c53..75fafb0 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/simulator_app/src/android/nearby/fastpair/provider/simulator/app/MainActivity.java
@@ -657,9 +657,7 @@
int desiredIoCapability = getIoCapabilityFromModelId(modelId);
- mBluetoothController.setIoCapability(
- /*ioCapabilityClassic=*/ desiredIoCapability,
- /*ioCapabilityBLE=*/ desiredIoCapability);
+ mBluetoothController.setIoCapability(desiredIoCapability);
runOnUiThread(() -> {
updateStringStatusView(
@@ -950,9 +948,7 @@
}
// Recover the IO capability.
- mBluetoothController.setIoCapability(
- /*ioCapabilityClassic=*/ IO_CAPABILITY_IO, /*ioCapabilityBLE=*/
- IO_CAPABILITY_KBDISP);
+ mBluetoothController.setIoCapability(IO_CAPABILITY_IO);
super.onDestroy();
}
diff --git a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt
index 0cc0c92..345e8d2 100644
--- a/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt
+++ b/nearby/tests/multidevices/clients/test_support/fastpair_provider/src/android/nearby/fastpair/provider/bluetooth/BluetoothController.kt
@@ -50,23 +50,16 @@
}
/**
- * Sets the Input/Output capability of the device for both classic Bluetooth and BLE operations.
+ * Sets the Input/Output capability of the device for classic Bluetooth operations.
* Note: In order to let changes take effect, this method will make sure the Bluetooth stack is
* restarted by blocking calling thread.
*
* @param ioCapabilityClassic One of {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_NONE},
* ```
* {@link #IO_CAPABILITY_KBDISP} or more in {@link BluetoothAdapter}.
- * @param ioCapabilityBLE
- * ```
- * One of {@link #IO_CAPABILITY_IO}, {@link #IO_CAPABILITY_NONE}, {@link
- * ```
- * #IO_CAPABILITY_KBDISP} or more in {@link BluetoothAdapter}.
- * ```
*/
- fun setIoCapability(ioCapabilityClassic: Int, ioCapabilityBLE: Int) {
+ fun setIoCapability(ioCapabilityClassic: Int) {
bluetoothAdapter.ioCapability = ioCapabilityClassic
- bluetoothAdapter.leIoCapability = ioCapabilityBLE
// Toggling airplane mode on/off to restart Bluetooth stack and reset the BLE.
try {
@@ -273,4 +266,4 @@
private const val TURN_AIRPLANE_MODE_OFF = 0
private const val TURN_AIRPLANE_MODE_ON = 1
}
-}
\ No newline at end of file
+}
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index 2b773c9..8081d12 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -32,7 +32,6 @@
namespace net {
using base::unique_fd;
-using bpf::NONEXISTENT_COOKIE;
using bpf::getSocketCookie;
using bpf::retrieveProgram;
using netdutils::Status;
@@ -185,7 +184,7 @@
}
uint64_t sock_cookie = getSocketCookie(sockFd);
- if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
+ if (!sock_cookie) return -errno;
UidTagValue newKey = {.uid = (uint32_t)chargeUid, .tag = tag};
@@ -249,7 +248,7 @@
int BpfHandler::untagSocket(int sockFd) {
uint64_t sock_cookie = getSocketCookie(sockFd);
- if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
+ if (!sock_cookie) return -errno;
if (!mCookieTagMap.isValid()) return -EPERM;
base::Result<void> res = mCookieTagMap.deleteValue(sock_cookie);
diff --git a/service-t/Android.bp b/service-t/Android.bp
index 5bf2973..7de749c 100644
--- a/service-t/Android.bp
+++ b/service-t/Android.bp
@@ -75,3 +75,47 @@
"//packages/modules/IPsec/tests/iketests",
],
}
+
+// Test building mDNS as a standalone, so that it can be imported into other repositories as-is.
+// The mDNS code is platform code so it should use framework-annotations-lib, contrary to apps that
+// should use sdk_version: "system_current" and only androidx.annotation_annotation. But this build
+// rule verifies that the mDNS code can be built into apps, if code transformations are applied to
+// the annotations.
+// When using "system_current", framework annotations are not available; they would appear as
+// package-private as they are marked as such in the system_current stubs. So build against
+// core_platform and add the stubs manually in "libs". See http://b/147773144#comment7.
+java_library {
+ name: "service-connectivity-mdns-standalone-build-test",
+ sdk_version: "core_platform",
+ srcs: [
+ ":service-mdns-droidstubs",
+ "src/com/android/server/connectivity/mdns/**/*.java",
+ ],
+ exclude_srcs: [
+ "src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java",
+ "src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java"
+ ],
+ static_libs: [
+ "net-utils-device-common-mdns-standalone-build-test",
+ ],
+ libs: [
+ "framework-annotations-lib",
+ "android_system_stubs_current",
+ "androidx.annotation_annotation",
+ ],
+ visibility: [
+ "//visibility:private",
+ ],
+}
+
+droidstubs {
+ name: "service-mdns-droidstubs",
+ srcs: ["src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java"],
+ libs: [
+ "net-utils-device-common-mdns-standalone-build-test",
+ "service-connectivity-tiramisu-pre-jarjar"
+ ],
+ visibility: [
+ "//visibility:private",
+ ],
+}
\ No newline at end of file
diff --git a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
index 2dbe771..a16757b 100644
--- a/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
+++ b/service-t/jni/com_android_server_net_NetworkStatsFactory.cpp
@@ -170,23 +170,10 @@
return 0;
}
-static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats, jint limitUid,
- jobjectArray limitIfacesObj, jint limitTag) {
-
- std::vector<std::string> limitIfaces;
- if (limitIfacesObj != NULL && env->GetArrayLength(limitIfacesObj) > 0) {
- int num = env->GetArrayLength(limitIfacesObj);
- for (int i = 0; i < num; i++) {
- jstring string = (jstring)env->GetObjectArrayElement(limitIfacesObj, i);
- ScopedUtfChars string8(env, string);
- if (string8.c_str() != NULL) {
- limitIfaces.push_back(std::string(string8.c_str()));
- }
- }
- }
+static int readNetworkStatsDetail(JNIEnv* env, jclass clazz, jobject stats) {
std::vector<stats_line> lines;
- if (parseBpfNetworkStatsDetail(&lines, limitIfaces, limitTag, limitUid) < 0)
+ if (parseBpfNetworkStatsDetail(&lines) < 0)
return -1;
return statsLinesToNetworkStats(env, clazz, stats, lines);
@@ -202,8 +189,7 @@
}
static const JNINativeMethod gMethods[] = {
- { "nativeReadNetworkStatsDetail",
- "(Landroid/net/NetworkStats;I[Ljava/lang/String;I)I",
+ { "nativeReadNetworkStatsDetail", "(Landroid/net/NetworkStats;)I",
(void*) readNetworkStatsDetail },
{ "nativeReadNetworkStatsDev", "(Landroid/net/NetworkStats;)I",
(void*) readNetworkStatsDev },
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
index 4fbc5f4..1bc8ca5 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStats.cpp
@@ -109,13 +109,12 @@
return newLine;
}
-int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines,
- const std::vector<std::string>& limitIfaces, int limitTag,
- int limitUid, const BpfMap<StatsKey, StatsValue>& statsMap,
+int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines,
+ const BpfMap<StatsKey, StatsValue>& statsMap,
const BpfMap<uint32_t, IfaceValue>& ifaceMap) {
int64_t unknownIfaceBytesTotal = 0;
const auto processDetailUidStats =
- [lines, &limitIfaces, &limitTag, &limitUid, &unknownIfaceBytesTotal, &ifaceMap](
+ [&lines, &unknownIfaceBytesTotal, &ifaceMap](
const StatsKey& key,
const BpfMap<StatsKey, StatsValue>& statsMap) -> Result<void> {
char ifname[IFNAMSIZ];
@@ -123,23 +122,17 @@
&unknownIfaceBytesTotal)) {
return Result<void>();
}
- std::string ifnameStr(ifname);
- if (limitIfaces.size() > 0 &&
- std::find(limitIfaces.begin(), limitIfaces.end(), ifnameStr) == limitIfaces.end()) {
- // Nothing matched; skip this line.
- return Result<void>();
- }
- if (limitTag != TAG_ALL && uint32_t(limitTag) != key.tag) {
- return Result<void>();
- }
- if (limitUid != UID_ALL && uint32_t(limitUid) != key.uid) {
- return Result<void>();
- }
Result<StatsValue> statsEntry = statsMap.readValue(key);
if (!statsEntry.ok()) {
return base::ResultError(statsEntry.error().message(), statsEntry.error().code());
}
- lines->push_back(populateStatsEntry(key, statsEntry.value(), ifname));
+ stats_line newLine = populateStatsEntry(key, statsEntry.value(), ifname);
+ lines.push_back(newLine);
+ if (newLine.tag) {
+ // account tagged traffic in the untagged stats (for historical reasons?)
+ newLine.tag = 0;
+ lines.push_back(newLine);
+ }
return Result<void>();
};
Result<void> res = statsMap.iterate(processDetailUidStats);
@@ -162,9 +155,7 @@
return 0;
}
-int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines,
- const std::vector<std::string>& limitIfaces, int limitTag,
- int limitUid) {
+int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines) {
static BpfMapRO<uint32_t, IfaceValue> ifaceIndexNameMap(IFACE_INDEX_NAME_MAP_PATH);
static BpfMapRO<uint32_t, uint32_t> configurationMap(CONFIGURATION_MAP_PATH);
static BpfMap<StatsKey, StatsValue> statsMapA(STATS_MAP_A_PATH);
@@ -195,8 +186,7 @@
// TODO: the above comment feels like it may be obsolete / out of date,
// since we no longer swap the map via netd binder rpc - though we do
// still swap it.
- int ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid,
- *inactiveStatsMap, ifaceIndexNameMap);
+ int ret = parseBpfNetworkStatsDetailInternal(*lines, *inactiveStatsMap, ifaceIndexNameMap);
if (ret) {
ALOGE("parse detail network stats failed: %s", strerror(errno));
return ret;
@@ -211,11 +201,11 @@
return 0;
}
-int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines,
+int parseBpfNetworkStatsDevInternal(std::vector<stats_line>& lines,
const BpfMap<uint32_t, StatsValue>& statsMap,
const BpfMap<uint32_t, IfaceValue>& ifaceMap) {
int64_t unknownIfaceBytesTotal = 0;
- const auto processDetailIfaceStats = [lines, &unknownIfaceBytesTotal, &ifaceMap, &statsMap](
+ const auto processDetailIfaceStats = [&lines, &unknownIfaceBytesTotal, &ifaceMap, &statsMap](
const uint32_t& key, const StatsValue& value,
const BpfMap<uint32_t, StatsValue>&) {
char ifname[IFNAMSIZ];
@@ -227,7 +217,7 @@
.tag = (uint32_t)TAG_NONE,
.counterSet = (uint32_t)SET_ALL,
};
- lines->push_back(populateStatsEntry(fakeKey, value, ifname));
+ lines.push_back(populateStatsEntry(fakeKey, value, ifname));
return Result<void>();
};
Result<void> res = statsMap.iterateWithValue(processDetailIfaceStats);
@@ -244,29 +234,28 @@
int parseBpfNetworkStatsDev(std::vector<stats_line>* lines) {
static BpfMapRO<uint32_t, IfaceValue> ifaceIndexNameMap(IFACE_INDEX_NAME_MAP_PATH);
static BpfMapRO<uint32_t, StatsValue> ifaceStatsMap(IFACE_STATS_MAP_PATH);
- return parseBpfNetworkStatsDevInternal(lines, ifaceStatsMap, ifaceIndexNameMap);
+ return parseBpfNetworkStatsDevInternal(*lines, ifaceStatsMap, ifaceIndexNameMap);
}
-void groupNetworkStats(std::vector<stats_line>* lines) {
- if (lines->size() <= 1) return;
- std::sort(lines->begin(), lines->end());
+void groupNetworkStats(std::vector<stats_line>& lines) {
+ if (lines.size() <= 1) return;
+ std::sort(lines.begin(), lines.end());
// Similar to std::unique(), but aggregates the duplicates rather than discarding them.
- size_t nextOutput = 0;
- for (size_t i = 1; i < lines->size(); i++) {
- if (lines->at(nextOutput) == lines->at(i)) {
- lines->at(nextOutput) += lines->at(i);
+ size_t currentOutput = 0;
+ for (size_t i = 1; i < lines.size(); i++) {
+ // note that == operator only compares the 'key' portion: iface/uid/tag/set
+ if (lines[currentOutput] == lines[i]) {
+ // while += operator only affects the 'data' portion: {rx,tx}{Bytes,Packets}
+ lines[currentOutput] += lines[i];
} else {
- nextOutput++;
- if (nextOutput != i) {
- lines->at(nextOutput) = lines->at(i);
- }
+ // okay, we're done aggregating the current line, move to the next one
+ lines[++currentOutput] = lines[i];
}
}
- if (lines->size() != nextOutput + 1) {
- lines->resize(nextOutput + 1);
- }
+ // possibly shrink the vector - currentOutput is the last line with valid data
+ lines.resize(currentOutput + 1);
}
// True if lhs equals to rhs, only compare iface, uid, tag and set.
diff --git a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
index ff62c0b..ccd3f5e 100644
--- a/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
+++ b/service-t/native/libs/libnetworkstats/BpfNetworkStatsTest.cpp
@@ -225,18 +225,11 @@
ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID2, &result2, mFakeAppUidStatsMap));
expectStatsEqual(value2, result2);
std::vector<stats_line> lines;
- std::vector<std::string> ifaces;
populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET1, value1, mFakeStatsMap);
populateFakeStats(TEST_UID2, 0, IFACE_INDEX3, TEST_COUNTERSET1, value1, mFakeStatsMap);
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
- mFakeStatsMap, mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)2, lines.size());
- lines.clear();
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
- mFakeStatsMap, mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)1, lines.size());
- expectStatsLineEqual(value1, IFACE_NAME3, TEST_UID2, TEST_COUNTERSET1, 0, lines.front());
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ((unsigned long)3, lines.size());
}
TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
@@ -297,24 +290,8 @@
mFakeStatsMap);
populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
std::vector<stats_line> lines;
- std::vector<std::string> ifaces;
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
- mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)4, lines.size());
- lines.clear();
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
- mFakeStatsMap, mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)3, lines.size());
- lines.clear();
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1,
- mFakeStatsMap, mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)2, lines.size());
- lines.clear();
- ifaces.push_back(std::string(IFACE_NAME1));
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1,
- mFakeStatsMap, mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)1, lines.size());
- expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines.front());
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ((unsigned long)7, lines.size());
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
@@ -333,24 +310,8 @@
populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, value1, mFakeStatsMap);
populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
std::vector<stats_line> lines;
- std::vector<std::string> ifaces;
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
- mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
ASSERT_EQ((unsigned long)4, lines.size());
- lines.clear();
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
- mFakeStatsMap, mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)3, lines.size());
- lines.clear();
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
- mFakeStatsMap, mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)1, lines.size());
- expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, 0, lines.front());
- lines.clear();
- ifaces.push_back(std::string(IFACE_NAME1));
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
- mFakeStatsMap, mFakeIfaceIndexNameMap));
- ASSERT_EQ((unsigned long)2, lines.size());
}
TEST_F(BpfNetworkStatsHelperTest, TestUnknownIfaceError) {
@@ -387,10 +348,8 @@
ifname, curKey, &unknownIfaceBytesTotal));
ASSERT_EQ(-1, unknownIfaceBytesTotal);
std::vector<stats_line> lines;
- std::vector<std::string> ifaces;
// TODO: find a way to test the total of unknown Iface Bytes go above limit.
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
- mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
ASSERT_EQ((unsigned long)1, lines.size());
expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines.front());
}
@@ -422,7 +381,7 @@
EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
std::vector<stats_line> lines;
ASSERT_EQ(0,
- parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
+ parseBpfNetworkStatsDevInternal(lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
ASSERT_EQ((unsigned long)4, lines.size());
expectStatsLineEqual(value1, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
@@ -450,28 +409,32 @@
.txPackets = TEST_PACKET0,
.txBytes = TEST_BYTES0,
};
- StatsValue value3 = {
+ StatsValue value3 = { // value1 *2
.rxPackets = TEST_PACKET0 * 2,
.rxBytes = TEST_BYTES0 * 2,
.txPackets = TEST_PACKET1 * 2,
.txBytes = TEST_BYTES1 * 2,
};
+ StatsValue value5 = { // value2 + value3
+ .rxPackets = TEST_PACKET1 + TEST_PACKET0 * 2,
+ .rxBytes = TEST_BYTES1 + TEST_BYTES0 * 2,
+ .txPackets = TEST_PACKET0 + TEST_PACKET1 * 2,
+ .txBytes = TEST_BYTES0 + TEST_BYTES1 * 2,
+ };
std::vector<stats_line> lines;
- std::vector<std::string> ifaces;
// Test empty stats.
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
- mFakeIfaceIndexNameMap));
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
ASSERT_EQ((size_t) 0, lines.size());
lines.clear();
// Test 1 line stats.
populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
- mFakeIfaceIndexNameMap));
- ASSERT_EQ((size_t) 1, lines.size());
- expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]);
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ((size_t) 2, lines.size()); // TEST_TAG != 0 -> 1 entry becomes 2 lines
+ expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[0]);
+ expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[1]);
lines.clear();
// These items should not be grouped.
@@ -480,25 +443,27 @@
populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value2,
mFakeStatsMap);
populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
- mFakeIfaceIndexNameMap));
- ASSERT_EQ((size_t) 5, lines.size());
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ((size_t) 9, lines.size());
lines.clear();
// These items should be grouped.
populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
- mFakeIfaceIndexNameMap));
- ASSERT_EQ((size_t) 5, lines.size());
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ((size_t) 9, lines.size());
// Verify Sorted & Grouped.
- expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]);
- expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, TEST_TAG, lines[1]);
- expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG + 1, lines[2]);
- expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, TEST_TAG, lines[3]);
- expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[4]);
+ expectStatsLineEqual(value5, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[0]);
+ expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, 0, lines[1]);
+ expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[2]);
+ expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, TEST_TAG, lines[3]);
+ expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG + 1, lines[4]);
+ expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, 0, lines[5]);
+ expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, TEST_TAG, lines[6]);
+ expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, 0, lines[7]);
+ expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[8]);
lines.clear();
// Perform test on IfaceStats.
@@ -512,7 +477,7 @@
EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
ASSERT_EQ(0,
- parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
+ parseBpfNetworkStatsDevInternal(lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
ASSERT_EQ((size_t) 2, lines.size());
expectStatsLineEqual(value3, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
@@ -531,41 +496,48 @@
.txPackets = TEST_PACKET1,
.txBytes = TEST_BYTES1,
};
+ StatsValue value4 = { // value1 * 4
+ .rxPackets = TEST_PACKET0 * 4,
+ .rxBytes = TEST_BYTES0 * 4,
+ .txPackets = TEST_PACKET1 * 4,
+ .txBytes = TEST_BYTES1 * 4,
+ };
// Mutate uid, 0 < TEST_UID1 < INT_MAX < INT_MIN < UINT_MAX.
- populateFakeStats(0, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- populateFakeStats(UINT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- populateFakeStats(INT_MIN, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- populateFakeStats(INT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
+ populateFakeStats(0, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
+ populateFakeStats(UINT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
+ populateFakeStats(INT_MIN, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
+ populateFakeStats(INT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
// Mutate tag, 0 < TEST_TAG < INT_MAX < INT_MIN < UINT_MAX.
- populateFakeStats(TEST_UID1, INT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- populateFakeStats(TEST_UID1, INT_MIN, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
- populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
+ populateFakeStats(TEST_UID1, INT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
+ populateFakeStats(TEST_UID1, INT_MIN, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
+ populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
populateFakeStats(TEST_UID1, UINT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
// TODO: Mutate counterSet and enlarge TEST_MAP_SIZE if overflow on counterSet is possible.
std::vector<stats_line> lines;
- std::vector<std::string> ifaces;
- ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
- mFakeIfaceIndexNameMap));
- ASSERT_EQ((size_t) 8, lines.size());
+ ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(lines, mFakeStatsMap, mFakeIfaceIndexNameMap));
+ ASSERT_EQ((size_t) 12, lines.size());
// Uid 0 first
- expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, TEST_TAG, lines[0]);
+ expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, 0, lines[0]);
+ expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, TEST_TAG, lines[1]);
// Test uid, mutate tag.
- expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[1]);
- expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MAX, lines[2]);
- expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MIN, lines[3]);
- expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, UINT_MAX, lines[4]);
+ expectStatsLineEqual(value4, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[2]);
+ expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MAX, lines[3]);
+ expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MIN, lines[4]);
+ expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, UINT_MAX, lines[5]);
// Mutate uid.
- expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[5]);
- expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, TEST_TAG, lines[6]);
- expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[7]);
- lines.clear();
+ expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, 0, lines[6]);
+ expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[7]);
+ expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, 0, lines[8]);
+ expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, TEST_TAG, lines[9]);
+ expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, 0, lines[10]);
+ expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[11]);
}
} // namespace bpf
} // namespace android
diff --git a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
index dc5732f..6aa0fb4 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTraceHandler.cpp
@@ -101,6 +101,11 @@
void NetworkTraceHandler::InitPerfettoTracing() {
perfetto::TracingInitArgs args = {};
args.backends |= perfetto::kSystemBackend;
+ // The following line disables the Perfetto system consumer. Perfetto inlines
+ // the call to `Initialize` which allows the compiler to see that the branch
+ // with the SystemConsumerTracingBackend is not used. With LTO enabled, this
+ // strips the Perfetto consumer code and reduces the size of this binary by
+ // around 270KB total. Be careful when changing this value.
args.enable_system_consumer = false;
perfetto::Tracing::Initialize(args);
NetworkTraceHandler::RegisterDataSource();
diff --git a/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
index 3abb49a..3de9897 100644
--- a/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
+++ b/service-t/native/libs/libnetworkstats/NetworkTracePoller.cpp
@@ -99,6 +99,15 @@
ALOGW("Failed to disable tracing: %s", res.error().message().c_str());
}
+ // Make sure everything in the system has actually seen the 'false' we just
+ // wrote, things should now be well and truly disabled.
+ synchronizeKernelRCU();
+
+ // Drain remaining events from the ring buffer now that tracing is disabled.
+ // This prevents the next trace from seeing stale events and allows writing
+ // the last batch of events to Perfetto.
+ ConsumeAllLocked();
+
mTaskRunner.reset();
mRingBuffer.reset();
diff --git a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
index 03a1a44..133009f 100644
--- a/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
+++ b/service-t/native/libs/libnetworkstats/include/netdbpf/BpfNetworkStats.h
@@ -26,7 +26,7 @@
// TODO: set this to a proper value based on the map size;
constexpr int TAG_STATS_MAP_SOFT_LIMIT = 3;
constexpr int UID_ALL = -1;
-constexpr int TAG_ALL = -1;
+//constexpr int TAG_ALL = -1;
constexpr int TAG_NONE = 0;
constexpr int SET_ALL = -1;
constexpr int SET_DEFAULT = 0;
@@ -63,9 +63,8 @@
const BpfMap<uint32_t, StatsValue>& ifaceStatsMap,
const BpfMap<uint32_t, IfaceValue>& ifaceNameMap);
// For test only
-int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines,
- const std::vector<std::string>& limitIfaces, int limitTag,
- int limitUid, const BpfMap<StatsKey, StatsValue>& statsMap,
+int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>& lines,
+ const BpfMap<StatsKey, StatsValue>& statsMap,
const BpfMap<uint32_t, IfaceValue>& ifaceMap);
// For test only
int cleanStatsMapInternal(const base::unique_fd& cookieTagMap, const base::unique_fd& tagStatsMap);
@@ -107,18 +106,16 @@
}
// For test only
-int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines,
+int parseBpfNetworkStatsDevInternal(std::vector<stats_line>& lines,
const BpfMap<uint32_t, StatsValue>& statsMap,
const BpfMap<uint32_t, IfaceValue>& ifaceMap);
int bpfGetUidStats(uid_t uid, Stats* stats);
int bpfGetIfaceStats(const char* iface, Stats* stats);
-int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines,
- const std::vector<std::string>& limitIfaces, int limitTag,
- int limitUid);
+int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines);
int parseBpfNetworkStatsDev(std::vector<stats_line>* lines);
-void groupNetworkStats(std::vector<stats_line>* lines);
+void groupNetworkStats(std::vector<stats_line>& lines);
int cleanStatsMap();
} // namespace bpf
} // namespace android
diff --git a/service-t/src/com/android/server/NsdService.java b/service-t/src/com/android/server/NsdService.java
index c00f1ae..383ed2c 100644
--- a/service-t/src/com/android/server/NsdService.java
+++ b/service-t/src/com/android/server/NsdService.java
@@ -44,6 +44,7 @@
import android.net.nsd.MDnsManager;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
+import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
@@ -56,10 +57,12 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.State;
import com.android.internal.util.StateMachine;
import com.android.net.module.util.DeviceConfigUtils;
import com.android.net.module.util.PermissionUtils;
+import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.ExecutorProvider;
import com.android.server.connectivity.mdns.MdnsAdvertiser;
import com.android.server.connectivity.mdns.MdnsDiscoveryManager;
@@ -159,6 +162,7 @@
private final MdnsSocketProvider mMdnsSocketProvider;
@NonNull
private final MdnsAdvertiser mAdvertiser;
+ private final SharedLog mServiceLogs = new SharedLog(TAG);
// WARNING : Accessing these values in any thread is not safe, it must only be changed in the
// state machine thread. If change this outside state machine, it will need to introduce
// synchronization.
@@ -179,6 +183,8 @@
private int mUniqueId = 1;
// The count of the connected legacy clients.
private int mLegacyClientCount = 0;
+ // The number of client that ever connected.
+ private int mClientNumberId = 1;
private static class MdnsListener implements MdnsServiceBrowserListener {
protected final int mClientId;
@@ -332,6 +338,7 @@
mMDnsManager.startDaemon();
mIsDaemonStarted = true;
maybeScheduleStop();
+ mServiceLogs.log("Start mdns_responder daemon");
}
private void maybeStopDaemon() {
@@ -342,6 +349,7 @@
mMDnsManager.unregisterEventListener(mMDnsEventCallback);
mMDnsManager.stopDaemon();
mIsDaemonStarted = false;
+ mServiceLogs.log("Stop mdns_responder daemon");
}
private boolean isAnyRequestActive() {
@@ -401,7 +409,9 @@
final INsdManagerCallback cb = arg.callback;
try {
cb.asBinder().linkToDeath(arg.connector, 0);
- cInfo = new ClientInfo(cb, arg.useJavaBackend);
+ final String tag = "Client" + arg.uid + "-" + mClientNumberId++;
+ cInfo = new ClientInfo(cb, arg.useJavaBackend,
+ mServiceLogs.forSubComponent(tag));
mClients.put(arg.connector, cInfo);
} catch (RemoteException e) {
Log.w(TAG, "Client " + clientId + " has already died");
@@ -628,6 +638,8 @@
listenServiceType, listener, options);
storeDiscoveryManagerRequestMap(clientId, id, listener, clientInfo);
clientInfo.onDiscoverServicesStarted(clientId, info);
+ clientInfo.log("Register a DiscoveryListener " + id
+ + " for service type:" + listenServiceType);
} else {
maybeStartDaemon();
if (discoverServices(id, info)) {
@@ -669,6 +681,7 @@
if (request instanceof DiscoveryManagerRequest) {
stopDiscoveryManagerRequest(request, clientId, id, clientInfo);
clientInfo.onStopDiscoverySucceeded(clientId);
+ clientInfo.log("Unregister the DiscoveryListener " + id);
} else {
removeRequestMap(clientId, id, clientInfo);
if (stopServiceDiscovery(id)) {
@@ -804,6 +817,8 @@
mMdnsDiscoveryManager.registerListener(
resolveServiceType, listener, options);
storeDiscoveryManagerRequestMap(clientId, id, listener, clientInfo);
+ clientInfo.log("Register a ResolutionListener " + id
+ + " for service type:" + resolveServiceType);
} else {
if (clientInfo.mResolvedService != null) {
clientInfo.onResolveServiceFailed(
@@ -846,6 +861,7 @@
if (request instanceof DiscoveryManagerRequest) {
stopDiscoveryManagerRequest(request, clientId, id, clientInfo);
clientInfo.onStopResolutionSucceeded(clientId);
+ clientInfo.log("Unregister the ResolutionListener " + id);
} else {
removeRequestMap(clientId, id, clientInfo);
if (stopResolveService(id)) {
@@ -891,6 +907,8 @@
mMdnsDiscoveryManager.registerListener(
resolveServiceType, listener, options);
storeDiscoveryManagerRequestMap(clientId, id, listener, clientInfo);
+ clientInfo.log("Register a ServiceInfoListener " + id
+ + " for service type:" + resolveServiceType);
break;
}
case NsdManager.UNREGISTER_SERVICE_CALLBACK: {
@@ -914,6 +932,7 @@
if (request instanceof DiscoveryManagerRequest) {
stopDiscoveryManagerRequest(request, clientId, id, clientInfo);
clientInfo.onServiceInfoCallbackUnregistered(clientId);
+ clientInfo.log("Unregister the ServiceInfoListener " + id);
} else {
loge("Unregister failed with non-DiscoveryManagerRequest.");
}
@@ -1106,9 +1125,12 @@
final String serviceName = serviceInfo.getServiceInstanceName();
final NsdServiceInfo servInfo = new NsdServiceInfo(serviceName, serviceType);
final Network network = serviceInfo.getNetwork();
+ // In MdnsDiscoveryManagerEvent, the Network can be null which means it is a
+ // network for Tethering interface. In other words, the network == null means the
+ // network has netId = INetd.LOCAL_NET_ID.
setServiceNetworkForCallback(
servInfo,
- network == null ? NETID_UNSET : network.netId,
+ network == null ? INetd.LOCAL_NET_ID : network.netId,
serviceInfo.getInterfaceIndex());
return servInfo;
}
@@ -1327,6 +1349,9 @@
mDeps = deps;
mMdnsSocketProvider = deps.makeMdnsSocketProvider(ctx, handler.getLooper());
+ // Netlink monitor starts on boot, and intentionally never stopped, to ensure that all
+ // address events are received.
+ handler.post(mMdnsSocketProvider::startNetLinkMonitor);
mMdnsSocketClient =
new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider);
mMdnsDiscoveryManager =
@@ -1539,12 +1564,14 @@
@NonNull public final NsdServiceConnector connector;
@NonNull public final INsdManagerCallback callback;
public final boolean useJavaBackend;
+ public final int uid;
ConnectorArgs(@NonNull NsdServiceConnector connector, @NonNull INsdManagerCallback callback,
- boolean useJavaBackend) {
+ boolean useJavaBackend, int uid) {
this.connector = connector;
this.callback = callback;
this.useJavaBackend = useJavaBackend;
+ this.uid = uid;
}
}
@@ -1553,9 +1580,9 @@
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
if (DBG) Log.d(TAG, "New client connect. useJavaBackend=" + useJavaBackend);
final INsdServiceConnector connector = new NsdServiceConnector();
- mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
- NsdManager.REGISTER_CLIENT,
- new ConnectorArgs((NsdServiceConnector) connector, cb, useJavaBackend)));
+ mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.REGISTER_CLIENT,
+ new ConnectorArgs((NsdServiceConnector) connector, cb, useJavaBackend,
+ Binder.getCallingUid())));
return connector;
}
@@ -1754,15 +1781,39 @@
}
@Override
- public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (!PermissionUtils.checkDumpPermission(mContext, TAG, pw)) return;
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ if (!PermissionUtils.checkDumpPermission(mContext, TAG, writer)) return;
- for (ClientInfo client : mClients.values()) {
- pw.println("Client Info");
- pw.println(client);
- }
-
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ // Dump state machine logs
mNsdStateMachine.dump(fd, pw, args);
+
+ // Dump service and clients logs
+ pw.println();
+ pw.increaseIndent();
+ mServiceLogs.reverseDump(pw);
+ pw.decreaseIndent();
+
+ // Dump advertiser related logs
+ pw.println();
+ pw.println("Advertiser:");
+ pw.increaseIndent();
+ mAdvertiser.dump(pw);
+ pw.decreaseIndent();
+
+ // Dump discoverymanager related logs
+ pw.println();
+ pw.println("DiscoveryManager:");
+ pw.increaseIndent();
+ mMdnsDiscoveryManager.dump(pw);
+ pw.decreaseIndent();
+
+ // Dump socketprovider related logs
+ pw.println();
+ pw.println("SocketProvider:");
+ pw.increaseIndent();
+ mMdnsSocketProvider.dump(pw);
+ pw.decreaseIndent();
}
private abstract static class ClientRequest {
@@ -1813,11 +1864,14 @@
private boolean mIsPreSClient = false;
// The flag of using java backend if the client's target SDK >= U
private final boolean mUseJavaBackend;
+ // Store client logs
+ private final SharedLog mClientLogs;
- private ClientInfo(INsdManagerCallback cb, boolean useJavaBackend) {
+ private ClientInfo(INsdManagerCallback cb, boolean useJavaBackend, SharedLog sharedLog) {
mCb = cb;
mUseJavaBackend = useJavaBackend;
- if (DBG) Log.d(TAG, "New client");
+ mClientLogs = sharedLog;
+ mClientLogs.log("New client. useJavaBackend=" + useJavaBackend);
}
@Override
@@ -1855,6 +1909,7 @@
// Remove any pending requests from the global map when we get rid of a client,
// and send cancellations to the daemon.
private void expungeAllRequests() {
+ mClientLogs.log("Client unregistered. expungeAllRequests!");
// TODO: to keep handler responsive, do not clean all requests for that client at once.
for (int i = 0; i < mClientRequests.size(); i++) {
final int clientId = mClientRequests.keyAt(i);
@@ -1909,6 +1964,10 @@
return -1;
}
+ private void log(String message) {
+ mClientLogs.log(message);
+ }
+
void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
try {
mCb.onDiscoverServicesStarted(listenerKey, info);
diff --git a/service-t/src/com/android/server/connectivity/mdns/ISocketNetLinkMonitor.java b/service-t/src/com/android/server/connectivity/mdns/ISocketNetLinkMonitor.java
new file mode 100644
index 0000000..ef3928c
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/ISocketNetLinkMonitor.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2022 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.connectivity.mdns;
+
+/**
+ * The interface for netlink monitor.
+ */
+public interface ISocketNetLinkMonitor {
+
+ /**
+ * Returns if the netlink monitor is supported or not. By default, it is not supported.
+ */
+ default boolean isSupported() {
+ return false;
+ }
+
+ /**
+ * Starts the monitor.
+ */
+ default void startMonitoring() {
+ }
+
+ /**
+ * Stops the monitor.
+ */
+ default void stopMonitoring() {
+ }
+}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
index ec3e997..33fef9d 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsAdvertiser.java
@@ -28,7 +28,9 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.SharedLog;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.UUID;
@@ -46,6 +48,7 @@
// Top-level domain for link-local queries, as per RFC6762 3.
private static final String LOCAL_TLD = "local";
+ private static final SharedLog LOGGER = new SharedLog(TAG);
private final Looper mLooper;
private final AdvertiserCallback mCb;
@@ -82,7 +85,7 @@
// Note NetworkInterface is final and not mockable
final String logTag = socket.getInterface().getName();
return new MdnsInterfaceAdvertiser(logTag, socket, initialAddresses, looper,
- packetCreationBuffer, cb, deviceHostName);
+ packetCreationBuffer, cb, deviceHostName, LOGGER.forSubComponent(logTag));
}
/**
@@ -129,9 +132,7 @@
@Override
public void onServiceConflict(@NonNull MdnsInterfaceAdvertiser advertiser, int serviceId) {
- if (DBG) {
- Log.v(TAG, "Found conflict, restarted probing for service " + serviceId);
- }
+ LOGGER.i("Found conflict, restarted probing for service " + serviceId);
final Registration registration = mRegistrations.get(serviceId);
if (registration == null) return;
@@ -439,9 +440,7 @@
return;
}
- if (DBG) {
- Log.i(TAG, "Adding service " + service + " with ID " + id);
- }
+ LOGGER.i("Adding service " + service + " with ID " + id);
final Network network = service.getNetwork();
final Registration registration = new Registration(service);
@@ -473,9 +472,7 @@
public void removeService(int id) {
checkThread();
if (!mRegistrations.contains(id)) return;
- if (DBG) {
- Log.i(TAG, "Removing service with ID " + id);
- }
+ LOGGER.i("Removing service with ID " + id);
for (int i = mAdvertiserRequests.size() - 1; i >= 0; i--) {
final InterfaceAdvertiserRequest advertiser = mAdvertiserRequests.valueAt(i);
advertiser.removeService(id);
@@ -487,6 +484,10 @@
}
}
+ /** Dump info to dumpsys */
+ public void dump(PrintWriter pw) {
+ LOGGER.reverseDump(pw);
+ }
private static <K, V> boolean any(@NonNull ArrayMap<K, V> map,
@NonNull BiPredicate<K, V> predicate) {
for (int i = 0; i < map.size(); i++) {
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
index fb8af8d..491698d 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsDiscoveryManager.java
@@ -23,16 +23,16 @@
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.net.Network;
-import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.net.module.util.SharedLog;
import java.io.IOException;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -43,7 +43,7 @@
public class MdnsDiscoveryManager implements MdnsSocketClientBase.Callback {
private static final String TAG = MdnsDiscoveryManager.class.getSimpleName();
public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
- private static final MdnsLogger LOGGER = new MdnsLogger("MdnsDiscoveryManager");
+ private static final SharedLog LOGGER = new SharedLog(TAG);
private final ExecutorProvider executorProvider;
private final MdnsSocketClientBase socketClient;
@@ -120,9 +120,7 @@
@NonNull String serviceType,
@NonNull MdnsServiceBrowserListener listener,
@NonNull MdnsSearchOptions searchOptions) {
- LOGGER.log(
- "Registering listener for subtypes: %s",
- TextUtils.join(",", searchOptions.getSubtypes()));
+ LOGGER.i("Registering listener for serviceType: " + serviceType);
if (perNetworkServiceTypeClients.isEmpty()) {
// First listener. Starts the socket client.
try {
@@ -157,8 +155,7 @@
@RequiresPermission(permission.CHANGE_WIFI_MULTICAST_STATE)
public synchronized void unregisterListener(
@NonNull String serviceType, @NonNull MdnsServiceBrowserListener listener) {
- LOGGER.log("Unregistering listener for service type: %s", serviceType);
- if (DBG) Log.d(TAG, "Unregistering listener for serviceType:" + serviceType);
+ LOGGER.i("Unregistering listener for serviceType:" + serviceType);
final List<MdnsServiceTypeClient> serviceTypeClients =
perNetworkServiceTypeClients.getByServiceType(serviceType);
if (serviceTypeClients.isEmpty()) {
@@ -198,11 +195,19 @@
}
}
+ /** Dump info to dumpsys */
+ public void dump(PrintWriter pw) {
+ LOGGER.reverseDump(pw);
+ }
+
@VisibleForTesting
MdnsServiceTypeClient createServiceTypeClient(@NonNull String serviceType,
@Nullable Network network) {
+ LOGGER.log("createServiceTypeClient for serviceType:" + serviceType
+ + " network:" + network);
return new MdnsServiceTypeClient(
serviceType, socketClient,
- executorProvider.newServiceTypeClientSchedulerExecutor(), network);
+ executorProvider.newServiceTypeClientSchedulerExecutor(), network,
+ LOGGER.forSubComponent(serviceType + "-" + network));
}
}
\ No newline at end of file
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
index 79cddce..9eaa580 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiser.java
@@ -26,6 +26,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.HexDump;
+import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo;
import com.android.server.connectivity.mdns.MdnsPacketRepeater.PacketRepeaterCallback;
@@ -62,6 +63,9 @@
@NonNull
private final MdnsReplySender mReplySender;
+ @NonNull
+ private final SharedLog mSharedLog;
+
/**
* Callbacks called by {@link MdnsInterfaceAdvertiser} to report status updates.
*/
@@ -96,15 +100,13 @@
@Override
public void onFinished(MdnsProber.ProbingInfo info) {
final MdnsAnnouncer.AnnouncementInfo announcementInfo;
- if (DBG) {
- Log.v(mTag, "Probing finished for service " + info.getServiceId());
- }
+ mSharedLog.i("Probing finished for service " + info.getServiceId());
mCbHandler.post(() -> mCb.onRegisterServiceSucceeded(
MdnsInterfaceAdvertiser.this, info.getServiceId()));
try {
announcementInfo = mRecordRepository.onProbingSucceeded(info);
} catch (IOException e) {
- Log.e(mTag, "Error building announcements", e);
+ mSharedLog.e("Error building announcements", e);
return;
}
@@ -171,15 +173,16 @@
public MdnsInterfaceAdvertiser(@NonNull String logTag,
@NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> initialAddresses,
@NonNull Looper looper, @NonNull byte[] packetCreationBuffer, @NonNull Callback cb,
- @NonNull String[] deviceHostName) {
+ @NonNull String[] deviceHostName, @NonNull SharedLog sharedLog) {
this(logTag, socket, initialAddresses, looper, packetCreationBuffer, cb,
- new Dependencies(), deviceHostName);
+ new Dependencies(), deviceHostName, sharedLog);
}
public MdnsInterfaceAdvertiser(@NonNull String logTag,
@NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> initialAddresses,
@NonNull Looper looper, @NonNull byte[] packetCreationBuffer, @NonNull Callback cb,
- @NonNull Dependencies deps, @NonNull String[] deviceHostName) {
+ @NonNull Dependencies deps, @NonNull String[] deviceHostName,
+ @NonNull SharedLog sharedLog) {
mTag = MdnsInterfaceAdvertiser.class.getSimpleName() + "/" + logTag;
mRecordRepository = deps.makeRecordRepository(looper, deviceHostName);
mRecordRepository.updateAddresses(initialAddresses);
@@ -190,6 +193,7 @@
mAnnouncer = deps.makeMdnsAnnouncer(logTag, looper, mReplySender,
mAnnouncingCallback);
mProber = deps.makeMdnsProber(logTag, looper, mReplySender, mProbingCallback);
+ mSharedLog = sharedLog;
}
/**
@@ -213,10 +217,8 @@
// Cancel announcements for the existing service. This only happens for exiting services
// (so cancelling exiting announcements), as per RecordRepository.addService.
if (replacedExitingService >= 0) {
- if (DBG) {
- Log.d(mTag, "Service " + replacedExitingService
- + " getting re-added, cancelling exit announcements");
- }
+ mSharedLog.i("Service " + replacedExitingService
+ + " getting re-added, cancelling exit announcements");
mAnnouncer.stop(replacedExitingService);
}
mProber.startProbing(mRecordRepository.setServiceProbing(id));
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
index 5254342..7af2231 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsMultinetworkSocketClient.java
@@ -70,7 +70,7 @@
}
@Override
- public void onSocketCreated(@NonNull Network network,
+ public void onSocketCreated(@Nullable Network network,
@NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {
// The socket may be already created by other request before, try to get the stored
// ReadPacketHandler.
@@ -86,7 +86,7 @@
}
@Override
- public void onInterfaceDestroyed(@NonNull Network network,
+ public void onInterfaceDestroyed(@Nullable Network network,
@NonNull MdnsInterfaceSocket socket) {
mSocketPacketHandlers.remove(socket);
mActiveNetworkSockets.remove(socket);
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java
new file mode 100644
index 0000000..bfda535
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceCache.java
@@ -0,0 +1,178 @@
+/*
+ * 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.connectivity.mdns;
+
+import static com.android.server.connectivity.mdns.MdnsSocketProvider.ensureRunningOnHandlerThread;
+import static com.android.server.connectivity.mdns.util.MdnsUtils.equalsIgnoreDnsCase;
+import static com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLowerCase;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Network;
+import android.os.Handler;
+import android.os.Looper;
+import android.util.ArrayMap;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * The {@link MdnsServiceCache} manages the service which discovers from each socket and cache these
+ * services to reduce duplicated queries.
+ *
+ * <p>This class is not thread safe, it is intended to be used only from the looper thread.
+ * However, the constructor is an exception, as it is called on another thread;
+ * therefore for thread safety all members of this class MUST either be final or initialized
+ * to their default value (0, false or null).
+ */
+public class MdnsServiceCache {
+ private static class CacheKey {
+ @NonNull final String mLowercaseServiceType;
+ @Nullable final Network mNetwork;
+
+ CacheKey(@NonNull String serviceType, @Nullable Network network) {
+ mLowercaseServiceType = toDnsLowerCase(serviceType);
+ mNetwork = network;
+ }
+
+ @Override public int hashCode() {
+ return Objects.hash(mLowercaseServiceType, mNetwork);
+ }
+
+ @Override public boolean equals(Object other) {
+ if (this == other) {
+ return true;
+ }
+ if (!(other instanceof CacheKey)) {
+ return false;
+ }
+ return Objects.equals(mLowercaseServiceType, ((CacheKey) other).mLowercaseServiceType)
+ && Objects.equals(mNetwork, ((CacheKey) other).mNetwork);
+ }
+ }
+ /**
+ * A map of cached services. Key is composed of service name, type and network. Value is the
+ * service which use the service type to discover from each socket.
+ */
+ @NonNull
+ private final ArrayMap<CacheKey, List<MdnsResponse>> mCachedServices = new ArrayMap<>();
+ @NonNull
+ private final Handler mHandler;
+
+ public MdnsServiceCache(@NonNull Looper looper) {
+ mHandler = new Handler(looper);
+ }
+
+ /**
+ * Get the cache services which are queried from given service type and network.
+ *
+ * @param serviceType the target service type.
+ * @param network the target network
+ * @return the set of services which matches the given service type.
+ */
+ @NonNull
+ public List<MdnsResponse> getCachedServices(@NonNull String serviceType,
+ @Nullable Network network) {
+ ensureRunningOnHandlerThread(mHandler);
+ final CacheKey key = new CacheKey(serviceType, network);
+ return mCachedServices.containsKey(key)
+ ? Collections.unmodifiableList(new ArrayList<>(mCachedServices.get(key)))
+ : Collections.emptyList();
+ }
+
+ private MdnsResponse findMatchedResponse(@NonNull List<MdnsResponse> responses,
+ @NonNull String serviceName) {
+ for (MdnsResponse response : responses) {
+ if (equalsIgnoreDnsCase(serviceName, response.getServiceInstanceName())) {
+ return response;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the cache service.
+ *
+ * @param serviceName the target service name.
+ * @param serviceType the target service type.
+ * @param network the target network
+ * @return the service which matches given conditions.
+ */
+ @Nullable
+ public MdnsResponse getCachedService(@NonNull String serviceName,
+ @NonNull String serviceType, @Nullable Network network) {
+ ensureRunningOnHandlerThread(mHandler);
+ final List<MdnsResponse> responses =
+ mCachedServices.get(new CacheKey(serviceType, network));
+ if (responses == null) {
+ return null;
+ }
+ final MdnsResponse response = findMatchedResponse(responses, serviceName);
+ return response != null ? new MdnsResponse(response) : null;
+ }
+
+ /**
+ * Add or update a service.
+ *
+ * @param serviceType the service type.
+ * @param network the target network
+ * @param response the response of the discovered service.
+ */
+ public void addOrUpdateService(@NonNull String serviceType, @Nullable Network network,
+ @NonNull MdnsResponse response) {
+ ensureRunningOnHandlerThread(mHandler);
+ final List<MdnsResponse> responses = mCachedServices.computeIfAbsent(
+ new CacheKey(serviceType, network), key -> new ArrayList<>());
+ // Remove existing service if present.
+ final MdnsResponse existing =
+ findMatchedResponse(responses, response.getServiceInstanceName());
+ responses.remove(existing);
+ responses.add(response);
+ }
+
+ /**
+ * Remove a service which matches the given service name, type and network.
+ *
+ * @param serviceName the target service name.
+ * @param serviceType the target service type.
+ * @param network the target network.
+ */
+ @Nullable
+ public MdnsResponse removeService(@NonNull String serviceName, @NonNull String serviceType,
+ @Nullable Network network) {
+ ensureRunningOnHandlerThread(mHandler);
+ final List<MdnsResponse> responses =
+ mCachedServices.get(new CacheKey(serviceType, network));
+ if (responses == null) {
+ return null;
+ }
+ final Iterator<MdnsResponse> iterator = responses.iterator();
+ while (iterator.hasNext()) {
+ final MdnsResponse response = iterator.next();
+ if (equalsIgnoreDnsCase(serviceName, response.getServiceInstanceName())) {
+ iterator.remove();
+ return response;
+ }
+ }
+ return null;
+ }
+
+ // TODO: check ttl expiration for each service and notify to the clients.
+}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
index f87804b..72b931d 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsServiceTypeClient.java
@@ -28,7 +28,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.net.module.util.SharedLog;
import java.net.Inet4Address;
import java.net.Inet6Address;
@@ -49,8 +49,6 @@
public class MdnsServiceTypeClient {
private static final int DEFAULT_MTU = 1500;
- private static final MdnsLogger LOGGER = new MdnsLogger("MdnsServiceTypeClient");
-
private final String serviceType;
private final String[] serviceTypeLabels;
@@ -58,6 +56,7 @@
private final MdnsResponseDecoder responseDecoder;
private final ScheduledExecutorService executor;
@Nullable private final Network network;
+ @NonNull private final SharedLog sharedLog;
private final Object lock = new Object();
private final ArrayMap<MdnsServiceBrowserListener, MdnsSearchOptions> listeners =
new ArrayMap<>();
@@ -90,8 +89,10 @@
@NonNull String serviceType,
@NonNull MdnsSocketClientBase socketClient,
@NonNull ScheduledExecutorService executor,
- @Nullable Network network) {
- this(serviceType, socketClient, executor, new MdnsResponseDecoder.Clock(), network);
+ @Nullable Network network,
+ @NonNull SharedLog sharedLog) {
+ this(serviceType, socketClient, executor, new MdnsResponseDecoder.Clock(), network,
+ sharedLog);
}
@VisibleForTesting
@@ -100,7 +101,8 @@
@NonNull MdnsSocketClientBase socketClient,
@NonNull ScheduledExecutorService executor,
@NonNull MdnsResponseDecoder.Clock clock,
- @Nullable Network network) {
+ @Nullable Network network,
+ @NonNull SharedLog sharedLog) {
this.serviceType = serviceType;
this.socketClient = socketClient;
this.executor = executor;
@@ -108,6 +110,7 @@
this.responseDecoder = new MdnsResponseDecoder(clock, serviceTypeLabels);
this.clock = clock;
this.network = network;
+ this.sharedLog = sharedLog;
}
private static MdnsServiceInfo buildMdnsServiceInfoFromResponse(
@@ -174,6 +177,7 @@
this.searchOptions = searchOptions;
if (listeners.put(listener, searchOptions) == null) {
for (MdnsResponse existingResponse : instanceNameToResponse.values()) {
+ if (!responseMatchesOptions(existingResponse, searchOptions)) continue;
final MdnsServiceInfo info =
buildMdnsServiceInfoFromResponse(existingResponse, serviceTypeLabels);
listener.onServiceNameDiscovered(info);
@@ -199,6 +203,13 @@
}
}
+ private boolean responseMatchesOptions(@NonNull MdnsResponse response,
+ @NonNull MdnsSearchOptions options) {
+ if (options.getResolveInstanceName() == null) return true;
+ // DNS is case-insensitive, so ignore case in the comparison
+ return options.getResolveInstanceName().equalsIgnoreCase(response.getServiceInstanceName());
+ }
+
/**
* Unregisters {@code listener} from receiving discovery event of mDNS service instances.
*
@@ -253,20 +264,20 @@
}
private void onResponseModified(@NonNull MdnsResponse response) {
+ final String serviceInstanceName = response.getServiceInstanceName();
final MdnsResponse currentResponse =
- instanceNameToResponse.get(response.getServiceInstanceName());
+ instanceNameToResponse.get(serviceInstanceName);
boolean newServiceFound = false;
boolean serviceBecomesComplete = false;
if (currentResponse == null) {
newServiceFound = true;
- String serviceInstanceName = response.getServiceInstanceName();
if (serviceInstanceName != null) {
instanceNameToResponse.put(serviceInstanceName, response);
}
} else {
boolean before = currentResponse.isComplete();
- instanceNameToResponse.put(response.getServiceInstanceName(), response);
+ instanceNameToResponse.put(serviceInstanceName, response);
boolean after = response.isComplete();
serviceBecomesComplete = !before && after;
}
@@ -274,15 +285,19 @@
buildMdnsServiceInfoFromResponse(response, serviceTypeLabels);
for (int i = 0; i < listeners.size(); i++) {
+ if (!responseMatchesOptions(response, listeners.valueAt(i))) continue;
final MdnsServiceBrowserListener listener = listeners.keyAt(i);
if (newServiceFound) {
+ sharedLog.log("onServiceNameDiscovered: " + serviceInstanceName);
listener.onServiceNameDiscovered(serviceInfo);
}
if (response.isComplete()) {
if (newServiceFound || serviceBecomesComplete) {
+ sharedLog.log("onServiceFound: " + serviceInstanceName);
listener.onServiceFound(serviceInfo);
} else {
+ sharedLog.log("onServiceUpdated: " + serviceInstanceName);
listener.onServiceUpdated(serviceInfo);
}
}
@@ -295,12 +310,15 @@
return;
}
for (int i = 0; i < listeners.size(); i++) {
+ if (!responseMatchesOptions(response, listeners.valueAt(i))) continue;
final MdnsServiceBrowserListener listener = listeners.keyAt(i);
final MdnsServiceInfo serviceInfo =
buildMdnsServiceInfoFromResponse(response, serviceTypeLabels);
if (response.isComplete()) {
+ sharedLog.log("onServiceRemoved: " + serviceInstanceName);
listener.onServiceRemoved(serviceInfo);
}
+ sharedLog.log("onServiceNameRemoved: " + serviceInstanceName);
listener.onServiceNameRemoved(serviceInfo);
}
}
@@ -475,7 +493,7 @@
servicesToResolve)
.call();
} catch (RuntimeException e) {
- LOGGER.e(String.format("Failed to run EnqueueMdnsQueryCallable for subtype: %s",
+ sharedLog.e(String.format("Failed to run EnqueueMdnsQueryCallable for subtype: %s",
TextUtils.join(",", config.subtypes)), e);
result = null;
}
@@ -512,6 +530,10 @@
== 0) {
iter.remove();
for (int i = 0; i < listeners.size(); i++) {
+ if (!responseMatchesOptions(existingResponse,
+ listeners.valueAt(i))) {
+ continue;
+ }
final MdnsServiceBrowserListener listener = listeners.keyAt(i);
String serviceInstanceName =
existingResponse.getServiceInstanceName();
@@ -520,8 +542,12 @@
buildMdnsServiceInfoFromResponse(
existingResponse, serviceTypeLabels);
if (existingResponse.isComplete()) {
+ sharedLog.log("TTL expired. onServiceRemoved: "
+ + serviceInstanceName);
listener.onServiceRemoved(serviceInfo);
}
+ sharedLog.log("TTL expired. onServiceNameRemoved: "
+ + serviceInstanceName);
listener.onServiceNameRemoved(serviceInfo);
}
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
index 1d9a24c..c45345a 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MdnsSocketProvider.java
@@ -16,33 +16,35 @@
package com.android.server.connectivity.mdns;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
-import android.net.INetd;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
import android.net.TetheringManager;
import android.net.TetheringManager.TetheringEventCallback;
import android.os.Handler;
import android.os.Looper;
-import android.system.OsConstants;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
-import com.android.net.module.util.ip.NetlinkMonitor;
-import com.android.net.module.util.netlink.NetlinkConstants;
-import com.android.net.module.util.netlink.NetlinkMessage;
-import com.android.server.connectivity.mdns.util.MdnsLogger;
+import com.android.net.module.util.SharedLog;
import java.io.IOException;
+import java.io.PrintWriter;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
@@ -64,22 +66,27 @@
// But 1440 should generally be enough because of standard Ethernet.
// Note: mdnsresponder mDNSEmbeddedAPI.h uses 8940 for Ethernet jumbo frames.
private static final int READ_BUFFER_SIZE = 2048;
- private static final MdnsLogger LOGGER = new MdnsLogger(TAG);
+ private static final SharedLog LOGGER = new SharedLog(TAG);
+ private static final int IFACE_IDX_NOT_EXIST = -1;
@NonNull private final Context mContext;
@NonNull private final Looper mLooper;
@NonNull private final Handler mHandler;
@NonNull private final Dependencies mDependencies;
@NonNull private final NetworkCallback mNetworkCallback;
@NonNull private final TetheringEventCallback mTetheringEventCallback;
- @NonNull private final NetlinkMonitor mNetlinkMonitor;
+ @NonNull private final ISocketNetLinkMonitor mSocketNetlinkMonitor;
private final ArrayMap<Network, SocketInfo> mNetworkSockets = new ArrayMap<>();
private final ArrayMap<String, SocketInfo> mTetherInterfaceSockets = new ArrayMap<>();
private final ArrayMap<Network, LinkProperties> mActiveNetworksLinkProperties =
new ArrayMap<>();
+ private final ArrayMap<Network, int[]> mActiveNetworksTransports = new ArrayMap<>();
private final ArrayMap<SocketCallback, Network> mCallbacksToRequestedNetworks =
new ArrayMap<>();
private final List<String> mLocalOnlyInterfaces = new ArrayList<>();
private final List<String> mTetheredInterfaces = new ArrayList<>();
+ // mIfaceIdxToLinkProperties should not be cleared in maybeStopMonitoringSockets() because
+ // the netlink monitor is never stop and the old states must be kept.
+ private final SparseArray<LinkProperties> mIfaceIdxToLinkProperties = new SparseArray<>();
private final byte[] mPacketReadBuffer = new byte[READ_BUFFER_SIZE];
private boolean mMonitoringSockets = false;
private boolean mRequestStop = false;
@@ -98,7 +105,14 @@
@Override
public void onLost(Network network) {
mActiveNetworksLinkProperties.remove(network);
- removeSocket(network, null /* interfaceName */);
+ mActiveNetworksTransports.remove(network);
+ removeNetworkSocket(network);
+ }
+
+ @Override
+ public void onCapabilitiesChanged(@NonNull Network network,
+ @NonNull NetworkCapabilities networkCapabilities) {
+ mActiveNetworksTransports.put(network, networkCapabilities.getTransportTypes());
}
@Override
@@ -118,7 +132,8 @@
}
};
- mNetlinkMonitor = new SocketNetlinkMonitor(mHandler);
+ mSocketNetlinkMonitor = mDependencies.createSocketNetlinkMonitor(mHandler, LOGGER,
+ new NetLinkMessageProcessor());
}
/**
@@ -133,19 +148,89 @@
return ni == null ? null : new NetworkInterfaceWrapper(ni);
}
- /*** Check whether given network interface can support mdns */
- public boolean canScanOnInterface(@NonNull NetworkInterfaceWrapper networkInterface) {
- return MulticastNetworkInterfaceProvider.canScanOnInterface(networkInterface);
- }
-
/*** Create a MdnsInterfaceSocket */
public MdnsInterfaceSocket createMdnsInterfaceSocket(
@NonNull NetworkInterface networkInterface, int port, @NonNull Looper looper,
@NonNull byte[] packetReadBuffer) throws IOException {
return new MdnsInterfaceSocket(networkInterface, port, looper, packetReadBuffer);
}
- }
+ /*** Get network interface by given interface name */
+ public int getNetworkInterfaceIndexByName(@NonNull final String ifaceName) {
+ final NetworkInterface iface;
+ try {
+ iface = NetworkInterface.getByName(ifaceName);
+ } catch (SocketException e) {
+ Log.e(TAG, "Error querying interface", e);
+ return IFACE_IDX_NOT_EXIST;
+ }
+ if (iface == null) {
+ Log.e(TAG, "Interface not found: " + ifaceName);
+ return IFACE_IDX_NOT_EXIST;
+ }
+ return iface.getIndex();
+ }
+ /*** Creates a SocketNetlinkMonitor */
+ public ISocketNetLinkMonitor createSocketNetlinkMonitor(@NonNull final Handler handler,
+ @NonNull final SharedLog log,
+ @NonNull final NetLinkMonitorCallBack cb) {
+ return SocketNetLinkMonitorFactory.createNetLinkMonitor(handler, log, cb);
+ }
+ }
+ /**
+ * The callback interface for the netlink monitor messages.
+ */
+ public interface NetLinkMonitorCallBack {
+ /**
+ * Handles the interface address add or update.
+ */
+ void addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull LinkAddress newAddress);
+
+
+ /**
+ * Handles the interface address delete.
+ */
+ void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress);
+ }
+ private class NetLinkMessageProcessor implements NetLinkMonitorCallBack {
+
+ @Override
+ public void addOrUpdateInterfaceAddress(int ifaceIdx,
+ @NonNull final LinkAddress newAddress) {
+
+ LinkProperties linkProperties;
+ linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx);
+ if (linkProperties == null) {
+ linkProperties = new LinkProperties();
+ mIfaceIdxToLinkProperties.put(ifaceIdx, linkProperties);
+ }
+ boolean updated = linkProperties.addLinkAddress(newAddress);
+
+ if (!updated) {
+ return;
+ }
+ maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses());
+ }
+
+ @Override
+ public void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress) {
+ LinkProperties linkProperties;
+ boolean updated = false;
+ linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx);
+ if (linkProperties != null) {
+ updated = linkProperties.removeLinkAddress(deleteAddress);
+ if (linkProperties.getLinkAddresses().isEmpty()) {
+ mIfaceIdxToLinkProperties.remove(ifaceIdx);
+ }
+ }
+
+ if (linkProperties == null || !updated) {
+ return;
+ }
+ maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses());
+
+ }
+ }
/*** Data class for storing socket related info */
private static class SocketInfo {
final MdnsInterfaceSocket mSocket;
@@ -157,18 +242,6 @@
}
}
- private static class SocketNetlinkMonitor extends NetlinkMonitor {
- SocketNetlinkMonitor(Handler handler) {
- super(handler, LOGGER.mLog, TAG, OsConstants.NETLINK_ROUTE,
- NetlinkConstants.RTMGRP_IPV4_IFADDR | NetlinkConstants.RTMGRP_IPV6_IFADDR);
- }
-
- @Override
- public void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) {
- // TODO: Handle netlink message.
- }
- }
-
/*** Ensure that current running thread is same as given handler thread */
public static void ensureRunningOnHandlerThread(Handler handler) {
if (handler.getLooper().getThread() != Thread.currentThread()) {
@@ -185,7 +258,7 @@
Log.d(TAG, "Already monitoring sockets.");
return;
}
- if (DBG) Log.d(TAG, "Start monitoring sockets.");
+ LOGGER.i("Start monitoring sockets.");
mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback(
new NetworkRequest.Builder().clearCapabilities().build(),
mNetworkCallback, mHandler);
@@ -193,9 +266,20 @@
final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
tetheringManager.registerTetheringEventCallback(mHandler::post, mTetheringEventCallback);
- mHandler.post(mNetlinkMonitor::start);
+ if (mSocketNetlinkMonitor.isSupported()) {
+ mHandler.post(mSocketNetlinkMonitor::startMonitoring);
+ }
mMonitoringSockets = true;
}
+ /**
+ * Start netlink monitor.
+ */
+ public void startNetLinkMonitor() {
+ ensureRunningOnHandlerThread(mHandler);
+ if (mSocketNetlinkMonitor.isSupported()) {
+ mSocketNetlinkMonitor.startMonitoring();
+ }
+ }
private void maybeStopMonitoringSockets() {
if (!mMonitoringSockets) return; // Already unregistered.
@@ -203,14 +287,13 @@
// Only unregister the network callback if there is no socket request.
if (mCallbacksToRequestedNetworks.isEmpty()) {
+ LOGGER.i("Stop monitoring sockets.");
mContext.getSystemService(ConnectivityManager.class)
.unregisterNetworkCallback(mNetworkCallback);
final TetheringManager tetheringManager = mContext.getSystemService(
TetheringManager.class);
tetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback);
-
- mHandler.post(mNetlinkMonitor::stop);
// Clear all saved status.
mActiveNetworksLinkProperties.clear();
mNetworkSockets.clear();
@@ -219,6 +302,8 @@
mTetheredInterfaces.clear();
mMonitoringSockets = false;
}
+ // The netlink monitor is not stopped here because the MdnsSocketProvider need to listen
+ // to all the netlink updates when the system is up and running.
}
/*** Request to stop monitoring sockets and unregister callbacks */
@@ -228,14 +313,13 @@
Log.d(TAG, "Monitoring sockets hasn't been started.");
return;
}
- if (DBG) Log.d(TAG, "Try to stop monitoring sockets.");
mRequestStop = true;
maybeStopMonitoringSockets();
}
/*** Check whether the target network is matched current network */
public static boolean isNetworkMatched(@Nullable Network targetNetwork,
- @NonNull Network currentNetwork) {
+ @Nullable Network currentNetwork) {
return targetNetwork == null || targetNetwork.equals(currentNetwork);
}
@@ -258,25 +342,43 @@
return;
}
+ final NetworkAsKey networkKey = new NetworkAsKey(network);
final SocketInfo socketInfo = mNetworkSockets.get(network);
if (socketInfo == null) {
- createSocket(network, lp);
+ createSocket(networkKey, lp);
} else {
- // Update the addresses of this socket.
- final List<LinkAddress> addresses = lp.getLinkAddresses();
- socketInfo.mAddresses.clear();
- socketInfo.mAddresses.addAll(addresses);
- // Try to join the group again.
- socketInfo.mSocket.joinGroup(addresses);
-
- notifyAddressesChanged(network, socketInfo.mSocket, lp);
+ updateSocketInfoAddress(network, socketInfo, lp.getLinkAddresses());
+ }
+ }
+ private void maybeUpdateTetheringSocketAddress(int ifaceIndex,
+ @NonNull final List<LinkAddress> updatedAddresses) {
+ for (int i = 0; i < mTetherInterfaceSockets.size(); ++i) {
+ String tetheringInterfaceName = mTetherInterfaceSockets.keyAt(i);
+ if (mDependencies.getNetworkInterfaceIndexByName(tetheringInterfaceName)
+ == ifaceIndex) {
+ updateSocketInfoAddress(null /* network */,
+ mTetherInterfaceSockets.valueAt(i), updatedAddresses);
+ return;
+ }
}
}
- private static LinkProperties createLPForTetheredInterface(String interfaceName) {
- final LinkProperties linkProperties = new LinkProperties();
+ private void updateSocketInfoAddress(@Nullable final Network network,
+ @NonNull final SocketInfo socketInfo,
+ @NonNull final List<LinkAddress> addresses) {
+ // Update the addresses of this socket.
+ socketInfo.mAddresses.clear();
+ socketInfo.mAddresses.addAll(addresses);
+ // Try to join the group again.
+ socketInfo.mSocket.joinGroup(addresses);
+
+ notifyAddressesChanged(network, socketInfo.mSocket, addresses);
+ }
+ private LinkProperties createLPForTetheredInterface(@NonNull final String interfaceName,
+ int ifaceIndex) {
+ final LinkProperties linkProperties =
+ new LinkProperties(mIfaceIdxToLinkProperties.get(ifaceIndex));
linkProperties.setInterfaceName(interfaceName);
- // TODO: Use NetlinkMonitor to update addresses for tethering interfaces.
return linkProperties;
}
@@ -295,16 +397,17 @@
final CompareResult<String> interfaceDiff = new CompareResult<>(
current, updated);
for (String name : interfaceDiff.added) {
- createSocket(new Network(INetd.LOCAL_NET_ID), createLPForTetheredInterface(name));
+ int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(name);
+ createSocket(LOCAL_NET, createLPForTetheredInterface(name, ifaceIndex));
}
for (String name : interfaceDiff.removed) {
- removeSocket(new Network(INetd.LOCAL_NET_ID), name);
+ removeTetherInterfaceSocket(name);
}
current.clear();
current.addAll(updated);
}
- private void createSocket(Network network, LinkProperties lp) {
+ private void createSocket(NetworkKey networkKey, LinkProperties lp) {
final String interfaceName = lp.getInterfaceName();
if (interfaceName == null) {
Log.e(TAG, "Can not create socket with null interface name.");
@@ -314,44 +417,90 @@
try {
final NetworkInterfaceWrapper networkInterface =
mDependencies.getNetworkInterfaceByName(interfaceName);
- if (networkInterface == null || !mDependencies.canScanOnInterface(networkInterface)) {
+ // There are no transports for tethered interfaces. Other interfaces should always
+ // have transports since LinkProperties updates are always sent after
+ // NetworkCapabilities updates.
+ final int[] transports;
+ if (networkKey == LOCAL_NET) {
+ transports = new int[0];
+ } else {
+ transports = mActiveNetworksTransports.getOrDefault(
+ ((NetworkAsKey) networkKey).mNetwork, new int[0]);
+ }
+ if (networkInterface == null || !isMdnsCapableInterface(networkInterface, transports)) {
return;
}
- if (DBG) {
- Log.d(TAG, "Create a socket on network:" + network
- + " with interfaceName:" + interfaceName);
- }
+ LOGGER.log("Create socket on net:" + networkKey + ", ifName:" + interfaceName);
final MdnsInterfaceSocket socket = mDependencies.createMdnsInterfaceSocket(
networkInterface.getNetworkInterface(), MdnsConstants.MDNS_PORT, mLooper,
mPacketReadBuffer);
- final List<LinkAddress> addresses;
- if (network.netId == INetd.LOCAL_NET_ID) {
- addresses = CollectionUtils.map(
- networkInterface.getInterfaceAddresses(), LinkAddress::new);
+ final List<LinkAddress> addresses = lp.getLinkAddresses();
+ if (networkKey == LOCAL_NET) {
mTetherInterfaceSockets.put(interfaceName, new SocketInfo(socket, addresses));
} else {
- addresses = lp.getLinkAddresses();
- mNetworkSockets.put(network, new SocketInfo(socket, addresses));
+ mNetworkSockets.put(((NetworkAsKey) networkKey).mNetwork,
+ new SocketInfo(socket, addresses));
}
// Try to join IPv4/IPv6 group.
socket.joinGroup(addresses);
// Notify the listeners which need this socket.
- notifySocketCreated(network, socket, addresses);
+ if (networkKey == LOCAL_NET) {
+ notifySocketCreated(null /* network */, socket, addresses);
+ } else {
+ notifySocketCreated(((NetworkAsKey) networkKey).mNetwork, socket, addresses);
+ }
} catch (IOException e) {
- Log.e(TAG, "Create a socket failed with interface=" + interfaceName, e);
+ LOGGER.e("Create socket failed ifName:" + interfaceName, e);
}
}
- private void removeSocket(Network network, String interfaceName) {
- final SocketInfo socketInfo = network.netId == INetd.LOCAL_NET_ID
- ? mTetherInterfaceSockets.remove(interfaceName)
- : mNetworkSockets.remove(network);
+ private boolean isMdnsCapableInterface(
+ @NonNull NetworkInterfaceWrapper iface, @NonNull int[] transports) {
+ try {
+ // Never try mDNS on cellular, or on interfaces with incompatible flags
+ if (CollectionUtils.contains(transports, TRANSPORT_CELLULAR)
+ || iface.isLoopback()
+ || iface.isPointToPoint()
+ || iface.isVirtual()
+ || !iface.isUp()) {
+ return false;
+ }
+
+ // Otherwise, always try mDNS on non-VPN Wifi.
+ if (!CollectionUtils.contains(transports, TRANSPORT_VPN)
+ && CollectionUtils.contains(transports, TRANSPORT_WIFI)) {
+ return true;
+ }
+
+ // For other transports, or no transports (tethering downstreams), do mDNS based on the
+ // interface flags. This is not always reliable (for example some Wifi interfaces may
+ // not have the MULTICAST flag even though they can do mDNS, and some cellular
+ // interfaces may have the BROADCAST or MULTICAST flags), so checks are done based on
+ // transports above in priority.
+ return iface.supportsMulticast();
+ } catch (SocketException e) {
+ LOGGER.e("Error checking interface flags", e);
+ return false;
+ }
+ }
+
+ private void removeNetworkSocket(Network network) {
+ final SocketInfo socketInfo = mNetworkSockets.remove(network);
if (socketInfo == null) return;
socketInfo.mSocket.destroy();
notifyInterfaceDestroyed(network, socketInfo.mSocket);
+ LOGGER.log("Remove socket on net:" + network);
+ }
+
+ private void removeTetherInterfaceSocket(String interfaceName) {
+ final SocketInfo socketInfo = mTetherInterfaceSockets.remove(interfaceName);
+ if (socketInfo == null) return;
+ socketInfo.mSocket.destroy();
+ notifyInterfaceDestroyed(null /* network */, socketInfo.mSocket);
+ LOGGER.log("Remove socket on ifName:" + interfaceName);
}
private void notifySocketCreated(Network network, MdnsInterfaceSocket socket,
@@ -374,12 +523,12 @@
}
private void notifyAddressesChanged(Network network, MdnsInterfaceSocket socket,
- LinkProperties lp) {
+ List<LinkAddress> addresses) {
for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) {
final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i);
if (isNetworkMatched(requestedNetwork, network)) {
mCallbacksToRequestedNetworks.keyAt(i)
- .onAddressesChanged(network, socket, lp.getLinkAddresses());
+ .onAddressesChanged(network, socket, addresses);
}
}
}
@@ -393,7 +542,7 @@
if (DBG) Log.d(TAG, "There is no LinkProperties for this network:" + network);
return;
}
- createSocket(network, lp);
+ createSocket(new NetworkAsKey(network), lp);
} else {
// Notify the socket for requested network.
cb.onSocketCreated(network, socketInfo.mSocket, socketInfo.mAddresses);
@@ -403,12 +552,14 @@
private void retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb) {
final SocketInfo socketInfo = mTetherInterfaceSockets.get(interfaceName);
if (socketInfo == null) {
+ int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(interfaceName);
createSocket(
- new Network(INetd.LOCAL_NET_ID), createLPForTetheredInterface(interfaceName));
+ LOCAL_NET,
+ createLPForTetheredInterface(interfaceName, ifaceIndex));
} else {
// Notify the socket for requested network.
cb.onSocketCreated(
- new Network(INetd.LOCAL_NET_ID), socketInfo.mSocket, socketInfo.mAddresses);
+ null /* network */, socketInfo.mSocket, socketInfo.mAddresses);
}
}
@@ -458,6 +609,7 @@
info.mSocket.destroy();
// Still notify to unrequester for socket destroy.
cb.onInterfaceDestroyed(network, info.mSocket);
+ LOGGER.log("Remove socket on net:" + network + " after unrequestSocket");
}
// Remove all sockets for tethering interface because these sockets do not have associated
@@ -467,7 +619,9 @@
final SocketInfo info = mTetherInterfaceSockets.valueAt(i);
info.mSocket.destroy();
// Still notify to unrequester for socket destroy.
- cb.onInterfaceDestroyed(new Network(INetd.LOCAL_NET_ID), info.mSocket);
+ cb.onInterfaceDestroyed(null /* network */, info.mSocket);
+ LOGGER.log("Remove socket on ifName:" + mTetherInterfaceSockets.keyAt(i)
+ + " after unrequestSocket");
}
mTetherInterfaceSockets.clear();
@@ -475,16 +629,57 @@
maybeStopMonitoringSockets();
}
+ /** Dump info to dumpsys */
+ public void dump(PrintWriter pw) {
+ LOGGER.reverseDump(pw);
+ }
+
/*** Callbacks for listening socket changes */
public interface SocketCallback {
/*** Notify the socket is created */
- default void onSocketCreated(@NonNull Network network, @NonNull MdnsInterfaceSocket socket,
+ default void onSocketCreated(@Nullable Network network, @NonNull MdnsInterfaceSocket socket,
@NonNull List<LinkAddress> addresses) {}
/*** Notify the interface is destroyed */
- default void onInterfaceDestroyed(@NonNull Network network,
+ default void onInterfaceDestroyed(@Nullable Network network,
@NonNull MdnsInterfaceSocket socket) {}
/*** Notify the addresses is changed on the network */
- default void onAddressesChanged(@NonNull Network network,
+ default void onAddressesChanged(@Nullable Network network,
@NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {}
}
+
+ private interface NetworkKey {
+ }
+
+ private static final NetworkKey LOCAL_NET = new NetworkKey() {
+ @Override
+ public String toString() {
+ return "NetworkKey:LOCAL_NET";
+ }
+ };
+
+ private static class NetworkAsKey implements NetworkKey {
+ private final Network mNetwork;
+
+ NetworkAsKey(Network network) {
+ this.mNetwork = network;
+ }
+
+ @Override
+ public int hashCode() {
+ return mNetwork.hashCode();
+ }
+
+ @Override
+ public boolean equals(@Nullable Object other) {
+ if (!(other instanceof NetworkAsKey)) {
+ return false;
+ }
+ return mNetwork.equals(((NetworkAsKey) other).mNetwork);
+ }
+
+ @Override
+ public String toString() {
+ return "NetworkAsKey{ network=" + mNetwork + " }";
+ }
+ }
}
diff --git a/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java b/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java
index ade7b95..f248c98 100644
--- a/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java
+++ b/service-t/src/com/android/server/connectivity/mdns/MulticastNetworkInterfaceProvider.java
@@ -148,7 +148,7 @@
}
/*** Check whether given network interface can support mdns */
- public static boolean canScanOnInterface(@Nullable NetworkInterfaceWrapper networkInterface) {
+ private static boolean canScanOnInterface(@Nullable NetworkInterfaceWrapper networkInterface) {
try {
if ((networkInterface == null)
|| networkInterface.isLoopback()
diff --git a/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java b/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java
new file mode 100644
index 0000000..4650255
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/SocketNetLinkMonitorFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2022 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.connectivity.mdns;
+
+import android.annotation.NonNull;
+import android.os.Handler;
+
+import com.android.net.module.util.SharedLog;
+import com.android.server.connectivity.mdns.internal.SocketNetlinkMonitor;
+
+/**
+ * The factory class for creating the netlink monitor.
+ */
+public class SocketNetLinkMonitorFactory {
+
+ /**
+ * Creates a new netlink monitor.
+ */
+ public static ISocketNetLinkMonitor createNetLinkMonitor(@NonNull final Handler handler,
+ @NonNull SharedLog log, @NonNull MdnsSocketProvider.NetLinkMonitorCallBack cb) {
+ return new SocketNetlinkMonitor(handler, log, cb);
+ }
+
+ private SocketNetLinkMonitorFactory() {
+ }
+
+}
diff --git a/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java b/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
new file mode 100644
index 0000000..6395b53
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/internal/SocketNetlinkMonitor.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 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.connectivity.mdns.internal;
+
+import android.annotation.NonNull;
+import android.net.LinkAddress;
+import android.os.Handler;
+import android.system.OsConstants;
+import android.util.Log;
+
+import com.android.net.module.util.SharedLog;
+import com.android.net.module.util.ip.NetlinkMonitor;
+import com.android.net.module.util.netlink.NetlinkConstants;
+import com.android.net.module.util.netlink.NetlinkMessage;
+import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
+import com.android.net.module.util.netlink.StructIfaddrMsg;
+import com.android.server.connectivity.mdns.ISocketNetLinkMonitor;
+import com.android.server.connectivity.mdns.MdnsSocketProvider;
+
+/**
+ * The netlink monitor for MdnsSocketProvider.
+ */
+public class SocketNetlinkMonitor extends NetlinkMonitor implements ISocketNetLinkMonitor {
+
+ public static final String TAG = SocketNetlinkMonitor.class.getSimpleName();
+
+ @NonNull
+ private final MdnsSocketProvider.NetLinkMonitorCallBack mCb;
+ public SocketNetlinkMonitor(@NonNull final Handler handler,
+ @NonNull SharedLog log,
+ @NonNull final MdnsSocketProvider.NetLinkMonitorCallBack cb) {
+ super(handler, log, TAG, OsConstants.NETLINK_ROUTE,
+ NetlinkConstants.RTMGRP_IPV4_IFADDR | NetlinkConstants.RTMGRP_IPV6_IFADDR);
+ mCb = cb;
+ }
+ @Override
+ public void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) {
+ if (nlMsg instanceof RtNetlinkAddressMessage) {
+ processRtNetlinkAddressMessage((RtNetlinkAddressMessage) nlMsg);
+ }
+ }
+
+ /**
+ * Process the RTM_NEWADDR and RTM_DELADDR netlink message.
+ */
+ private void processRtNetlinkAddressMessage(RtNetlinkAddressMessage msg) {
+ final StructIfaddrMsg ifaddrMsg = msg.getIfaddrHeader();
+ final LinkAddress la = new LinkAddress(msg.getIpAddress(), ifaddrMsg.prefixLen,
+ msg.getFlags(), ifaddrMsg.scope);
+ if (!la.isPreferred()) {
+ // Skip the unusable ip address.
+ return;
+ }
+ switch (msg.getHeader().nlmsg_type) {
+ case NetlinkConstants.RTM_NEWADDR:
+ mCb.addOrUpdateInterfaceAddress(ifaddrMsg.index, la);
+ break;
+ case NetlinkConstants.RTM_DELADDR:
+ mCb.deleteInterfaceAddress(ifaddrMsg.index, la);
+ break;
+ default:
+ Log.e(TAG, "Unknown rtnetlink address msg type " + msg.getHeader().nlmsg_type);
+ }
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public void startMonitoring() {
+ this.start();
+ }
+
+ @Override
+ public void stopMonitoring() {
+ this.stop();
+ }
+}
diff --git a/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
new file mode 100644
index 0000000..4b0f2a4
--- /dev/null
+++ b/service-t/src/com/android/server/connectivity/mdns/util/MdnsUtils.java
@@ -0,0 +1,59 @@
+/*
+ * 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.connectivity.mdns.util;
+
+import android.annotation.NonNull;
+
+/**
+ * Mdns utility functions.
+ */
+public class MdnsUtils {
+
+ private MdnsUtils() { }
+
+ /**
+ * Convert the string to DNS case-insensitive lowercase
+ *
+ * Per rfc6762#page-46, accented characters are not defined to be automatically equivalent to
+ * their unaccented counterparts. So the "DNS lowercase" should be if character is A-Z then they
+ * transform into a-z. Otherwise, they are kept as-is.
+ */
+ public static String toDnsLowerCase(@NonNull String string) {
+ final char[] outChars = new char[string.length()];
+ for (int i = 0; i < string.length(); i++) {
+ outChars[i] = toDnsLowerCase(string.charAt(i));
+ }
+ return new String(outChars);
+ }
+
+ /**
+ * Compare two strings by DNS case-insensitive lowercase.
+ */
+ public static boolean equalsIgnoreDnsCase(@NonNull String a, @NonNull String b) {
+ if (a.length() != b.length()) return false;
+ for (int i = 0; i < a.length(); i++) {
+ if (toDnsLowerCase(a.charAt(i)) != toDnsLowerCase(b.charAt(i))) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ private static char toDnsLowerCase(char a) {
+ return a >= 'A' && a <= 'Z' ? (char) (a + ('a' - 'A')) : a;
+ }
+}
diff --git a/service-t/src/com/android/server/net/NetworkStatsFactory.java b/service-t/src/com/android/server/net/NetworkStatsFactory.java
index 5952eae..5f66f47 100644
--- a/service-t/src/com/android/server/net/NetworkStatsFactory.java
+++ b/service-t/src/com/android/server/net/NetworkStatsFactory.java
@@ -84,12 +84,9 @@
* are expected to monotonically increase since device boot.
*/
@NonNull
- public NetworkStats getNetworkStatsDetail(int limitUid, @Nullable String[] limitIfaces,
- int limitTag) throws IOException {
+ public NetworkStats getNetworkStatsDetail() throws IOException {
final NetworkStats stats = new NetworkStats(SystemClock.elapsedRealtime(), 0);
- // TODO: remove both path and useBpfStats arguments.
- // The path is never used if useBpfStats is true.
- final int ret = nativeReadNetworkStatsDetail(stats, limitUid, limitIfaces, limitTag);
+ final int ret = nativeReadNetworkStatsDetail(stats);
if (ret != 0) {
throw new IOException("Failed to parse network stats");
}
@@ -213,8 +210,7 @@
requestSwapActiveStatsMapLocked();
// Stats are always read from the inactive map, so they must be read after the
// swap
- final NetworkStats stats = mDeps.getNetworkStatsDetail(
- UID_ALL, INTERFACES_ALL, TAG_ALL);
+ final NetworkStats stats = mDeps.getNetworkStatsDetail();
// BPF stats are incremental; fold into mPersistSnapshot.
mPersistSnapshot.setElapsedRealtime(stats.getElapsedRealtime());
mPersistSnapshot.combineAllValues(stats);
@@ -301,8 +297,7 @@
* are expected to monotonically increase since device boot.
*/
@VisibleForTesting
- public static native int nativeReadNetworkStatsDetail(NetworkStats stats, int limitUid,
- String[] limitIfaces, int limitTag);
+ public static native int nativeReadNetworkStatsDetail(NetworkStats stats);
@VisibleForTesting
public static native int nativeReadNetworkStatsDev(NetworkStats stats);
diff --git a/service-t/src/com/android/server/net/NetworkStatsService.java b/service-t/src/com/android/server/net/NetworkStatsService.java
index 961337d..c660792 100644
--- a/service-t/src/com/android/server/net/NetworkStatsService.java
+++ b/service-t/src/com/android/server/net/NetworkStatsService.java
@@ -946,7 +946,11 @@
@GuardedBy("mStatsLock")
private void shutdownLocked() {
final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
- tetheringManager.unregisterTetheringEventCallback(mTetherListener);
+ try {
+ tetheringManager.unregisterTetheringEventCallback(mTetherListener);
+ } catch (IllegalStateException e) {
+ Log.i(TAG, "shutdownLocked: error when unregister tethering, ignored. e=" + e);
+ }
mContext.unregisterReceiver(mPollReceiver);
mContext.unregisterReceiver(mRemovedReceiver);
mContext.unregisterReceiver(mUserReceiver);
diff --git a/service/jni/com_android_server_TestNetworkService.cpp b/service/jni/com_android_server_TestNetworkService.cpp
index 7aeecfa..3e4c4de 100644
--- a/service/jni/com_android_server_TestNetworkService.cpp
+++ b/service/jni/com_android_server_TestNetworkService.cpp
@@ -38,9 +38,14 @@
#include "jni.h"
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
+#include <bpf/KernelVersion.h>
#include <nativehelper/JNIHelp.h>
#include <nativehelper/ScopedUtfChars.h>
+#ifndef IFF_NO_CARRIER
+#define IFF_NO_CARRIER 0x0040
+#endif
+
namespace android {
//------------------------------------------------------------------------------
@@ -66,17 +71,21 @@
// Allocate interface.
ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
+ if (!hasCarrier) {
+ // Using IFF_NO_CARRIER is supported starting in kernel version >= 6.0
+ // Up until then, unsupported flags are ignored.
+ if (!bpf::isAtLeastKernelVersion(6, 0, 0)) {
+ throwException(env, EOPNOTSUPP, "IFF_NO_CARRIER not supported", ifr.ifr_name);
+ return -1;
+ }
+ ifr.ifr_flags |= IFF_NO_CARRIER;
+ }
strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
throwException(env, errno, "allocating", ifr.ifr_name);
return -1;
}
- if (!hasCarrier) {
- // disable carrier before setting IFF_UP
- setTunTapCarrierEnabledImpl(env, iface, tun.get(), hasCarrier);
- }
-
// Mark some TAP interfaces as supporting multicast
if (setIffMulticast && !isTun) {
base::unique_fd inet6CtrlSock(socket(AF_INET6, SOCK_DGRAM, 0));
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index ad4596d..8d909ed 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -26,9 +26,14 @@
#include <nativehelper/JNIHelp.h>
#include <net/if.h>
#include <spawn.h>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <sys/wait.h>
+#include <sys/xattr.h>
#include <string>
+#include <unistd.h>
+#include <android-modules-utils/sdk_level.h>
#include <bpf/BpfMap.h>
#include <bpf/BpfUtils.h>
#include <netjniutils/netjniutils.h>
@@ -45,7 +50,103 @@
#define DEVICEPREFIX "v4-"
namespace android {
-static const char* kClatdPath = "/apex/com.android.tethering/bin/for-system/clatd";
+
+static bool fatal = false;
+
+#define ALOGF(s ...) do { ALOGE(s); fatal = true; } while(0)
+
+enum verify { VERIFY_DIR, VERIFY_BIN, VERIFY_PROG, VERIFY_MAP_RO, VERIFY_MAP_RW };
+
+static void verifyPerms(const char * const path,
+ const mode_t mode, const uid_t uid, const gid_t gid,
+ const char * const ctxt,
+ const verify vtype) {
+ struct stat s = {};
+
+ if (lstat(path, &s)) ALOGF("lstat '%s' errno=%d", path, errno);
+ if (s.st_mode != mode) ALOGF("'%s' mode is 0%o != 0%o", path, s.st_mode, mode);
+ if (s.st_uid != uid) ALOGF("'%s' uid is %d != %d", path, s.st_uid, uid);
+ if (s.st_gid != gid) ALOGF("'%s' gid is %d != %d", path, s.st_gid, gid);
+
+ char b[255] = {};
+ int v = lgetxattr(path, "security.selinux", &b, sizeof(b));
+ if (v < 0) ALOGF("lgetxattr '%s' errno=%d", path, errno);
+ if (strncmp(ctxt, b, sizeof(b))) ALOGF("context of '%s' is '%s' != '%s'", path, b, ctxt);
+
+ int fd = -1;
+
+ switch (vtype) {
+ case VERIFY_DIR: return;
+ case VERIFY_BIN: return;
+ case VERIFY_PROG: fd = bpf::retrieveProgram(path); break;
+ case VERIFY_MAP_RO: fd = bpf::mapRetrieveRO(path); break;
+ case VERIFY_MAP_RW: fd = bpf::mapRetrieveRW(path); break;
+ }
+
+ if (fd < 0) ALOGF("bpf_obj_get '%s' failed, errno=%d", path, errno);
+
+ if (fd >= 0) close(fd);
+}
+
+#undef ALOGF
+
+bool isGsiImage() {
+ // this implementation matches 2 other places in the codebase (same function name too)
+ return !access("/system/system_ext/etc/init/init.gsi.rc", F_OK);
+}
+
+static const char* kClatdDir = "/apex/com.android.tethering/bin/for-system";
+static const char* kClatdBin = "/apex/com.android.tethering/bin/for-system/clatd";
+
+#define V(path, md, uid, gid, ctx, vtype) \
+ verifyPerms((path), (md), AID_ ## uid, AID_ ## gid, "u:object_r:" ctx ":s0", VERIFY_ ## vtype)
+
+static void verifyClatPerms() {
+ // We might run as part of tests instead of as part of system server
+ if (getuid() != AID_SYSTEM) return;
+
+ // First verify the clatd directory and binary,
+ // since this is built into the apex file system image,
+ // failures here are 99% likely to be build problems.
+ V(kClatdDir, S_IFDIR|0750, ROOT, SYSTEM, "system_file", DIR);
+ V(kClatdBin, S_IFREG|S_ISUID|S_ISGID|0755, CLAT, CLAT, "clatd_exec", BIN);
+
+ // Move on to verifying that the bpf programs and maps are as expected.
+ // This relies on the kernel and bpfloader.
+
+ // Clat BPF was only mainlined during T.
+ if (!modules::sdklevel::IsAtLeastT()) return;
+
+ V("/sys/fs/bpf", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf", DIR);
+ V("/sys/fs/bpf/net_shared", S_IFDIR|S_ISVTX|0777, ROOT, ROOT, "fs_bpf_net_shared", DIR);
+
+ // pre-U we do not have selinux privs to getattr on bpf maps/progs
+ // so while the below *should* be as listed, we have no way to actually verify
+ if (!modules::sdklevel::IsAtLeastU()) return;
+
+#define V2(path, md, vtype) \
+ V("/sys/fs/bpf/net_shared/" path, (md), ROOT, SYSTEM, "fs_bpf_net_shared", vtype)
+
+ V2("prog_clatd_schedcls_egress4_clat_rawip", S_IFREG|0440, PROG);
+ V2("prog_clatd_schedcls_ingress6_clat_rawip", S_IFREG|0440, PROG);
+ V2("prog_clatd_schedcls_ingress6_clat_ether", S_IFREG|0440, PROG);
+ V2("map_clatd_clat_egress4_map", S_IFREG|0660, MAP_RW);
+ V2("map_clatd_clat_ingress6_map", S_IFREG|0660, MAP_RW);
+
+#undef V2
+
+ // HACK: Some old vendor kernels lack ~5.10 backport of 'bpffs selinux genfscon' support.
+ // This is *NOT* supported, but let's allow, at least for now, U+ GSI to boot on them.
+ // (without this hack pixel5 R vendor + U gsi breaks)
+ if (isGsiImage() && !bpf::isAtLeastKernelVersion(5, 10, 0)) {
+ ALOGE("GSI with *BAD* pre-5.10 kernel lacking bpffs selinux genfscon support.");
+ return;
+ }
+
+ if (fatal) abort();
+}
+
+#undef V
static void throwIOException(JNIEnv* env, const char* msg, int error) {
jniThrowExceptionFmt(env, "java/io/IOException", "%s: %s", msg, strerror(error));
@@ -138,7 +239,7 @@
}
struct ifreq ifr = {
- .ifr_flags = IFF_TUN,
+ .ifr_flags = static_cast<short>(IFF_TUN | IFF_TUN_EXCL),
};
strlcpy(ifr.ifr_name, v4interface.c_str(), sizeof(ifr.ifr_name));
@@ -365,7 +466,7 @@
// 5. actually perform vfork/dup2/execve
pid_t pid;
- if (int ret = posix_spawn(&pid, kClatdPath, &fa, &attr, (char* const*)args, nullptr)) {
+ if (int ret = posix_spawn(&pid, kClatdBin, &fa, &attr, (char* const*)args, nullptr)) {
posix_spawnattr_destroy(&attr);
posix_spawn_file_actions_destroy(&fa);
throwIOException(env, "posix_spawn failed", ret);
@@ -384,11 +485,15 @@
static constexpr int WAITPID_ATTEMPTS = 50;
static constexpr int WAITPID_RETRY_INTERVAL_US = 100000;
-static void stopClatdProcess(int pid) {
- int err = kill(pid, SIGTERM);
- if (err) {
- err = errno;
+static void com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv* env, jclass clazz,
+ jint pid) {
+ if (pid <= 0) {
+ jniThrowExceptionFmt(env, "java/io/IOException", "Invalid pid");
+ return;
}
+
+ int err = kill(pid, SIGTERM);
+ if (err) err = errno;
if (err == ESRCH) {
ALOGE("clatd child process %d unexpectedly disappeared", pid);
return;
@@ -405,7 +510,9 @@
if (ret == 0) {
ALOGE("Failed to SIGTERM clatd pid=%d, try SIGKILL", pid);
// TODO: fix that kill failed or waitpid doesn't return.
- kill(pid, SIGKILL);
+ if (kill(pid, SIGKILL)) {
+ ALOGE("Failed to SIGKILL clatd pid=%d: %s", pid, strerror(errno));
+ }
ret = waitpid(pid, &status, 0);
}
if (ret == -1) {
@@ -415,23 +522,6 @@
}
}
-static void com_android_server_connectivity_ClatCoordinator_stopClatd(JNIEnv* env, jclass clazz,
- jstring iface, jstring pfx96,
- jstring v4, jstring v6,
- jint pid) {
- ScopedUtfChars ifaceStr(env, iface);
- ScopedUtfChars pfx96Str(env, pfx96);
- ScopedUtfChars v4Str(env, v4);
- ScopedUtfChars v6Str(env, v6);
-
- if (pid <= 0) {
- jniThrowExceptionFmt(env, "java/io/IOException", "Invalid pid");
- return;
- }
-
- stopClatdProcess(pid);
-}
-
static jlong com_android_server_connectivity_ClatCoordinator_getSocketCookie(
JNIEnv* env, jclass clazz, jobject sockJavaFd) {
int sockFd = netjniutils::GetNativeFileDescriptor(env, sockJavaFd);
@@ -441,7 +531,7 @@
}
uint64_t sock_cookie = bpf::getSocketCookie(sockFd);
- if (sock_cookie == bpf::NONEXISTENT_COOKIE) {
+ if (!sock_cookie) {
throwIOException(env, "get socket cookie failed", errno);
return -1;
}
@@ -476,14 +566,14 @@
"(Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/io/FileDescriptor;Ljava/lang/"
"String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)I",
(void*)com_android_server_connectivity_ClatCoordinator_startClatd},
- {"native_stopClatd",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V",
+ {"native_stopClatd", "(I)V",
(void*)com_android_server_connectivity_ClatCoordinator_stopClatd},
{"native_getSocketCookie", "(Ljava/io/FileDescriptor;)J",
(void*)com_android_server_connectivity_ClatCoordinator_getSocketCookie},
};
int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env) {
+ verifyClatPerms();
return jniRegisterNativeMethods(env,
"android/net/connectivity/com/android/server/connectivity/ClatCoordinator",
gMethods, NELEM(gMethods));
diff --git a/service/jni/onload.cpp b/service/jni/onload.cpp
index 3d15d43..4bbaae6 100644
--- a/service/jni/onload.cpp
+++ b/service/jni/onload.cpp
@@ -22,8 +22,8 @@
namespace android {
int register_com_android_server_TestNetworkService(JNIEnv* env);
-int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env);
int register_com_android_server_BpfNetMaps(JNIEnv* env);
+int register_com_android_server_connectivity_ClatCoordinator(JNIEnv* env);
int register_android_server_net_NetworkStatsFactory(JNIEnv* env);
int register_android_server_net_NetworkStatsService(JNIEnv* env);
@@ -38,15 +38,15 @@
return JNI_ERR;
}
- if (register_com_android_server_connectivity_ClatCoordinator(env) < 0) {
- return JNI_ERR;
- }
-
if (register_com_android_server_BpfNetMaps(env) < 0) {
return JNI_ERR;
}
if (android::modules::sdklevel::IsAtLeastT()) {
+ if (register_com_android_server_connectivity_ClatCoordinator(env) < 0) {
+ return JNI_ERR;
+ }
+
if (register_android_server_net_NetworkStatsFactory(env) < 0) {
return JNI_ERR;
}
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index 2af30dd..b449e72 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -98,6 +98,7 @@
import static com.android.net.module.util.DeviceConfigUtils.TETHERING_MODULE_NAME;
import static com.android.net.module.util.NetworkMonitorUtils.isPrivateDnsValidationRequired;
+import static com.android.net.module.util.PermissionUtils.checkAnyPermissionOf;
import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission;
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermissionOr;
@@ -243,6 +244,7 @@
import android.util.LocalLog;
import android.util.Log;
import android.util.Pair;
+import android.util.Range;
import android.util.SparseArray;
import android.util.SparseIntArray;
@@ -309,11 +311,13 @@
import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
+import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
@@ -463,7 +467,11 @@
private String mCurrentTcpBufferSizes;
private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
- new Class[] { ConnectivityService.class, NetworkAgent.class, NetworkAgentInfo.class });
+ new Class[] {
+ ConnectivityService.class,
+ NetworkAgent.class,
+ NetworkAgentInfo.class,
+ AutomaticOnOffKeepaliveTracker.class });
private enum ReapUnvalidatedNetworks {
// Tear down networks that have no chance (e.g. even if validated) of becoming
@@ -1480,6 +1488,18 @@
@NonNull final UserHandle user) {
return CompatChanges.isChangeEnabled(changeId, packageName, user);
}
+
+ /**
+ * Call {@link InetDiagMessage#destroyLiveTcpSockets(Set, Set)}
+ *
+ * @param ranges target uid ranges
+ * @param exemptUids uids to skip close socket
+ */
+ public void destroyLiveTcpSockets(@NonNull final Set<Range<Integer>> ranges,
+ @NonNull final Set<Integer> exemptUids)
+ throws SocketException, InterruptedIOException, ErrnoException {
+ InetDiagMessage.destroyLiveTcpSockets(ranges, exemptUids);
+ }
}
public ConnectivityService(Context context) {
@@ -2324,11 +2344,12 @@
if (newNc.getNetworkSpecifier() != null) {
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
- if (!checkAnyPermissionOf(callerPid, callerUid, android.Manifest.permission.NETWORK_STACK,
+ if (!checkAnyPermissionOf(mContext, callerPid, callerUid,
+ android.Manifest.permission.NETWORK_STACK,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)) {
newNc.setAdministratorUids(new int[0]);
}
- if (!checkAnyPermissionOf(
+ if (!checkAnyPermissionOf(mContext,
callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
newNc.setAllowedUids(new ArraySet<>());
newNc.setSubscriptionIds(Collections.emptySet());
@@ -2837,15 +2858,6 @@
setUidBlockedReasons(uid, blockedReasons);
}
- private boolean checkAnyPermissionOf(int pid, int uid, String... permissions) {
- for (String permission : permissions) {
- if (mContext.checkPermission(permission, pid, uid) == PERMISSION_GRANTED) {
- return true;
- }
- }
- return false;
- }
-
private void enforceInternetPermission() {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.INTERNET,
@@ -3004,13 +3016,13 @@
}
private boolean checkNetworkStackPermission(int pid, int uid) {
- return checkAnyPermissionOf(pid, uid,
+ return checkAnyPermissionOf(mContext, pid, uid,
android.Manifest.permission.NETWORK_STACK,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
}
private boolean checkNetworkSignalStrengthWakeupPermission(int pid, int uid) {
- return checkAnyPermissionOf(pid, uid,
+ return checkAnyPermissionOf(mContext, pid, uid,
android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP,
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
android.Manifest.permission.NETWORK_SETTINGS);
@@ -5008,7 +5020,7 @@
}
private RequestInfoPerUidCounter getRequestCounter(NetworkRequestInfo nri) {
- return checkAnyPermissionOf(
+ return checkAnyPermissionOf(mContext,
nri.mPid, nri.mUid, NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
? mSystemNetworkRequestCounter : mNetworkRequestCounter;
}
@@ -5605,12 +5617,13 @@
handleConfigureAlwaysOnNetworks();
break;
}
- // Sent by KeepaliveTracker to process an app request on the state machine thread.
- case NetworkAgent.CMD_START_SOCKET_KEEPALIVE: {
+ // Sent by AutomaticOnOffKeepaliveTracker to process an app request on the
+ // handler thread.
+ case AutomaticOnOffKeepaliveTracker.CMD_REQUEST_START_KEEPALIVE: {
mKeepaliveTracker.handleStartKeepalive(msg);
break;
}
- case NetworkAgent.CMD_MONITOR_AUTOMATIC_KEEPALIVE: {
+ case AutomaticOnOffKeepaliveTracker.CMD_MONITOR_AUTOMATIC_KEEPALIVE: {
final AutomaticOnOffKeepalive ki =
mKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
if (null == ki) return; // The callback was unregistered before the alarm fired
@@ -7912,10 +7925,20 @@
return SdkLevel.isAtLeastU() ? (networkHandle + ":" + iface) : ("iface:" + iface);
}
+ private static boolean isWakeupMarkingSupported(NetworkCapabilities capabilities) {
+ if (capabilities.hasTransport(TRANSPORT_WIFI)) {
+ return true;
+ }
+ if (SdkLevel.isAtLeastU() && capabilities.hasTransport(TRANSPORT_CELLULAR)) {
+ return true;
+ }
+ return false;
+ }
+
private void wakeupModifyInterface(String iface, NetworkAgentInfo nai, boolean add) {
// Marks are only available on WiFi interfaces. Checking for
// marks on unsupported interfaces is harmless.
- if (!nai.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+ if (!isWakeupMarkingSupported(nai.networkCapabilities)) {
return;
}
@@ -8450,11 +8473,11 @@
return stableRanges;
}
- private void maybeCloseSockets(NetworkAgentInfo nai, UidRangeParcel[] ranges,
- int[] exemptUids) {
+ private void maybeCloseSockets(NetworkAgentInfo nai, Set<UidRange> ranges,
+ Set<Integer> exemptUids) {
if (nai.isVPN() && !nai.networkAgentConfig.allowBypass) {
try {
- mNetd.socketDestroy(ranges, exemptUids);
+ mDeps.destroyLiveTcpSockets(UidRange.toIntRanges(ranges), exemptUids);
} catch (Exception e) {
loge("Exception in socket destroy: ", e);
}
@@ -8462,16 +8485,16 @@
}
private void updateVpnUidRanges(boolean add, NetworkAgentInfo nai, Set<UidRange> uidRanges) {
- int[] exemptUids = new int[2];
+ final Set<Integer> exemptUids = new ArraySet<>();
// TODO: Excluding VPN_UID is necessary in order to not to kill the TCP connection used
// by PPTP. Fix this by making Vpn set the owner UID to VPN_UID instead of system when
// starting a legacy VPN, and remove VPN_UID here. (b/176542831)
- exemptUids[0] = VPN_UID;
- exemptUids[1] = nai.networkCapabilities.getOwnerUid();
+ exemptUids.add(VPN_UID);
+ exemptUids.add(nai.networkCapabilities.getOwnerUid());
UidRangeParcel[] ranges = toUidRangeStableParcels(uidRanges);
// Close sockets before modifying uid ranges so that RST packets can reach to the server.
- maybeCloseSockets(nai, ranges, exemptUids);
+ maybeCloseSockets(nai, uidRanges, exemptUids);
try {
if (add) {
mNetd.networkAddUidRangesParcel(new NativeUidRangeConfig(
@@ -8485,7 +8508,7 @@
" on netId " + nai.network.netId + ". " + e);
}
// Close sockets that established connection while requesting netd.
- maybeCloseSockets(nai, ranges, exemptUids);
+ maybeCloseSockets(nai, uidRanges, exemptUids);
}
private boolean isProxySetOnAnyDefaultNetwork() {
diff --git a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
index 7e288c6..ee8ab68 100644
--- a/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
+++ b/service/src/com/android/server/connectivity/AutomaticOnOffKeepaliveTracker.java
@@ -16,7 +16,6 @@
package com.android.server.connectivity;
-import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
import static android.net.SocketKeepalive.MIN_INTERVAL_SEC;
import static android.net.SocketKeepalive.SUCCESS_PAUSED;
@@ -40,7 +39,6 @@
import android.net.ISocketKeepaliveCallback;
import android.net.MarkMaskParcel;
import android.net.Network;
-import android.net.NetworkAgent;
import android.net.SocketKeepalive.InvalidSocketException;
import android.os.FileUtils;
import android.os.Handler;
@@ -52,6 +50,7 @@
import android.system.Os;
import android.system.OsConstants;
import android.system.StructTimeval;
+import android.util.LocalLog;
import android.util.Log;
import android.util.SparseArray;
@@ -93,6 +92,29 @@
private static final int ADJUST_TCP_POLLING_DELAY_MS = 2000;
private static final String AUTOMATIC_ON_OFF_KEEPALIVE_VERSION =
"automatic_on_off_keepalive_version";
+
+ // ConnectivityService parses message constants from itself and AutomaticOnOffKeepaliveTracker
+ // with MessageUtils for debugging purposes, and crashes if some messages have the same values.
+ private static final int BASE = 2000;
+ /**
+ * Sent by AutomaticOnOffKeepaliveTracker periodically (when relevant) to trigger monitor
+ * automatic keepalive request.
+ *
+ * NATT keepalives have an automatic mode where the system only sends keepalive packets when
+ * TCP sockets are open over a VPN. The system will check periodically for presence of
+ * such open sockets, and this message is what triggers the re-evaluation.
+ *
+ * obj = A Binder object associated with the keepalive.
+ */
+ public static final int CMD_MONITOR_AUTOMATIC_KEEPALIVE = BASE + 1;
+
+ /**
+ * Sent by AutomaticOnOffKeepaliveTracker to ConnectivityService to start a keepalive.
+ *
+ * obj = AutomaticKeepaliveInfo object
+ */
+ public static final int CMD_REQUEST_START_KEEPALIVE = BASE + 2;
+
/**
* States for {@code #AutomaticOnOffKeepalive}.
*
@@ -152,6 +174,10 @@
// TODO: Remove this when TCP polling design is replaced with callback.
private long mTestLowTcpPollingTimerUntilMs = 0;
+ private static final int MAX_EVENTS_LOGS = 40;
+ private final LocalLog mEventLog = new LocalLog(MAX_EVENTS_LOGS);
+
+ private final KeepaliveStatsTracker mKeepaliveStatsTracker = new KeepaliveStatsTracker();
/**
* Information about a managed keepalive.
*
@@ -198,7 +224,7 @@
throw new InvalidSocketException(ERROR_INVALID_SOCKET, e);
}
mAlarmListener = () -> mConnectivityServiceHandler.obtainMessage(
- NetworkAgent.CMD_MONITOR_AUTOMATIC_KEEPALIVE, mCallback.asBinder())
+ CMD_MONITOR_AUTOMATIC_KEEPALIVE, mCallback.asBinder())
.sendToTarget();
} else {
mAutomaticOnOffState = STATE_ALWAYS_ON;
@@ -230,6 +256,7 @@
@Override
public void binderDied() {
+ mEventLog.log("Binder died : " + mCallback);
mConnectivityServiceHandler.post(() -> cleanupAutoOnOffKeepalive(this));
}
@@ -332,6 +359,7 @@
* @param autoKi the keepalive to resume
*/
public void handleMaybeResumeKeepalive(@NonNull AutomaticOnOffKeepalive autoKi) {
+ mEventLog.log("Resume keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork());
// Might happen if the automatic keepalive was removed by the app just as the alarm fires.
if (!mAutomaticOnOffKeepalives.contains(autoKi)) return;
if (STATE_ALWAYS_ON == autoKi.mAutomaticOnOffState) {
@@ -377,6 +405,7 @@
* Handle stop all keepalives on the specific network.
*/
public void handleStopAllKeepalives(NetworkAgentInfo nai, int reason) {
+ mEventLog.log("Stop all keepalives on " + nai.network + " because " + reason);
mKeepaliveTracker.handleStopAllKeepalives(nai, reason);
final List<AutomaticOnOffKeepalive> matches =
CollectionUtils.filter(mAutomaticOnOffKeepalives, it -> it.mKi.getNai() == nai);
@@ -392,6 +421,8 @@
*/
public void handleStartKeepalive(Message message) {
final AutomaticOnOffKeepalive autoKi = (AutomaticOnOffKeepalive) message.obj;
+ mEventLog.log("Start keepalive " + autoKi.mCallback + " on " + autoKi.getNetwork());
+ mKeepaliveStatsTracker.onStartKeepalive();
mKeepaliveTracker.handleStartKeepalive(autoKi.mKi);
// Add automatic on/off request into list to track its life cycle.
@@ -409,10 +440,14 @@
}
private void handleResumeKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
+ mKeepaliveStatsTracker.onResumeKeepalive();
mKeepaliveTracker.handleStartKeepalive(ki);
+ mEventLog.log("Resumed successfully keepalive " + ki.mCallback + " on " + ki.mNai);
}
private void handlePauseKeepalive(@NonNull final KeepaliveTracker.KeepaliveInfo ki) {
+ mEventLog.log("Suspend keepalive " + ki.mCallback + " on " + ki.mNai);
+ mKeepaliveStatsTracker.onPauseKeepalive();
// TODO : mKT.handleStopKeepalive should take a KeepaliveInfo instead
mKeepaliveTracker.handleStopKeepalive(ki.getNai(), ki.getSlot(), SUCCESS_PAUSED);
}
@@ -421,6 +456,7 @@
* Handle stop keepalives on the specific network with given slot.
*/
public void handleStopKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi, int reason) {
+ mEventLog.log("Stop keepalive " + autoKi.mCallback + " because " + reason);
// Stop the keepalive unless it was suspended. This includes the case where it's managed
// but enabled, and the case where it's always on.
if (autoKi.mAutomaticOnOffState != STATE_SUSPENDED) {
@@ -435,6 +471,7 @@
private void cleanupAutoOnOffKeepalive(@NonNull final AutomaticOnOffKeepalive autoKi) {
ensureRunningOnHandlerThread();
+ mKeepaliveStatsTracker.onStopKeepalive(autoKi.mAutomaticOnOffState != STATE_SUSPENDED);
autoKi.close();
if (null != autoKi.mAlarmListener) mAlarmManager.cancel(autoKi.mAlarmListener);
@@ -466,9 +503,13 @@
try {
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
automaticOnOffKeepalives, underpinnedNetwork);
- mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
- // TODO : move ConnectivityService#encodeBool to a static lib.
- automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget();
+ mEventLog.log("Start natt keepalive " + cb + " on " + nai.network
+ + " " + srcAddrString + ":" + srcPort
+ + " → " + dstAddrString + ":" + dstPort
+ + " auto=" + autoKi
+ + " underpinned=" + underpinnedNetwork);
+ mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi)
+ .sendToTarget();
} catch (InvalidSocketException e) {
mKeepaliveTracker.notifyErrorCallback(cb, e.error);
}
@@ -496,9 +537,13 @@
try {
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
automaticOnOffKeepalives, underpinnedNetwork);
- mConnectivityServiceHandler.obtainMessage(NetworkAgent.CMD_START_SOCKET_KEEPALIVE,
- // TODO : move ConnectivityService#encodeBool to a static lib.
- automaticOnOffKeepalives ? 1 : 0, 0, autoKi).sendToTarget();
+ mEventLog.log("Start natt keepalive " + cb + " on " + nai.network
+ + " " + srcAddrString
+ + " → " + dstAddrString + ":" + dstPort
+ + " auto=" + autoKi
+ + " underpinned=" + underpinnedNetwork);
+ mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi)
+ .sendToTarget();
} catch (InvalidSocketException e) {
mKeepaliveTracker.notifyErrorCallback(cb, e.error);
}
@@ -526,7 +571,7 @@
final AutomaticOnOffKeepalive autoKi = new AutomaticOnOffKeepalive(ki,
false /* autoOnOff, tcp keepalives are never auto on/off */,
null /* underpinnedNetwork, tcp keepalives do not refer to this */);
- mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, autoKi)
+ mConnectivityServiceHandler.obtainMessage(CMD_REQUEST_START_KEEPALIVE, autoKi)
.sendToTarget();
} catch (InvalidSocketException e) {
mKeepaliveTracker.notifyErrorCallback(cb, e.error);
@@ -550,6 +595,11 @@
pw.println(autoKi.toString());
}
pw.decreaseIndent();
+
+ pw.println("Events (most recent first):");
+ pw.increaseIndent();
+ mEventLog.reverseDump(pw);
+ pw.decreaseIndent();
}
/**
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index 5d04632..fbe706c 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -237,9 +237,8 @@
/**
* Stop clatd.
*/
- public void stopClatd(String iface, String pfx96, String v4, String v6, int pid)
- throws IOException {
- native_stopClatd(iface, pfx96, v4, v6, pid);
+ public void stopClatd(int pid) throws IOException {
+ native_stopClatd(pid);
}
/**
@@ -843,9 +842,7 @@
Log.i(TAG, "Stopping clatd pid=" + mClatdTracker.pid + " on " + mClatdTracker.iface);
maybeStopBpf(mClatdTracker);
- mDeps.stopClatd(mClatdTracker.iface, mClatdTracker.pfx96.getHostAddress(),
- mClatdTracker.v4.getHostAddress(), mClatdTracker.v6.getHostAddress(),
- mClatdTracker.pid);
+ mDeps.stopClatd(mClatdTracker.pid);
untagSocket(mClatdTracker.cookie);
Log.i(TAG, "clatd on " + mClatdTracker.iface + " stopped");
@@ -944,7 +941,6 @@
private static native int native_startClatd(FileDescriptor tunfd, FileDescriptor readsock6,
FileDescriptor writesock6, String iface, String pfx96, String v4, String v6)
throws IOException;
- private static native void native_stopClatd(String iface, String pfx96, String v4, String v6,
- int pid) throws IOException;
+ private static native void native_stopClatd(int pid) throws IOException;
private static native long native_getSocketCookie(FileDescriptor sock) throws IOException;
}
diff --git a/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java b/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
new file mode 100644
index 0000000..290d201
--- /dev/null
+++ b/service/src/com/android/server/connectivity/KeepaliveStatsTracker.java
@@ -0,0 +1,191 @@
+/*
+ * 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.connectivity;
+
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.metrics.DailykeepaliveInfoReported;
+import com.android.metrics.DurationForNumOfKeepalive;
+import com.android.metrics.DurationPerNumOfKeepalive;
+
+import java.util.ArrayList;
+import java.util.List;
+
+// TODO(b/273451360): Also track KeepaliveLifetimeForCarrier and DailykeepaliveInfoReported
+/**
+ * Tracks carrier and duration metrics of automatic on/off keepalives.
+ *
+ * <p>This class follows AutomaticOnOffKeepaliveTracker closely and its on*Keepalive methods needs
+ * to be called in a timely manner to keep the metrics accurate. It is also not thread-safe and all
+ * public methods must be called by the same thread, namely the ConnectivityService handler thread.
+ */
+public class KeepaliveStatsTracker {
+ private static final String TAG = KeepaliveStatsTracker.class.getSimpleName();
+
+ private final Dependencies mDependencies;
+ // List of duration stats metric where the index is the number of concurrent keepalives.
+ // Each DurationForNumOfKeepalive message stores a registered duration and an active duration.
+ // Registered duration is the total time spent with mNumRegisteredKeepalive == index.
+ // Active duration is the total time spent with mNumActiveKeepalive == index.
+ private final List<DurationForNumOfKeepalive.Builder> mDurationPerNumOfKeepalive =
+ new ArrayList<>();
+
+ private int mNumRegisteredKeepalive = 0;
+ private int mNumActiveKeepalive = 0;
+
+ // A timestamp of the most recent time the duration metrics was updated.
+ private long mTimestampSinceLastUpdateDurations;
+
+ /** Dependency class */
+ @VisibleForTesting
+ public static class Dependencies {
+ // Returns a timestamp with the time base of SystemClock.uptimeMillis to keep durations
+ // relative to start time and avoid timezone change.
+ public long getUptimeMillis() {
+ return SystemClock.uptimeMillis();
+ }
+ }
+
+ public KeepaliveStatsTracker() {
+ this(new Dependencies());
+ }
+
+ @VisibleForTesting
+ public KeepaliveStatsTracker(Dependencies dependencies) {
+ mDependencies = dependencies;
+ mTimestampSinceLastUpdateDurations = mDependencies.getUptimeMillis();
+ }
+
+ /** Ensures the list of duration metrics is large enough for number of registered keepalives. */
+ private void ensureDurationPerNumOfKeepaliveSize() {
+ if (mNumActiveKeepalive < 0 || mNumRegisteredKeepalive < 0) {
+ throw new IllegalStateException(
+ "Number of active or registered keepalives is negative");
+ }
+ if (mNumActiveKeepalive > mNumRegisteredKeepalive) {
+ throw new IllegalStateException(
+ "Number of active keepalives greater than registered keepalives");
+ }
+
+ while (mDurationPerNumOfKeepalive.size() <= mNumRegisteredKeepalive) {
+ final DurationForNumOfKeepalive.Builder durationForNumOfKeepalive =
+ DurationForNumOfKeepalive.newBuilder();
+ durationForNumOfKeepalive.setNumOfKeepalive(mDurationPerNumOfKeepalive.size());
+ durationForNumOfKeepalive.setKeepaliveRegisteredDurationsMsec(0);
+ durationForNumOfKeepalive.setKeepaliveActiveDurationsMsec(0);
+
+ mDurationPerNumOfKeepalive.add(durationForNumOfKeepalive);
+ }
+ }
+
+ /**
+ * Updates the durations metrics to the given time. This should always be called before making a
+ * change to mNumRegisteredKeepalive or mNumActiveKeepalive to keep the duration metrics
+ * correct.
+ *
+ * @param timeNow a timestamp obtained using Dependencies.getUptimeMillis
+ */
+ private void updateDurationsPerNumOfKeepalive(long timeNow) {
+ if (mDurationPerNumOfKeepalive.size() < mNumRegisteredKeepalive) {
+ Log.e(TAG, "Unexpected jump in number of registered keepalive");
+ }
+ ensureDurationPerNumOfKeepaliveSize();
+
+ final int durationIncrease = (int) (timeNow - mTimestampSinceLastUpdateDurations);
+ final DurationForNumOfKeepalive.Builder durationForNumOfRegisteredKeepalive =
+ mDurationPerNumOfKeepalive.get(mNumRegisteredKeepalive);
+
+ durationForNumOfRegisteredKeepalive.setKeepaliveRegisteredDurationsMsec(
+ durationForNumOfRegisteredKeepalive.getKeepaliveRegisteredDurationsMsec()
+ + durationIncrease);
+
+ final DurationForNumOfKeepalive.Builder durationForNumOfActiveKeepalive =
+ mDurationPerNumOfKeepalive.get(mNumActiveKeepalive);
+
+ durationForNumOfActiveKeepalive.setKeepaliveActiveDurationsMsec(
+ durationForNumOfActiveKeepalive.getKeepaliveActiveDurationsMsec()
+ + durationIncrease);
+
+ mTimestampSinceLastUpdateDurations = timeNow;
+ }
+
+ /** Inform the KeepaliveStatsTracker a keepalive has just started and is active. */
+ public void onStartKeepalive() {
+ final long timeNow = mDependencies.getUptimeMillis();
+ updateDurationsPerNumOfKeepalive(timeNow);
+
+ mNumRegisteredKeepalive++;
+ mNumActiveKeepalive++;
+ }
+
+ /** Inform the KeepaliveStatsTracker a keepalive has just been paused. */
+ public void onPauseKeepalive() {
+ final long timeNow = mDependencies.getUptimeMillis();
+ updateDurationsPerNumOfKeepalive(timeNow);
+
+ mNumActiveKeepalive--;
+ }
+
+ /** Inform the KeepaliveStatsTracker a keepalive has just been resumed. */
+ public void onResumeKeepalive() {
+ final long timeNow = mDependencies.getUptimeMillis();
+ updateDurationsPerNumOfKeepalive(timeNow);
+
+ mNumActiveKeepalive++;
+ }
+
+ /** Inform the KeepaliveStatsTracker a keepalive has just been stopped. */
+ public void onStopKeepalive(boolean wasActive) {
+ final long timeNow = mDependencies.getUptimeMillis();
+ updateDurationsPerNumOfKeepalive(timeNow);
+
+ mNumRegisteredKeepalive--;
+ if (wasActive) mNumActiveKeepalive--;
+ }
+
+ /**
+ * Builds and returns DailykeepaliveInfoReported proto.
+ */
+ public DailykeepaliveInfoReported buildKeepaliveMetrics() {
+ final long timeNow = mDependencies.getUptimeMillis();
+ updateDurationsPerNumOfKeepalive(timeNow);
+
+ final DurationPerNumOfKeepalive.Builder durationPerNumOfKeepalive =
+ DurationPerNumOfKeepalive.newBuilder();
+
+ mDurationPerNumOfKeepalive.forEach(
+ durationForNumOfKeepalive ->
+ durationPerNumOfKeepalive.addDurationForNumOfKeepalive(
+ durationForNumOfKeepalive));
+
+ final DailykeepaliveInfoReported.Builder dailyKeepaliveInfoReported =
+ DailykeepaliveInfoReported.newBuilder();
+
+ // TODO(b/273451360): fill all the other values and write to ConnectivityStatsLog.
+ dailyKeepaliveInfoReported.setDurationPerNumOfKeepalive(durationPerNumOfKeepalive);
+
+ return dailyKeepaliveInfoReported.build();
+ }
+
+ /** Resets the stored metrics but maintains the state of keepalives */
+ public void resetMetrics() {
+ mDurationPerNumOfKeepalive.clear();
+ ensureDurationPerNumOfKeepaliveSize();
+ }
+}
diff --git a/service/src/com/android/server/connectivity/NetworkNotificationManager.java b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
index 45da0ea..cdc0aa9 100644
--- a/service/src/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/service/src/com/android/server/connectivity/NetworkNotificationManager.java
@@ -22,6 +22,7 @@
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import android.annotation.NonNull;
+import android.app.ActivityOptions;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -33,6 +34,8 @@
import android.net.NetworkSpecifier;
import android.net.TelephonyNetworkSpecifier;
import android.net.wifi.WifiInfo;
+import android.os.Build;
+import android.os.Bundle;
import android.os.UserHandle;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -45,6 +48,7 @@
import com.android.connectivity.resources.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.modules.utils.build.SdkLevel;
public class NetworkNotificationManager {
@@ -328,7 +332,26 @@
}
try {
- intent.send();
+ Bundle options = null;
+
+ if (SdkLevel.isAtLeastU() && intent.isActivity()) {
+ // Also check SDK_INT >= T separately, as the linter in some T-based branches does
+ // not recognize "isAtLeastU && something" as an SDK check for T+ APIs.
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ // Android U requires pending intent background start mode to be specified:
+ // See #background-activity-restrictions in
+ // https://developer.android.com/about/versions/14/behavior-changes-14
+ // But setPendingIntentBackgroundActivityStartMode is U+, and replaces
+ // setPendingIntentBackgroundActivityLaunchAllowed which is T+ but deprecated.
+ // Use setPendingIntentBackgroundActivityLaunchAllowed as the U+ version is not
+ // yet available in all branches.
+ final ActivityOptions activityOptions = ActivityOptions.makeBasic();
+ activityOptions.setPendingIntentBackgroundActivityLaunchAllowed(true);
+ options = activityOptions.toBundle();
+ }
+ }
+
+ intent.send(null, 0, null, null, null, null, options);
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Error sending dialog PendingIntent", e);
}
diff --git a/tests/cts/hostside/AndroidTest.xml b/tests/cts/hostside/AndroidTest.xml
index 7a73313..e83e36a 100644
--- a/tests/cts/hostside/AndroidTest.xml
+++ b/tests/cts/hostside/AndroidTest.xml
@@ -16,6 +16,7 @@
<configuration description="Config for CTS net host test cases">
<option name="test-suite-tag" value="cts" />
<option name="config-descriptor:metadata" key="component" value="networking" />
+ <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
<option name="config-descriptor:metadata" key="parameter" value="instant_app" />
<option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
<option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
diff --git a/tests/cts/hostside/app/AndroidManifest.xml b/tests/cts/hostside/app/AndroidManifest.xml
index 56d3cb5..ca3397b 100644
--- a/tests/cts/hostside/app/AndroidManifest.xml
+++ b/tests/cts/hostside/app/AndroidManifest.xml
@@ -34,7 +34,8 @@
<application android:requestLegacyExternalStorage="true">
<uses-library android:name="android.test.runner"/>
- <activity android:name=".MyActivity"/>
+ <activity android:name=".MyActivity"
+ android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"/>
<service android:name=".MyVpnService"
android:permission="android.permission.BIND_VPN_SERVICE"
android:exported="true">
diff --git a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
index b6902b5..624acd3 100755
--- a/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
+++ b/tests/cts/hostside/app/src/com/android/cts/net/hostside/VpnTest.java
@@ -154,7 +154,6 @@
import java.util.Random;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
@@ -809,26 +808,12 @@
mOldPrivateDnsSpecifier);
}
- // TODO: replace with CtsNetUtils.awaitPrivateDnsSetting in Q or above.
private void expectPrivateDnsHostname(final String hostname) throws Exception {
- final NetworkRequest request = new NetworkRequest.Builder()
- .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .build();
- final CountDownLatch latch = new CountDownLatch(1);
- final NetworkCallback callback = new NetworkCallback() {
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
- if (network.equals(mNetwork) &&
- Objects.equals(lp.getPrivateDnsServerName(), hostname)) {
- latch.countDown();
- }
- }
- };
-
- registerNetworkCallback(request, callback);
-
- assertTrue("Private DNS hostname was not " + hostname + " after " + TIMEOUT_MS + "ms",
- latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ for (Network network : mCtsNetUtils.getTestableNetworks()) {
+ // Wait for private DNS setting to propagate.
+ mCtsNetUtils.awaitPrivateDnsSetting("Test wait private DNS setting timeout",
+ network, hostname, false);
+ }
}
private void setAndVerifyPrivateDns(boolean strictMode) throws Exception {
@@ -1274,6 +1259,31 @@
}
@Test
+ public void testSocketClosed() throws Exception {
+ assumeTrue(supportedHardware());
+
+ final FileDescriptor localFd = openSocketFd(TEST_HOST, 80, TIMEOUT_MS);
+ final List<FileDescriptor> remoteFds = new ArrayList<>();
+
+ for (int i = 0; i < 30; i++) {
+ remoteFds.add(openSocketFdInOtherApp(TEST_HOST, 80, TIMEOUT_MS));
+ }
+
+ final String allowedApps = mRemoteSocketFactoryClient.getPackageName() + "," + mPackageName;
+ startVpn(new String[] {"192.0.2.2/32", "2001:db8:1:2::ffe/128"},
+ new String[] {"192.0.2.0/24", "2001:db8::/32"},
+ allowedApps, "", null, null /* underlyingNetworks */, false /* isAlwaysMetered */);
+
+ // Socket owned by VPN uid is not closed
+ assertSocketStillOpen(localFd, TEST_HOST);
+
+ // Sockets not owned by VPN uid are closed
+ for (final FileDescriptor remoteFd: remoteFds) {
+ assertSocketClosed(remoteFd, TEST_HOST);
+ }
+ }
+
+ @Test
public void testExcludedRoutes() throws Exception {
assumeTrue(supportedHardware());
assumeTrue(SdkLevel.isAtLeastT());
diff --git a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
index 603779d..3ca4775 100644
--- a/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
+++ b/tests/cts/hostside/src/com/android/cts/net/HostsideVpnTests.java
@@ -51,6 +51,10 @@
runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testAppDisallowed");
}
+ public void testSocketClosed() throws Exception {
+ runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testSocketClosed");
+ }
+
public void testGetConnectionOwnerUidSecurity() throws Exception {
runDeviceTests(TEST_PKG, TEST_PKG + ".VpnTest", "testGetConnectionOwnerUidSecurity");
}
diff --git a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
index 774176f..b380d02 100644
--- a/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/ConnectivityManagerTest.java
@@ -2112,7 +2112,12 @@
@AppModeFull(reason = "NETWORK_AIRPLANE_MODE permission can't be granted to instant apps")
@Test
public void testSetAirplaneMode() throws Exception{
- final boolean supportWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI);
+ // Starting from T, wifi supports airplane mode enhancement which may not disconnect wifi
+ // when airplane mode is on. The actual behavior that the device will have could only be
+ // checked with hidden wifi APIs(see Settings.Secure.WIFI_APM_STATE). Thus, stop verifying
+ // wifi on T+ device.
+ final boolean verifyWifi = mPackageManager.hasSystemFeature(FEATURE_WIFI)
+ && !SdkLevel.isAtLeastT();
final boolean supportTelephony = mPackageManager.hasSystemFeature(FEATURE_TELEPHONY);
// store the current state of airplane mode
final boolean isAirplaneModeEnabled = isAirplaneModeEnabled();
@@ -2123,7 +2128,7 @@
// Verify that networks are available as expected if wifi or cell is supported. Continue the
// test if none of them are supported since test should still able to verify the permission
// mechanism.
- if (supportWifi) {
+ if (verifyWifi) {
mCtsNetUtils.ensureWifiConnected();
registerCallbackAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb);
}
@@ -2147,7 +2152,7 @@
// Verify that the enabling airplane mode takes effect as expected to prevent flakiness
// caused by fast airplane mode switches. Ensure network lost before turning off
// airplane mode.
- if (supportWifi) waitForLost(wifiCb);
+ if (verifyWifi) waitForLost(wifiCb);
if (supportTelephony) waitForLost(telephonyCb);
// Verify we can disable Airplane Mode with correct permission:
@@ -2156,7 +2161,7 @@
// Verify that turning airplane mode off takes effect as expected.
// connectToCell only registers a request, it cannot / does not need to be called twice
mCtsNetUtils.ensureWifiConnected();
- if (supportWifi) waitForAvailable(wifiCb);
+ if (verifyWifi) waitForAvailable(wifiCb);
if (supportTelephony) waitForAvailable(telephonyCb);
} finally {
// Restore the previous state of airplane mode and permissions:
@@ -2176,15 +2181,12 @@
c -> c instanceof CallbackEntry.Available);
}
- private void waitForAvailable(
+ private void waitForTransport(
@NonNull final TestableNetworkCallback cb, final int expectedTransport) {
- cb.eventuallyExpect(
- CallbackEntry.AVAILABLE, NETWORK_CALLBACK_TIMEOUT_MS,
- entry -> {
- final NetworkCapabilities nc = mCm.getNetworkCapabilities(entry.getNetwork());
- return nc.hasTransport(expectedTransport);
- }
- );
+ cb.eventuallyExpect(CallbackEntry.NETWORK_CAPS_UPDATED,
+ NETWORK_CALLBACK_TIMEOUT_MS,
+ entry -> ((CallbackEntry.CapabilitiesChanged) entry).getCaps()
+ .hasTransport(expectedTransport));
}
private void waitForAvailable(
@@ -2409,6 +2411,7 @@
}
}
+ @AppModeFull(reason = "Cannot get WifiManager in instant app mode")
@Test
public void testBlockedStatusCallback() throws Exception {
// Cannot use @IgnoreUpTo(Build.VERSION_CODES.R) because this test also requires API 31
@@ -2555,15 +2558,14 @@
try {
tetherEventCallback.assumeWifiTetheringSupported(mContext);
- final TestableNetworkCallback wifiCb = new TestableNetworkCallback();
- mCtsNetUtils.ensureWifiConnected();
- registerCallbackAndWaitForAvailable(makeWifiNetworkRequest(), wifiCb);
+ tetherUtils.startWifiTethering(tetherEventCallback);
// Update setting to verify the behavior.
setAirplaneMode(true);
- // Verify wifi lost to make sure airplane mode takes effect. This could
+ // Verify softap lost to make sure airplane mode takes effect. This could
// prevent the race condition between airplane mode enabled and the followed
// up wifi tethering enabled.
- waitForLost(wifiCb);
+ tetherEventCallback.expectNoTetheringActive();
+
// start wifi tethering
tetherUtils.startWifiTethering(tetherEventCallback);
@@ -2672,7 +2674,8 @@
// Validate that an unmetered network is used over other networks.
waitForAvailable(defaultCallback, wifiNetwork);
- waitForAvailable(systemDefaultCallback, wifiNetwork);
+ systemDefaultCallback.eventuallyExpect(CallbackEntry.AVAILABLE,
+ NETWORK_CALLBACK_TIMEOUT_MS, cb -> wifiNetwork.equals(cb.getNetwork()));
// Validate that when setting unmetered to metered, unmetered is lost and replaced by
// the network with the TEST transport. Also wait for validation here, in case there
@@ -2684,11 +2687,14 @@
// callbacks may be received. Eventually, metered Wi-Fi should be the final available
// callback in any case therefore confirm its receipt before continuing to assure the
// system is in the expected state.
- waitForAvailable(systemDefaultCallback, TRANSPORT_WIFI);
+ waitForTransport(systemDefaultCallback, TRANSPORT_WIFI);
}, /* cleanup */ () -> {
- // Validate that removing the test network will fallback to the default network.
+ // Validate that removing the test network will fallback to the default network.
runWithShellPermissionIdentity(tnt::teardown);
- defaultCallback.expect(CallbackEntry.LOST, tnt, NETWORK_CALLBACK_TIMEOUT_MS);
+ // The other callbacks (LP or NC changes) would receive before LOST callback. Use
+ // eventuallyExpect to check callback for avoiding test flake.
+ defaultCallback.eventuallyExpect(CallbackEntry.LOST, NETWORK_CALLBACK_TIMEOUT_MS,
+ lost -> tnt.getNetwork().equals(lost.getNetwork()));
waitForAvailable(defaultCallback);
}, /* cleanup */ () -> {
setWifiMeteredStatusAndWait(ssid, oldMeteredValue, false /* waitForValidation */);
@@ -3395,15 +3401,15 @@
+ " uidFirewallRule=" + mCm.getUidFirewallRule(chain, Process.myUid()));
}
+ dstSock.receive(pkt);
+ assertArrayEquals(sendData, pkt.getData());
+
if (expectBlock) {
fail("Expect to be blocked by firewall but sending packet was not blocked:"
+ " chain=" + chain
+ " chainEnabled=" + mCm.getFirewallChainEnabled(chain)
+ " uidFirewallRule=" + mCm.getUidFirewallRule(chain, Process.myUid()));
}
-
- dstSock.receive(pkt);
- assertArrayEquals(sendData, pkt.getData());
}
private static final boolean EXPECT_PASS = false;
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index 67bdd17..732a42b 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -392,7 +392,15 @@
}
// Setting the carrier up / down relies on TUNSETCARRIER which was added in kernel version 5.0.
- private fun assumeChangingCarrierSupported() = assumeTrue(isKernelVersionAtLeast("5.0.0"))
+ private fun assumeChangingCarrierSupported() {
+ assumeTrue(isKernelVersionAtLeast("5.0.0"))
+ }
+
+ // Configuring a tap interface without carrier relies on IFF_NO_CARRIER
+ // which was added in kernel version 6.0.
+ private fun assumeCreateInterfaceWithoutCarrierSupported() {
+ assumeTrue(isKernelVersionAtLeast("6.0.0"))
+ }
private fun isAdbOverEthernet(): Boolean {
// If no ethernet interface is available, adb is not connected over ethernet.
@@ -417,7 +425,7 @@
}
// WARNING: setting hasCarrier to false requires kernel support. Call
- // assumeChangingCarrierSupported() at the top of your test.
+ // assumeCreateInterfaceWithoutCarrierSupported() at the top of your test.
private fun createInterface(hasCarrier: Boolean = true): EthernetTestInterface {
val iface = EthernetTestInterface(
context,
@@ -791,15 +799,13 @@
@Test
fun testNetworkRequest_forInterfaceWhileTogglingCarrier() {
+ assumeCreateInterfaceWithoutCarrierSupported()
assumeChangingCarrierSupported()
val iface = createInterface(false /* hasCarrier */)
val cb = requestNetwork(ETH_REQUEST)
- // TUNSETCARRIER races with the bring up code, so the network *can* become available despite
- // it being "created with no carrier".
- // TODO(b/249611919): re-enable assertion once kernel supports IFF_NO_CARRIER.
- // cb.assertNeverAvailable()
+ cb.assertNeverAvailable()
iface.setCarrierEnabled(true)
cb.expect<Available>()
diff --git a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
index 691ab99..17a9ca2 100644
--- a/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
+++ b/tests/cts/net/src/android/net/cts/MultinetworkApiTest.java
@@ -18,21 +18,18 @@
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import android.content.Context;
import android.content.ContentResolver;
+import android.content.Context;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkUtils;
import android.net.cts.util.CtsNetUtils;
import android.platform.test.annotations.AppModeFull;
-import android.provider.Settings;
import android.system.ErrnoException;
import android.system.OsConstants;
import android.test.AndroidTestCase;
-import java.util.ArrayList;
-
public class MultinetworkApiTest extends AndroidTestCase {
static {
@@ -75,26 +72,8 @@
super.tearDown();
}
- private Network[] getTestableNetworks() {
- final ArrayList<Network> testableNetworks = new ArrayList<Network>();
- for (Network network : mCM.getAllNetworks()) {
- final NetworkCapabilities nc = mCM.getNetworkCapabilities(network);
- if (nc != null
- && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
- testableNetworks.add(network);
- }
- }
-
- assertTrue(
- "This test requires that at least one network be connected. " +
- "Please ensure that the device is connected to a network.",
- testableNetworks.size() >= 1);
- return testableNetworks.toArray(new Network[0]);
- }
-
public void testGetaddrinfo() throws ErrnoException {
- for (Network network : getTestableNetworks()) {
+ for (Network network : mCtsNetUtils.getTestableNetworks()) {
int errno = runGetaddrinfoCheck(network.getNetworkHandle());
if (errno != 0) {
throw new ErrnoException(
@@ -109,7 +88,7 @@
assertNull(mCM.getProcessDefaultNetwork());
assertEquals(0, NetworkUtils.getBoundNetworkForProcess());
- for (Network network : getTestableNetworks()) {
+ for (Network network : mCtsNetUtils.getTestableNetworks()) {
mCM.setProcessDefaultNetwork(null);
assertNull(mCM.getProcessDefaultNetwork());
@@ -128,7 +107,7 @@
mCM.setProcessDefaultNetwork(null);
}
- for (Network network : getTestableNetworks()) {
+ for (Network network : mCtsNetUtils.getTestableNetworks()) {
NetworkUtils.bindProcessToNetwork(0);
assertNull(mCM.getBoundNetworkForProcess());
@@ -148,7 +127,7 @@
@AppModeFull(reason = "CHANGE_NETWORK_STATE permission can't be granted to instant apps")
public void testSetsocknetwork() throws ErrnoException {
- for (Network network : getTestableNetworks()) {
+ for (Network network : mCtsNetUtils.getTestableNetworks()) {
int errno = runSetsocknetwork(network.getNetworkHandle());
if (errno != 0) {
throw new ErrnoException(
@@ -158,7 +137,7 @@
}
public void testNativeDatagramTransmission() throws ErrnoException {
- for (Network network : getTestableNetworks()) {
+ for (Network network : mCtsNetUtils.getTestableNetworks()) {
int errno = runDatagramCheck(network.getNetworkHandle());
if (errno != 0) {
throw new ErrnoException(
@@ -181,7 +160,7 @@
public void testNetworkHandle() {
// Test Network -> NetworkHandle -> Network results in the same Network.
- for (Network network : getTestableNetworks()) {
+ for (Network network : mCtsNetUtils.getTestableNetworks()) {
long networkHandle = network.getNetworkHandle();
Network newNetwork = Network.fromNetworkHandle(networkHandle);
assertEquals(newNetwork, network);
@@ -203,7 +182,7 @@
}
public void testResNApi() throws Exception {
- final Network[] testNetworks = getTestableNetworks();
+ final Network[] testNetworks = mCtsNetUtils.getTestableNetworks();
for (Network network : testNetworks) {
// Throws AssertionError directly in jni function if test fail.
@@ -229,7 +208,7 @@
// b/144521720
try {
mCtsNetUtils.setPrivateDnsStrictMode(GOOGLE_PRIVATE_DNS_SERVER);
- for (Network network : getTestableNetworks()) {
+ for (Network network : mCtsNetUtils.getTestableNetworks()) {
// Wait for private DNS setting to propagate.
mCtsNetUtils.awaitPrivateDnsSetting("NxDomain test wait private DNS setting timeout",
network, GOOGLE_PRIVATE_DNS_SERVER, true);
diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
index 469fdba..db7f38c 100644
--- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt
@@ -403,6 +403,13 @@
// Wait until the link-local address can be used. Address flags are not available without
// elevated permissions, so check that bindSocket works.
PollingCheck.check("No usable v6 address on interface after $TIMEOUT_MS ms", TIMEOUT_MS) {
+ // To avoid race condition between socket connection succeeding and interface returning
+ // a non-empty address list. Verify that interface returns a non-empty list, before
+ // trying the socket connection.
+ if (NetworkInterface.getByName(ifaceName).interfaceAddresses.isEmpty()) {
+ return@check false
+ }
+
val sock = Os.socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP)
tryTest {
network.bindSocket(sock)
diff --git a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
index f0c87673..4854901 100644
--- a/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
+++ b/tests/cts/net/src/android/net/cts/PacProxyManagerTest.java
@@ -23,12 +23,14 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.PacProxyManager;
@@ -150,6 +152,9 @@
@AppModeFull(reason = "Instant apps can't bind sockets to localhost for a test proxy server")
@Test
public void testSetCurrentProxyScriptUrl() throws Exception {
+ // Devices without WebView/JavaScript cannot support PAC proxies
+ assumeTrue(mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW));
+
// Register a PacProxyInstalledListener
final TestPacProxyInstalledListener listener = new TestPacProxyInstalledListener();
final Executor executor = (Runnable r) -> r.run();
diff --git a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
index cbe54f8..1a780a7 100644
--- a/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
+++ b/tests/cts/net/src/android/net/cts/SSLCertificateSocketFactoryTest.java
@@ -66,7 +66,6 @@
InetAddress[] addresses;
try {
addresses = InetAddress.getAllByName(TEST_HOST);
- mTestHostAddress = addresses[0];
} catch (UnknownHostException uhe) {
throw new AssertionError(
"Unable to test SSLCertificateSocketFactory: cannot resolve " + TEST_HOST, uhe);
@@ -76,10 +75,11 @@
.map(addr -> new InetSocketAddress(addr, HTTPS_PORT))
.collect(Collectors.toList());
- // Find the local IP address which will be used to connect to TEST_HOST.
+ // Find the local and remote IP addresses which will be used to connect to TEST_HOST.
try {
Socket testSocket = new Socket(TEST_HOST, HTTPS_PORT);
mLocalAddress = testSocket.getLocalAddress();
+ mTestHostAddress = testSocket.getInetAddress();
testSocket.close();
} catch (IOException ioe) {
throw new AssertionError(""
diff --git a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
index d817630..0c4f794 100644
--- a/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
+++ b/tests/cts/net/util/java/android/net/cts/util/CtsNetUtils.java
@@ -57,6 +57,8 @@
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.Nullable;
+
import com.android.compatibility.common.util.PollingCheck;
import com.android.compatibility.common.util.ShellIdentityUtils;
import com.android.compatibility.common.util.SystemUtil;
@@ -68,6 +70,8 @@
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
+import java.util.ArrayList;
+import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -506,17 +510,18 @@
* @throws InterruptedException If the thread is interrupted.
*/
public void awaitPrivateDnsSetting(@NonNull String msg, @NonNull Network network,
- @NonNull String server, boolean requiresValidatedServer) throws InterruptedException {
+ @Nullable String server, boolean requiresValidatedServer) throws InterruptedException {
final CountDownLatch latch = new CountDownLatch(1);
final NetworkRequest request = new NetworkRequest.Builder().clearCapabilities().build();
- NetworkCallback callback = new NetworkCallback() {
+ final NetworkCallback callback = new NetworkCallback() {
@Override
public void onLinkPropertiesChanged(Network n, LinkProperties lp) {
Log.i(TAG, "Link properties of network " + n + " changed to " + lp);
if (requiresValidatedServer && lp.getValidatedPrivateDnsServers().isEmpty()) {
return;
}
- if (network.equals(n) && server.equals(lp.getPrivateDnsServerName())) {
+ Log.i(TAG, "Set private DNS server to " + server);
+ if (network.equals(n) && Objects.equals(server, lp.getPrivateDnsServerName())) {
latch.countDown();
}
}
@@ -539,6 +544,27 @@
}
/**
+ * Get all testable Networks with internet capability.
+ */
+ public Network[] getTestableNetworks() {
+ final ArrayList<Network> testableNetworks = new ArrayList<Network>();
+ for (Network network : mCm.getAllNetworks()) {
+ final NetworkCapabilities nc = mCm.getNetworkCapabilities(network);
+ if (nc != null
+ && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ && nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) {
+ testableNetworks.add(network);
+ }
+ }
+
+ assertTrue("This test requires that at least one public Internet-providing"
+ + " network be connected. Please ensure that the device is connected to"
+ + " a network.",
+ testableNetworks.size() >= 1);
+ return testableNetworks.toArray(new Network[0]);
+ }
+
+ /**
* Receiver that captures the last connectivity change's network type and state. Recognizes
* both {@code CONNECTIVITY_ACTION} and {@code NETWORK_CALLBACK_ACTION} intents.
*/
diff --git a/tests/unit/Android.bp b/tests/unit/Android.bp
index 36b3356..8b286a0 100644
--- a/tests/unit/Android.bp
+++ b/tests/unit/Android.bp
@@ -26,7 +26,6 @@
"libandroid_net_frameworktests_util_jni",
"libbase",
"libbinder",
- "libbpf_bcc",
"libc++",
"libcrypto",
"libcutils",
diff --git a/tests/unit/java/android/net/NetworkStatsAccessTest.java b/tests/unit/java/android/net/NetworkStatsAccessTest.java
index a74056b..8b86211 100644
--- a/tests/unit/java/android/net/NetworkStatsAccessTest.java
+++ b/tests/unit/java/android/net/NetworkStatsAccessTest.java
@@ -78,6 +78,7 @@
setHasAppOpsPermission(AppOpsManager.MODE_DEFAULT, false);
setHasReadHistoryPermission(false);
setHasNetworkStackPermission(false);
+ setHasMainlineNetworkStackPermission(false);
}
@After
@@ -154,6 +155,10 @@
setHasNetworkStackPermission(false);
assertEquals(NetworkStatsAccess.Level.DEFAULT,
NetworkStatsAccess.checkAccessLevel(mContext, TEST_PID, TEST_UID, TEST_PKG));
+
+ setHasMainlineNetworkStackPermission(true);
+ assertEquals(NetworkStatsAccess.Level.DEVICE,
+ NetworkStatsAccess.checkAccessLevel(mContext, TEST_PID, TEST_UID, TEST_PKG));
}
private void setHasCarrierPrivileges(boolean hasPrivileges) {
@@ -189,4 +194,10 @@
TEST_PID, TEST_UID)).thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED
: PackageManager.PERMISSION_DENIED);
}
+
+ private void setHasMainlineNetworkStackPermission(boolean hasPermission) {
+ when(mContext.checkPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK,
+ TEST_PID, TEST_UID)).thenReturn(hasPermission ? PackageManager.PERMISSION_GRANTED
+ : PackageManager.PERMISSION_DENIED);
+ }
}
diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
index 2cf8896..058c204 100755
--- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java
@@ -502,7 +502,7 @@
// complete before callbacks are verified.
private static final int TEST_REQUEST_TIMEOUT_MS = 150;
- private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 1000;
+ private static final int UNREASONABLY_LONG_ALARM_WAIT_MS = 2_000;
private static final long TIMESTAMP = 1234L;
@@ -1853,7 +1853,7 @@
final Context mockResContext = mock(Context.class);
doReturn(mResources).when(mockResContext).getResources();
ConnectivityResources.setResourcesContextForTest(mockResContext);
- mDeps = new ConnectivityServiceDependencies(mockResContext);
+ mDeps = spy(new ConnectivityServiceDependencies(mockResContext));
mAutoOnOffKeepaliveDependencies =
new AutomaticOnOffKeepaliveTrackerDependencies(mServiceContext);
mService = new ConnectivityService(mServiceContext,
@@ -1912,7 +1912,8 @@
.getBoolean(R.bool.config_cellular_radio_timesharing_capable);
}
- class ConnectivityServiceDependencies extends ConnectivityService.Dependencies {
+ // ConnectivityServiceDependencies is public to use Mockito.spy
+ public class ConnectivityServiceDependencies extends ConnectivityService.Dependencies {
final ConnectivityResources mConnRes;
ConnectivityServiceDependencies(final Context mockResContext) {
@@ -2148,6 +2149,12 @@
}
}
}
+
+ @Override
+ public void destroyLiveTcpSockets(final Set<Range<Integer>> ranges,
+ final Set<Integer> exemptUids) {
+ // This function is empty since the invocation of this method is verified by mocks
+ }
}
private class AutomaticOnOffKeepaliveTrackerDependencies
@@ -3369,8 +3376,10 @@
// This test would be flaky with the default 120ms timer: that is short enough that
// lingered networks are torn down before assertions can be run. We don't want to mock the
// lingering timer to keep the WakeupMessage logic realistic: this has already proven useful
- // in detecting races.
- mService.mLingerDelayMs = 300;
+ // in detecting races. Furthermore, sometimes the test is running while Phenotype is running
+ // so hot that the test doesn't get the CPU for multiple hundreds of milliseconds, so this
+ // needs to be suitably long.
+ mService.mLingerDelayMs = 2_000;
NetworkRequest request = new NetworkRequest.Builder()
.clearCapabilities().addCapability(NET_CAPABILITY_NOT_METERED)
@@ -12469,12 +12478,11 @@
private void assertVpnUidRangesUpdated(boolean add, Set<UidRange> vpnRanges, int exemptUid)
throws Exception {
- InOrder inOrder = inOrder(mMockNetd);
- ArgumentCaptor<int[]> exemptUidCaptor = ArgumentCaptor.forClass(int[].class);
+ InOrder inOrder = inOrder(mMockNetd, mDeps);
+ final Set<Integer> exemptUidSet = new ArraySet<>(List.of(exemptUid, Process.VPN_UID));
- inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
- exemptUidCaptor.capture());
- assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
+ inOrder.verify(mDeps).destroyLiveTcpSockets(UidRange.toIntRanges(vpnRanges),
+ exemptUidSet);
if (add) {
inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(
@@ -12486,9 +12494,8 @@
toUidRangeStableParcels(vpnRanges), PREFERENCE_ORDER_VPN));
}
- inOrder.verify(mMockNetd, times(1)).socketDestroy(eq(toUidRangeStableParcels(vpnRanges)),
- exemptUidCaptor.capture());
- assertContainsExactly(exemptUidCaptor.getValue(), Process.VPN_UID, exemptUid);
+ inOrder.verify(mDeps).destroyLiveTcpSockets(UidRange.toIntRanges(vpnRanges),
+ exemptUidSet);
}
@Test
diff --git a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
index 696eff4..3eb1b26 100644
--- a/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/AutomaticOnOffKeepaliveTrackerTest.java
@@ -47,7 +47,6 @@
import android.net.MarkMaskParcel;
import android.net.NattKeepalivePacketData;
import android.net.Network;
-import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.os.Binder;
@@ -268,11 +267,11 @@
@Override
public void handleMessage(@NonNull final Message msg) {
switch (msg.what) {
- case NetworkAgent.CMD_START_SOCKET_KEEPALIVE:
- Log.d(TAG, "Test handler received CMD_START_SOCKET_KEEPALIVE : " + msg);
+ case AutomaticOnOffKeepaliveTracker.CMD_REQUEST_START_KEEPALIVE:
+ Log.d(TAG, "Test handler received CMD_REQUEST_START_KEEPALIVE : " + msg);
mAOOKeepaliveTracker.handleStartKeepalive(msg);
break;
- case NetworkAgent.CMD_MONITOR_AUTOMATIC_KEEPALIVE:
+ case AutomaticOnOffKeepaliveTracker.CMD_MONITOR_AUTOMATIC_KEEPALIVE:
Log.d(TAG, "Test handler received CMD_MONITOR_AUTOMATIC_KEEPALIVE : " + msg);
mLastAutoKi = mAOOKeepaliveTracker.getKeepaliveForBinder((IBinder) msg.obj);
break;
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index b651c33..4158663 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -313,8 +313,7 @@
* Stop clatd.
*/
@Override
- public void stopClatd(@NonNull String iface, @NonNull String pfx96, @NonNull String v4,
- @NonNull String v6, int pid) throws IOException {
+ public void stopClatd(int pid) throws IOException {
if (pid == -1) {
fail("unsupported arg: " + pid);
}
@@ -479,8 +478,7 @@
eq((short) PRIO_CLAT), eq((short) ETH_P_IP));
inOrder.verify(mEgressMap).deleteEntry(eq(EGRESS_KEY));
inOrder.verify(mIngressMap).deleteEntry(eq(INGRESS_KEY));
- inOrder.verify(mDeps).stopClatd(eq(BASE_IFACE), eq(NAT64_PREFIX_STRING),
- eq(XLAT_LOCAL_IPV4ADDR_STRING), eq(XLAT_LOCAL_IPV6ADDR_STRING), eq(CLATD_PID));
+ inOrder.verify(mDeps).stopClatd(eq(CLATD_PID));
inOrder.verify(mCookieTagMap).deleteEntry(eq(COOKIE_TAG_KEY));
assertNull(coordinator.getClatdTrackerForTesting());
inOrder.verifyNoMoreInteractions();
diff --git a/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java b/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java
new file mode 100644
index 0000000..d262255
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/KeepaliveStatsTrackerTest.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2022 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.connectivity;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.doReturn;
+
+import android.os.Build;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.metrics.DailykeepaliveInfoReported;
+import com.android.metrics.DurationForNumOfKeepalive;
+import com.android.metrics.DurationPerNumOfKeepalive;
+import com.android.testutils.DevSdkIgnoreRule;
+import com.android.testutils.DevSdkIgnoreRunner;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(DevSdkIgnoreRunner.class)
+@SmallTest
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU)
+public class KeepaliveStatsTrackerTest {
+ private static final int TEST_UID = 1234;
+
+ private KeepaliveStatsTracker mKeepaliveStatsTracker;
+ @Mock KeepaliveStatsTracker.Dependencies mDependencies;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ setUptimeMillis(0);
+ mKeepaliveStatsTracker = new KeepaliveStatsTracker(mDependencies);
+ }
+
+ private void setUptimeMillis(long time) {
+ doReturn(time).when(mDependencies).getUptimeMillis();
+ }
+
+ /**
+ * Asserts that a DurationPerNumOfKeepalive contains expected values
+ *
+ * @param expectRegisteredDurations integer array where the index is the number of concurrent
+ * keepalives and the value is the expected duration of time that the tracker is in a state
+ * with the given number of keepalives registered.
+ * @param expectActiveDurations integer array where the index is the number of concurrent
+ * keepalives and the value is the expected duration of time that the tracker is in a state
+ * with the given number of keepalives active.
+ * @param resultDurationsPerNumOfKeepalive the DurationPerNumOfKeepalive message to assert.
+ */
+ private void assertDurationMetrics(
+ int[] expectRegisteredDurations,
+ int[] expectActiveDurations,
+ DurationPerNumOfKeepalive resultDurationsPerNumOfKeepalive) {
+ final int maxNumOfKeepalive = expectRegisteredDurations.length;
+ assertEquals(maxNumOfKeepalive, expectActiveDurations.length);
+ assertEquals(
+ maxNumOfKeepalive,
+ resultDurationsPerNumOfKeepalive.getDurationForNumOfKeepaliveCount());
+ for (int numOfKeepalive = 0; numOfKeepalive < maxNumOfKeepalive; numOfKeepalive++) {
+ final DurationForNumOfKeepalive resultDurations =
+ resultDurationsPerNumOfKeepalive.getDurationForNumOfKeepalive(numOfKeepalive);
+
+ assertEquals(numOfKeepalive, resultDurations.getNumOfKeepalive());
+ assertEquals(
+ expectRegisteredDurations[numOfKeepalive],
+ resultDurations.getKeepaliveRegisteredDurationsMsec());
+ assertEquals(
+ expectActiveDurations[numOfKeepalive],
+ resultDurations.getKeepaliveActiveDurationsMsec());
+ }
+ }
+
+ private void assertDailyKeepaliveInfoReported(
+ DailykeepaliveInfoReported dailyKeepaliveInfoReported,
+ int[] expectRegisteredDurations,
+ int[] expectActiveDurations) {
+ // TODO(b/273451360) Assert these values when they are filled.
+ assertFalse(dailyKeepaliveInfoReported.hasKeepaliveLifetimePerCarrier());
+ assertFalse(dailyKeepaliveInfoReported.hasKeepaliveRequests());
+ assertFalse(dailyKeepaliveInfoReported.hasAutomaticKeepaliveRequests());
+ assertFalse(dailyKeepaliveInfoReported.hasDistinctUserCount());
+ assertTrue(dailyKeepaliveInfoReported.getUidList().isEmpty());
+
+ final DurationPerNumOfKeepalive resultDurations =
+ dailyKeepaliveInfoReported.getDurationPerNumOfKeepalive();
+ assertDurationMetrics(expectRegisteredDurations, expectActiveDurations, resultDurations);
+ }
+
+ @Test
+ public void testNoKeepalive() {
+ final int writeTime = 5000;
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ // Expect that the durations are all in numOfKeepalive = 0.
+ final int[] expectRegisteredDurations = new int[] {writeTime};
+ final int[] expectActiveDurations = new int[] {writeTime};
+
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+ }
+
+ /*
+ * Diagram of test (not to scale):
+ * Key: S - Start/Stop, P - Pause, R - Resume, W - Write
+ *
+ * Keepalive S W
+ * Timeline |------------------------------|
+ */
+ @Test
+ public void testOneKeepalive_startOnly() {
+ final int startTime = 1000;
+ final int writeTime = 5000;
+
+ setUptimeMillis(startTime);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ // The keepalive is never stopped, expect the duration for numberOfKeepalive of 1 to range
+ // from startTime to writeTime.
+ final int[] expectRegisteredDurations = new int[] {startTime, writeTime - startTime};
+ final int[] expectActiveDurations = new int[] {startTime, writeTime - startTime};
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+ }
+
+ /*
+ * Diagram of test (not to scale):
+ * Key: S - Start/Stop, P - Pause, R - Resume, W - Write
+ *
+ * Keepalive S P W
+ * Timeline |------------------------------|
+ */
+ @Test
+ public void testOneKeepalive_paused() {
+ final int startTime = 1000;
+ final int pauseTime = 2030;
+ final int writeTime = 5000;
+
+ setUptimeMillis(startTime);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ setUptimeMillis(pauseTime);
+ mKeepaliveStatsTracker.onPauseKeepalive();
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ // The keepalive is paused but not stopped, expect the registered duration for
+ // numberOfKeepalive of 1 to still range from startTime to writeTime while the active
+ // duration stops at pauseTime.
+ final int[] expectRegisteredDurations = new int[] {startTime, writeTime - startTime};
+ final int[] expectActiveDurations =
+ new int[] {startTime + (writeTime - pauseTime), pauseTime - startTime};
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+ }
+
+ /*
+ * Diagram of test (not to scale):
+ * Key: S - Start/Stop, P - Pause, R - Resume, W - Write
+ *
+ * Keepalive S P R W
+ * Timeline |------------------------------|
+ */
+ @Test
+ public void testOneKeepalive_resumed() {
+ final int startTime = 1000;
+ final int pauseTime = 2030;
+ final int resumeTime = 3450;
+ final int writeTime = 5000;
+
+ setUptimeMillis(startTime);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ setUptimeMillis(pauseTime);
+ mKeepaliveStatsTracker.onPauseKeepalive();
+
+ setUptimeMillis(resumeTime);
+ mKeepaliveStatsTracker.onResumeKeepalive();
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ // The keepalive is paused and resumed but not stopped, expect the registered duration for
+ // numberOfKeepalive of 1 to still range from startTime to writeTime while the active
+ // duration stops at pauseTime but resumes at resumeTime and stops at writeTime.
+ final int[] expectRegisteredDurations = new int[] {startTime, writeTime - startTime};
+ final int[] expectActiveDurations =
+ new int[] {
+ startTime + (resumeTime - pauseTime),
+ (pauseTime - startTime) + (writeTime - resumeTime)
+ };
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+ }
+
+ /*
+ * Diagram of test (not to scale):
+ * Key: S - Start/Stop, P - Pause, R - Resume, W - Write
+ *
+ * Keepalive S P R S W
+ * Timeline |------------------------------|
+ */
+ @Test
+ public void testOneKeepalive_stopped() {
+ final int startTime = 1000;
+ final int pauseTime = 2930;
+ final int resumeTime = 3452;
+ final int stopTime = 4157;
+ final int writeTime = 5000;
+
+ setUptimeMillis(startTime);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ setUptimeMillis(pauseTime);
+ mKeepaliveStatsTracker.onPauseKeepalive();
+
+ setUptimeMillis(resumeTime);
+ mKeepaliveStatsTracker.onResumeKeepalive();
+
+ setUptimeMillis(stopTime);
+ mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ true);
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ // The keepalive is now stopped, expect the registered duration for numberOfKeepalive of 1
+ // to now range from startTime to stopTime while the active duration stops at pauseTime but
+ // resumes at resumeTime and stops again at stopTime.
+ final int[] expectRegisteredDurations =
+ new int[] {startTime + (writeTime - stopTime), stopTime - startTime};
+ final int[] expectActiveDurations =
+ new int[] {
+ startTime + (resumeTime - pauseTime) + (writeTime - stopTime),
+ (pauseTime - startTime) + (stopTime - resumeTime)
+ };
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+ }
+
+ /*
+ * Diagram of test (not to scale):
+ * Key: S - Start/Stop, P - Pause, R - Resume, W - Write
+ *
+ * Keepalive S P S W
+ * Timeline |------------------------------|
+ */
+ @Test
+ public void testOneKeepalive_pausedStopped() {
+ final int startTime = 1000;
+ final int pauseTime = 2930;
+ final int stopTime = 4157;
+ final int writeTime = 5000;
+
+ setUptimeMillis(startTime);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ setUptimeMillis(pauseTime);
+ mKeepaliveStatsTracker.onPauseKeepalive();
+
+ setUptimeMillis(stopTime);
+ mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ false);
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ // The keepalive is stopped while paused, expect the registered duration for
+ // numberOfKeepalive of 1 to range from startTime to stopTime while the active duration
+ // simply stops at pauseTime.
+ final int[] expectRegisteredDurations =
+ new int[] {startTime + (writeTime - stopTime), stopTime - startTime};
+ final int[] expectActiveDurations =
+ new int[] {startTime + (writeTime - pauseTime), (pauseTime - startTime)};
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+ }
+
+ /*
+ * Diagram of test (not to scale):
+ * Key: S - Start/Stop, P - Pause, R - Resume, W - Write
+ *
+ * Keepalive S P R P R P R S W
+ * Timeline |------------------------------|
+ */
+ @Test
+ public void testOneKeepalive_multiplePauses() {
+ final int startTime = 1000;
+ // Alternating timestamps of pause and resume
+ final int[] pauseResumeTimes = new int[] {1200, 1400, 1700, 2000, 2400, 2800};
+ final int stopTime = 4000;
+ final int writeTime = 5000;
+
+ setUptimeMillis(startTime);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ for (int i = 0; i < pauseResumeTimes.length; i++) {
+ setUptimeMillis(pauseResumeTimes[i]);
+ if (i % 2 == 0) {
+ mKeepaliveStatsTracker.onPauseKeepalive();
+ } else {
+ mKeepaliveStatsTracker.onResumeKeepalive();
+ }
+ }
+
+ setUptimeMillis(stopTime);
+ mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ true);
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ final int[] expectRegisteredDurations =
+ new int[] {startTime + (writeTime - stopTime), stopTime - startTime};
+ final int[] expectActiveDurations =
+ new int[] {
+ startTime + /* sum of (Resume - Pause) */ (900) + (writeTime - stopTime),
+ (pauseResumeTimes[0] - startTime)
+ + /* sum of (Pause - Resume) */ (700)
+ + (stopTime - pauseResumeTimes[5])
+ };
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+ }
+
+ /*
+ * Diagram of test (not to scale):
+ * Key: S - Start/Stop, P - Pause, R - Resume, W - Write
+ *
+ * Keepalive1 S1 P1 R1 S1 W
+ * Keepalive2 S2 P2 R2 W
+ * Timeline |------------------------------|
+ */
+ @Test
+ public void testTwoKeepalives() {
+ // The suffix 1/2 indicates which keepalive it is referring to.
+ final int startTime1 = 1000;
+ final int pauseTime1 = 1500;
+ final int startTime2 = 2000;
+ final int resumeTime1 = 2500;
+ final int pauseTime2 = 3000;
+ final int resumeTime2 = 3500;
+ final int stopTime1 = 4157;
+ final int writeTime = 5000;
+
+ setUptimeMillis(startTime1);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ setUptimeMillis(pauseTime1);
+ mKeepaliveStatsTracker.onPauseKeepalive();
+
+ setUptimeMillis(startTime2);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ setUptimeMillis(resumeTime1);
+ mKeepaliveStatsTracker.onResumeKeepalive();
+
+ setUptimeMillis(pauseTime2);
+ mKeepaliveStatsTracker.onPauseKeepalive();
+
+ setUptimeMillis(resumeTime2);
+ mKeepaliveStatsTracker.onResumeKeepalive();
+
+ setUptimeMillis(stopTime1);
+ mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ true);
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ // With two keepalives, the number of concurrent keepalives can vary from 0-2 depending on
+ // both keepalive states.
+ final int[] expectRegisteredDurations =
+ new int[] {
+ startTime1,
+ // 1 registered keepalive before keepalive2 starts and after keepalive1 stops.
+ (startTime2 - startTime1) + (writeTime - stopTime1),
+ // 2 registered keepalives between keepalive2 start and keepalive1 stop.
+ stopTime1 - startTime2
+ };
+
+ final int[] expectActiveDurations =
+ new int[] {
+ // 0 active keepalives when keepalive1 is paused before keepalive2 starts.
+ startTime1 + (startTime2 - pauseTime1),
+ // 1 active keepalive before keepalive1 is paused.
+ (pauseTime1 - startTime1)
+ // before keepalive1 is resumed and after keepalive2 starts.
+ + (resumeTime1 - startTime2)
+ // during keepalive2 is paused since keepalive1 has been resumed.
+ + (resumeTime2 - pauseTime2)
+ // after keepalive1 stops since keepalive2 has been resumed.
+ + (writeTime - stopTime1),
+ // 2 active keepalives before keepalive2 is paused and before keepalive1 stops.
+ (pauseTime2 - resumeTime1) + (stopTime1 - resumeTime2)
+ };
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+ }
+
+ /*
+ * Diagram of test (not to scale):
+ * Key: S - Start/Stop, P - Pause, R - Resume, W - Write
+ *
+ * Keepalive S W(reset+W) S W
+ * Timeline |------------------------------|
+ */
+ @Test
+ public void testResetMetrics() {
+ final int startTime = 1000;
+ final int writeTime = 5000;
+ final int stopTime = 7000;
+ final int writeTime2 = 10000;
+
+ setUptimeMillis(startTime);
+ mKeepaliveStatsTracker.onStartKeepalive();
+
+ setUptimeMillis(writeTime);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ // Same expect as testOneKeepalive_startOnly
+ final int[] expectRegisteredDurations = new int[] {startTime, writeTime - startTime};
+ final int[] expectActiveDurations = new int[] {startTime, writeTime - startTime};
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported,
+ expectRegisteredDurations,
+ expectActiveDurations);
+
+ // Reset metrics
+ mKeepaliveStatsTracker.resetMetrics();
+
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported2 =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+ // Expect the stored durations to be 0 but still contain the number of keepalive = 1.
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported2,
+ /* expectRegisteredDurations= */ new int[] {0, 0},
+ /* expectActiveDurations= */ new int[] {0, 0});
+
+ // Expect that the keepalive is still registered after resetting so it can be stopped.
+ setUptimeMillis(stopTime);
+ mKeepaliveStatsTracker.onStopKeepalive(/* wasActive= */ true);
+
+ setUptimeMillis(writeTime2);
+ final DailykeepaliveInfoReported dailyKeepaliveInfoReported3 =
+ mKeepaliveStatsTracker.buildKeepaliveMetrics();
+
+ final int[] expectRegisteredDurations2 =
+ new int[] {writeTime2 - stopTime, stopTime - writeTime};
+ final int[] expectActiveDurations2 =
+ new int[] {writeTime2 - stopTime, stopTime - writeTime};
+ assertDailyKeepaliveInfoReported(
+ dailyKeepaliveInfoReported3,
+ expectRegisteredDurations2,
+ expectActiveDurations2);
+ }
+}
diff --git a/tests/unit/java/com/android/server/connectivity/VpnTest.java b/tests/unit/java/com/android/server/connectivity/VpnTest.java
index dd9177ee..2926c9a 100644
--- a/tests/unit/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/unit/java/com/android/server/connectivity/VpnTest.java
@@ -72,6 +72,7 @@
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.longThat;
import static org.mockito.Mockito.after;
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doAnswer;
@@ -178,7 +179,6 @@
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
-import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -279,12 +279,11 @@
private static final String TEST_IFACE_NAME = "TEST_IFACE";
private static final int TEST_TUNNEL_RESOURCE_ID = 0x2345;
private static final long TEST_TIMEOUT_MS = 500L;
+ private static final long TIMEOUT_CROSSTHREAD_MS = 20_000L;
private static final String PRIMARY_USER_APP_EXCLUDE_KEY =
"VPNAPPEXCLUDED_27_com.testvpn.vpn";
static final String PKGS_BYTES = getPackageByteString(List.of(PKGS));
private static final Range<Integer> PRIMARY_USER_RANGE = uidRangeForUser(PRIMARY_USER.id);
- // Same as IkeSessionParams#IKE_NATT_KEEPALIVE_DELAY_SEC_DEFAULT
- private static final int IKE_NATT_KEEPALIVE_DELAY_SEC_DEFAULT = 10;
private static final int TEST_KEEPALIVE_TIMER = 800;
private static final int TEST_SUB_ID = 1234;
private static final String TEST_MCCMNC = "12345";
@@ -308,14 +307,51 @@
@Mock private SubscriptionManager mSubscriptionManager;
@Mock private IpSecService mIpSecService;
@Mock private VpnProfileStore mVpnProfileStore;
- @Mock private ScheduledThreadPoolExecutor mExecutor;
- @Mock private ScheduledFuture mScheduledFuture;
+ private final TestExecutor mExecutor;
@Mock DeviceIdleInternal mDeviceIdleInternal;
private final VpnProfile mVpnProfile;
private IpSecManager mIpSecManager;
private TestDeps mTestDeps;
+ public static class TestExecutor extends ScheduledThreadPoolExecutor {
+ public static final long REAL_DELAY = -1;
+
+ // For the purposes of the test, run all scheduled tasks after 10ms to save
+ // execution time, unless overridden by the specific test. Set to REAL_DELAY
+ // to actually wait for the delay specified by the real call to schedule().
+ public long delayMs = 10;
+ // If this is true, execute() will call the runnable inline. This is useful because
+ // super.execute() calls schedule(), which messes with checks that scheduled() is
+ // called a given number of times.
+ public boolean executeDirect = false;
+
+ public TestExecutor() {
+ super(1);
+ }
+
+ @Override
+ public void execute(final Runnable command) {
+ // See |executeDirect| for why this is necessary.
+ if (executeDirect) {
+ command.run();
+ } else {
+ super.execute(command);
+ }
+ }
+
+ @Override
+ public ScheduledFuture<?> schedule(final Runnable command, final long delay,
+ TimeUnit unit) {
+ if (0 == delay || delayMs == REAL_DELAY) {
+ // super.execute() calls schedule() with 0, so use the real delay if it's 0.
+ return super.schedule(command, delay, unit);
+ } else {
+ return super.schedule(command, delayMs, TimeUnit.MILLISECONDS);
+ }
+ }
+ }
+
public VpnTest() throws Exception {
// Build an actual VPN profile that is capable of being converted to and from an
// Ikev2VpnProfile
@@ -323,6 +359,7 @@
new Ikev2VpnProfile.Builder(TEST_VPN_SERVER, TEST_VPN_IDENTITY);
builder.setAuthPsk(TEST_VPN_PSK);
builder.setBypassable(true /* isBypassable */);
+ mExecutor = spy(new TestExecutor());
mVpnProfile = builder.build().toVpnProfile();
}
@@ -388,7 +425,6 @@
// Set up mIkev2SessionCreator and mExecutor
resetIkev2SessionCreator(mIkeSessionWrapper);
- resetExecutor(mScheduledFuture);
}
private void resetIkev2SessionCreator(Vpn.IkeSessionWrapper ikeSession) {
@@ -397,23 +433,6 @@
.thenReturn(ikeSession);
}
- private void resetExecutor(ScheduledFuture scheduledFuture) {
- doAnswer(
- (invocation) -> {
- ((Runnable) invocation.getArgument(0)).run();
- return null;
- })
- .when(mExecutor)
- .execute(any());
- when(mExecutor.schedule(
- any(Runnable.class), anyLong(), any())).thenReturn(mScheduledFuture);
- }
-
- @After
- public void tearDown() throws Exception {
- doReturn(PERMISSION_DENIED).when(mContext).checkCallingOrSelfPermission(any());
- }
-
private <T> void mockService(Class<T> clazz, String name, T service) {
doReturn(service).when(mContext).getSystemService(name);
doReturn(name).when(mContext).getSystemServiceName(clazz);
@@ -524,9 +543,9 @@
}
private void verifyPowerSaveTempWhitelistApp(String packageName) {
- verify(mDeviceIdleInternal).addPowerSaveTempWhitelistApp(anyInt(), eq(packageName),
- anyLong(), anyInt(), eq(false), eq(PowerWhitelistManager.REASON_VPN),
- eq("VpnManager event"));
+ verify(mDeviceIdleInternal, timeout(TEST_TIMEOUT_MS)).addPowerSaveTempWhitelistApp(
+ anyInt(), eq(packageName), anyLong(), anyInt(), eq(false),
+ eq(PowerWhitelistManager.REASON_VPN), eq("VpnManager event"));
}
@Test
@@ -765,7 +784,8 @@
@Test
public void testPrepare_throwSecurityExceptionWhenGivenPackageDoesNotBelongToTheCaller()
throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ mTestDeps.mIgnoreCallingUidChecks = false;
+ final Vpn vpn = createVpn();
assertThrows(SecurityException.class,
() -> vpn.prepare("com.not.vpn.owner", null, VpnManager.TYPE_VPN_SERVICE));
assertThrows(SecurityException.class,
@@ -777,7 +797,7 @@
@Test
public void testPrepare_bothOldPackageAndNewPackageAreNull() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ final Vpn vpn = createVpn();
assertTrue(vpn.prepare(null, null, VpnManager.TYPE_VPN_SERVICE));
}
@@ -860,17 +880,14 @@
assertEquals(expected, vpn.getProfileNameForPackage(TEST_VPN_PKG));
}
- private Vpn createVpnAndSetupUidChecks(String... grantedOps) throws Exception {
- return createVpnAndSetupUidChecks(PRIMARY_USER, grantedOps);
+ private Vpn createVpn(String... grantedOps) throws Exception {
+ return createVpn(PRIMARY_USER, grantedOps);
}
- private Vpn createVpnAndSetupUidChecks(UserInfo user, String... grantedOps) throws Exception {
+ private Vpn createVpn(UserInfo user, String... grantedOps) throws Exception {
final Vpn vpn = createVpn(user.id);
setMockedUsers(user);
- when(mPackageManager.getPackageUidAsUser(eq(TEST_VPN_PKG), anyInt()))
- .thenReturn(Process.myUid());
-
for (final String opStr : grantedOps) {
when(mAppOps.noteOpNoThrow(opStr, Process.myUid(), TEST_VPN_PKG,
null /* attributionTag */, null /* message */))
@@ -899,7 +916,7 @@
public void testProvisionVpnProfileNoIpsecTunnels() throws Exception {
when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_IPSEC_TUNNELS))
.thenReturn(false);
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
checkProvisionVpnProfile(
@@ -910,7 +927,7 @@
}
private Vpn prepareVpnForVerifyAppExclusionList() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
when(mVpnProfileStore.get(PRIMARY_USER_APP_EXCLUDE_KEY))
@@ -1026,7 +1043,7 @@
@Test
public void testProvisionVpnProfilePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
checkProvisionVpnProfile(
vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
@@ -1034,7 +1051,7 @@
@Test
public void testProvisionVpnProfileNotPreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ final Vpn vpn = createVpn();
// Expect that both the ACTIVATE_VPN and ACTIVATE_PLATFORM_VPN were tried, but the caller
// had neither.
@@ -1044,14 +1061,14 @@
@Test
public void testProvisionVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_VPN);
checkProvisionVpnProfile(vpn, true /* expectedResult */, AppOpsManager.OPSTR_ACTIVATE_VPN);
}
@Test
public void testProvisionVpnProfileTooLarge() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
final VpnProfile bigProfile = new VpnProfile("");
bigProfile.name = new String(new byte[Vpn.MAX_VPN_PROFILE_SIZE_BYTES + 1]);
@@ -1066,7 +1083,7 @@
@Test
public void testProvisionVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
- createVpnAndSetupUidChecks(
+ createVpn(
RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
@@ -1078,7 +1095,7 @@
@Test
public void testDeleteVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ final Vpn vpn = createVpn();
vpn.deleteVpnProfile(TEST_VPN_PKG);
@@ -1089,7 +1106,7 @@
@Test
public void testDeleteVpnProfileRestrictedUser() throws Exception {
final Vpn vpn =
- createVpnAndSetupUidChecks(
+ createVpn(
RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
@@ -1101,7 +1118,7 @@
@Test
public void testGetVpnProfilePrivileged() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ final Vpn vpn = createVpn();
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(new VpnProfile("").encode());
@@ -1120,7 +1137,7 @@
eq(null) /* message */);
verify(mAppOps).startOp(
eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
- eq(Process.myUid()),
+ eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
eq(packageName),
eq(null) /* attributionTag */,
eq(null) /* message */);
@@ -1130,14 +1147,14 @@
// Add a small delay to double confirm that finishOp is only called once.
verify(mAppOps, after(100)).finishOp(
eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
- eq(Process.myUid()),
+ eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
eq(packageName),
eq(null) /* attributionTag */);
}
@Test
public void testStartVpnProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -1150,7 +1167,7 @@
@Test
public void testStartVpnProfileVpnServicePreconsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -1164,7 +1181,7 @@
@Test
public void testStartVpnProfileNotConsented() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ final Vpn vpn = createVpn();
try {
vpn.startVpnProfile(TEST_VPN_PKG);
@@ -1189,7 +1206,7 @@
@Test
public void testStartVpnProfileMissingProfile() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG))).thenReturn(null);
@@ -1211,9 +1228,7 @@
@Test
public void testStartVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.startVpnProfile(TEST_VPN_PKG);
@@ -1224,9 +1239,7 @@
@Test
public void testStopVpnProfileRestrictedUser() throws Exception {
- final Vpn vpn =
- createVpnAndSetupUidChecks(
- RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(RESTRICTED_PROFILE_A, AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
try {
vpn.stopVpnProfile(TEST_VPN_PKG);
@@ -1237,7 +1250,7 @@
@Test
public void testStartOpAndFinishOpWillBeCalledWhenPlatformVpnIsOnAndOff() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
vpn.startVpnProfile(TEST_VPN_PKG);
@@ -1245,14 +1258,14 @@
// Add a small delay to make sure that startOp is only called once.
verify(mAppOps, after(100).times(1)).startOp(
eq(AppOpsManager.OPSTR_ESTABLISH_VPN_MANAGER),
- eq(Process.myUid()),
+ eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
eq(TEST_VPN_PKG),
eq(null) /* attributionTag */,
eq(null) /* message */);
// Check that the startOp is not called with OPSTR_ESTABLISH_VPN_SERVICE.
verify(mAppOps, never()).startOp(
eq(AppOpsManager.OPSTR_ESTABLISH_VPN_SERVICE),
- eq(Process.myUid()),
+ eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
eq(TEST_VPN_PKG),
eq(null) /* attributionTag */,
eq(null) /* message */);
@@ -1262,7 +1275,9 @@
@Test
public void testStartOpWithSeamlessHandover() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_VPN);
+ // Create with SYSTEM_USER so that establish() will match the user ID when checking
+ // against Binder.getCallerUid
+ final Vpn vpn = createVpn(SYSTEM_USER, AppOpsManager.OPSTR_ACTIVATE_VPN);
assertTrue(vpn.prepare(TEST_VPN_PKG, null, VpnManager.TYPE_VPN_SERVICE));
final VpnConfig config = new VpnConfig();
config.user = "VpnTest";
@@ -1293,12 +1308,12 @@
}
private void verifyVpnManagerEvent(String sessionKey, String category, int errorClass,
- int errorCode, String[] packageName, VpnProfileState... profileState) {
+ int errorCode, String[] packageName, @NonNull VpnProfileState... profileState) {
final Context userContext =
mContext.createContextAsUser(UserHandle.of(PRIMARY_USER.id), 0 /* flags */);
final ArgumentCaptor<Intent> intentArgumentCaptor = ArgumentCaptor.forClass(Intent.class);
- final int verifyTimes = (profileState == null) ? 1 : profileState.length;
+ final int verifyTimes = profileState.length;
verify(userContext, times(verifyTimes)).startService(intentArgumentCaptor.capture());
for (int i = 0; i < verifyTimes; i++) {
@@ -1329,10 +1344,8 @@
VpnManager.EXTRA_UNDERLYING_LINK_PROPERTIES));
}
- if (profileState != null) {
- assertEquals(profileState[i], intent.getParcelableExtra(
- VpnManager.EXTRA_VPN_PROFILE_STATE, VpnProfileState.class));
- }
+ assertEquals(profileState[i], intent.getParcelableExtra(
+ VpnManager.EXTRA_VPN_PROFILE_STATE, VpnProfileState.class));
}
reset(userContext);
}
@@ -1341,7 +1354,11 @@
// CATEGORY_EVENT_DEACTIVATED_BY_USER is not an error event, so both of errorClass and
// errorCode won't be set.
verifyVpnManagerEvent(sessionKey, VpnManager.CATEGORY_EVENT_DEACTIVATED_BY_USER,
- -1 /* errorClass */, -1 /* errorCode */, packageName, null /* profileState */);
+ -1 /* errorClass */, -1 /* errorCode */, packageName,
+ // VPN NetworkAgnet does not switch to CONNECTED in the test, and the state is not
+ // important here. Verify that the state as it is, i.e. CONNECTING state.
+ new VpnProfileState(VpnProfileState.STATE_CONNECTING,
+ sessionKey, false /* alwaysOn */, false /* lockdown */));
}
private void verifyAlwaysOnStateChanged(String[] packageName, VpnProfileState... profileState) {
@@ -1358,7 +1375,7 @@
// this is checked with CONTROL_VPN so simulate holding CONTROL_VPN in order to pass the
// security checks.
doReturn(PERMISSION_GRANTED).when(mContext).checkCallingOrSelfPermission(CONTROL_VPN);
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -1450,7 +1467,7 @@
@Test
public void testReconnectVpnManagerVpnWithAlwaysOnEnabled() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
vpn.startVpnProfile(TEST_VPN_PKG);
@@ -1474,46 +1491,73 @@
}
@Test
+ public void testLockdown_enableDisableWhileConnected() throws Exception {
+ final PlatformVpnSnapshot vpnSnapShot = verifySetupPlatformVpn(
+ createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */));
+
+ final InOrder order = inOrder(mTestDeps);
+ order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
+ .newNetworkAgent(any(), any(), any(), any(), any(), any(),
+ argThat(config -> config.allowBypass), any(), any());
+
+ // Make VPN lockdown.
+ assertTrue(vpnSnapShot.vpn.setAlwaysOnPackage(TEST_VPN_PKG, true /* lockdown */,
+ null /* lockdownAllowlist */));
+
+ order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
+ .newNetworkAgent(any(), any(), any(), any(), any(), any(),
+ argThat(config -> !config.allowBypass), any(), any());
+
+ // Disable lockdown.
+ assertTrue(vpnSnapShot.vpn.setAlwaysOnPackage(TEST_VPN_PKG, false /* lockdown */,
+ null /* lockdownAllowlist */));
+
+ order.verify(mTestDeps, timeout(TIMEOUT_CROSSTHREAD_MS))
+ .newNetworkAgent(any(), any(), any(), any(), any(), any(),
+ argThat(config -> config.allowBypass), any(), any());
+ }
+
+ @Test
public void testSetPackageAuthorizationVpnService() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ final Vpn vpn = createVpn();
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_SERVICE));
verify(mAppOps)
.setMode(
eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
- eq(Process.myUid()),
+ eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
}
@Test
public void testSetPackageAuthorizationPlatformVpn() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ final Vpn vpn = createVpn();
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, TYPE_VPN_PLATFORM));
verify(mAppOps)
.setMode(
eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
+ eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_ALLOWED));
}
@Test
public void testSetPackageAuthorizationRevokeAuthorization() throws Exception {
- final Vpn vpn = createVpnAndSetupUidChecks();
+ final Vpn vpn = createVpn();
assertTrue(vpn.setPackageAuthorization(TEST_VPN_PKG, VpnManager.TYPE_VPN_NONE));
verify(mAppOps)
.setMode(
eq(AppOpsManager.OPSTR_ACTIVATE_VPN),
- eq(Process.myUid()),
+ eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_IGNORED));
verify(mAppOps)
.setMode(
eq(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN),
- eq(Process.myUid()),
+ eq(UserHandle.getUid(PRIMARY_USER.id, Process.myUid())),
eq(TEST_VPN_PKG),
eq(AppOpsManager.MODE_IGNORED));
}
@@ -1551,7 +1595,7 @@
final ArgumentCaptor<IkeSessionCallback> captor =
ArgumentCaptor.forClass(IkeSessionCallback.class);
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(mVpnProfile.encode());
@@ -1574,10 +1618,7 @@
// same process with the real case.
if (errorCode == VpnManager.ERROR_CODE_NETWORK_LOST) {
cb.onLost(TEST_NETWORK);
- final ArgumentCaptor<Runnable> runnableCaptor =
- ArgumentCaptor.forClass(Runnable.class);
- verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any());
- runnableCaptor.getValue().run();
+ verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
} else {
final IkeSessionCallback ikeCb = captor.getValue();
ikeCb.onClosedWithException(exception);
@@ -1586,7 +1627,10 @@
verifyPowerSaveTempWhitelistApp(TEST_VPN_PKG);
reset(mDeviceIdleInternal);
verifyVpnManagerEvent(sessionKey, category, errorType, errorCode,
- new String[] {TEST_VPN_PKG}, null /* profileState */);
+ // VPN NetworkAgnet does not switch to CONNECTED in the test, and the state is not
+ // important here. Verify that the state as it is, i.e. CONNECTING state.
+ new String[] {TEST_VPN_PKG}, new VpnProfileState(VpnProfileState.STATE_CONNECTING,
+ sessionKey, false /* alwaysOn */, false /* lockdown */));
if (errorType == VpnManager.ERROR_CLASS_NOT_RECOVERABLE) {
verify(mConnectivityManager, timeout(TEST_TIMEOUT_MS))
.unregisterNetworkCallback(eq(cb));
@@ -1602,25 +1646,23 @@
}
private IkeSessionCallback verifyRetryAndGetNewIkeCb(int retryIndex) {
- final ArgumentCaptor<Runnable> runnableCaptor =
- ArgumentCaptor.forClass(Runnable.class);
final ArgumentCaptor<IkeSessionCallback> ikeCbCaptor =
ArgumentCaptor.forClass(IkeSessionCallback.class);
// Verify retry is scheduled
- final long expectedDelay = mTestDeps.getNextRetryDelaySeconds(retryIndex);
- verify(mExecutor).schedule(runnableCaptor.capture(), eq(expectedDelay), any());
+ final long expectedDelayMs = mTestDeps.getNextRetryDelayMs(retryIndex);
+ final ArgumentCaptor<Long> delayCaptor = ArgumentCaptor.forClass(Long.class);
+ verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), delayCaptor.capture(),
+ eq(TimeUnit.MILLISECONDS));
+ final List<Long> delays = delayCaptor.getAllValues();
+ assertEquals(expectedDelayMs, (long) delays.get(delays.size() - 1));
- // Mock the event of firing the retry task
- runnableCaptor.getValue().run();
-
- verify(mIkev2SessionCreator)
+ verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS + expectedDelayMs))
.createIkeSession(any(), any(), any(), any(), ikeCbCaptor.capture(), any());
// Forget the mIkev2SessionCreator#createIkeSession call and mExecutor#schedule call
// for the next retry verification
resetIkev2SessionCreator(mIkeSessionWrapper);
- resetExecutor(mScheduledFuture);
return ikeCbCaptor.getValue();
}
@@ -1878,12 +1920,14 @@
any(), any(), anyString(), any(), any(), any(), any(), any(), any());
doReturn(TEST_NETWORK).when(mMockNetworkAgent).getNetwork();
- final Vpn vpn = createVpnAndSetupUidChecks(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
+ final Vpn vpn = createVpn(AppOpsManager.OPSTR_ACTIVATE_PLATFORM_VPN);
when(mVpnProfileStore.get(vpn.getProfileNameForPackage(TEST_VPN_PKG)))
.thenReturn(vpnProfile.encode());
vpn.startVpnProfile(TEST_VPN_PKG);
final NetworkCallback nwCb = triggerOnAvailableAndGetCallback();
+ verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
+ reset(mExecutor);
// Mock the setup procedure by firing callbacks
final Pair<IkeSessionCallback, ChildSessionCallback> cbPair =
@@ -2088,12 +2132,78 @@
vpnSnapShot.nwCb.onCapabilitiesChanged(
TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
// Verify MOBIKE is triggered
- verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2,
+ verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(TEST_NETWORK_2,
expectedIpVersion, expectedEncapType, expectedKeepalive);
vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
}
+ @Test
+ public void testLinkPropertiesUpdateTriggerReevaluation() throws Exception {
+ final boolean hasV6 = true;
+
+ mockCarrierConfig(TEST_SUB_ID, TelephonyManager.SIM_STATE_LOADED, TEST_KEEPALIVE_TIMER,
+ PREFERRED_IKE_PROTOCOL_IPV6_ESP);
+ final IkeSessionParams params = getTestIkeSessionParams(hasV6,
+ new IkeFqdnIdentification(TEST_IDENTITY), TEST_KEEPALIVE_TIMER);
+ final IkeTunnelConnectionParams tunnelParams =
+ new IkeTunnelConnectionParams(params, CHILD_PARAMS);
+ final Ikev2VpnProfile ikeProfile = new Ikev2VpnProfile.Builder(tunnelParams)
+ .setBypassable(true)
+ .setAutomaticNattKeepaliveTimerEnabled(false)
+ .setAutomaticIpVersionSelectionEnabled(true)
+ .build();
+ final PlatformVpnSnapshot vpnSnapShot =
+ verifySetupPlatformVpn(ikeProfile.toVpnProfile(),
+ createIkeConfig(createIkeConnectInfo(), true /* isMobikeEnabled */),
+ hasV6 /* mtuSupportsIpv6 */,
+ false /* areLongLivedTcpConnectionsExpensive */);
+ reset(mExecutor);
+
+ // Simulate a new network coming up
+ final LinkProperties lp = new LinkProperties();
+ lp.addLinkAddress(new LinkAddress("192.0.2.2/32"));
+
+ // Have the executor use the real delay to make sure schedule() was called only
+ // once for all calls. Also, arrange for execute() not to call schedule() to avoid
+ // messing with the checks for schedule().
+ mExecutor.delayMs = TestExecutor.REAL_DELAY;
+ mExecutor.executeDirect = true;
+ vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
+ vpnSnapShot.nwCb.onCapabilitiesChanged(
+ TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
+ vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
+ verify(mExecutor).schedule(any(Runnable.class), longThat(it -> it > 0), any());
+ reset(mExecutor);
+
+ final InOrder order = inOrder(mIkeSessionWrapper);
+
+ // Verify the network is started
+ order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
+ ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
+
+ // Send the same properties, check that no migration is scheduled
+ vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
+ verify(mExecutor, never()).schedule(any(Runnable.class), anyLong(), any());
+
+ // Add v6 address, verify MOBIKE is triggered
+ lp.addLinkAddress(new LinkAddress("2001:db8::1/64"));
+ vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
+ order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
+ ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
+
+ // Add another v4 address, verify MOBIKE is triggered
+ final LinkProperties stacked = new LinkProperties();
+ stacked.setInterfaceName("v4-" + lp.getInterfaceName());
+ stacked.addLinkAddress(new LinkAddress("192.168.0.1/32"));
+ lp.addStackedLink(stacked);
+ vpnSnapShot.nwCb.onLinkPropertiesChanged(TEST_NETWORK_2, new LinkProperties(lp));
+ order.verify(mIkeSessionWrapper, timeout(TIMEOUT_CROSSTHREAD_MS)).setNetwork(TEST_NETWORK_2,
+ ESP_IP_VERSION_AUTO, ESP_ENCAP_TYPE_AUTO, TEST_KEEPALIVE_TIMER);
+
+ vpnSnapShot.vpn.mVpnRunner.exitVpnRunner();
+ }
+
private void mockCarrierConfig(int subId, int simStatus, int keepaliveTimer, int ikeProtocol) {
final SubscriptionInfo subscriptionInfo = mock(SubscriptionInfo.class);
doReturn(subId).when(subscriptionInfo).getSubscriptionId();
@@ -2247,7 +2357,7 @@
reset(mIkeSessionWrapper);
mockCarrierConfig(TEST_SUB_ID, simState, TEST_KEEPALIVE_TIMER, preferredIpProto);
vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2, nc);
- verify(mIkeSessionWrapper).setNetwork(TEST_NETWORK_2,
+ verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(TEST_NETWORK_2,
expectedIpVersion, expectedEncapType, expectedKeepaliveTimer);
if (expectedReadFromCarrierConfig) {
final ArgumentCaptor<NetworkCapabilities> ncCaptor =
@@ -2296,17 +2406,16 @@
// Mock network loss and verify a cleanup task is scheduled
vpnSnapShot.nwCb.onLost(TEST_NETWORK);
- verify(mExecutor).schedule(any(Runnable.class), anyLong(), any());
+ verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
// Mock new network comes up and the cleanup task is cancelled
vpnSnapShot.nwCb.onAvailable(TEST_NETWORK_2);
- verify(mScheduledFuture).cancel(anyBoolean());
verify(mIkeSessionWrapper, never()).setNetwork(any(), anyInt(), anyInt(), anyInt());
vpnSnapShot.nwCb.onCapabilitiesChanged(TEST_NETWORK_2,
new NetworkCapabilities.Builder().build());
// Verify MOBIKE is triggered
- verify(mIkeSessionWrapper).setNetwork(eq(TEST_NETWORK_2),
+ verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).setNetwork(eq(TEST_NETWORK_2),
eq(ESP_IP_VERSION_AUTO) /* ipVersion */,
eq(ESP_ENCAP_TYPE_AUTO) /* encapType */,
eq(DEFAULT_UDP_PORT_4500_NAT_TIMEOUT_SEC_INT) /* keepaliveDelay */);
@@ -2405,7 +2514,7 @@
vpnSnapShot.nwCb.onCapabilitiesChanged(
TEST_NETWORK_2, new NetworkCapabilities.Builder().build());
// Verify the old IKE Session is killed
- verify(mIkeSessionWrapper).kill();
+ verify(mIkeSessionWrapper, timeout(TEST_TIMEOUT_MS)).kill();
// Capture callbacks of the new IKE Session
final Pair<IkeSessionCallback, ChildSessionCallback> cbPair =
@@ -2437,19 +2546,16 @@
// Forget the #sendLinkProperties during first setup.
reset(mMockNetworkAgent);
- final ArgumentCaptor<Runnable> runnableCaptor =
- ArgumentCaptor.forClass(Runnable.class);
-
// Mock network loss
vpnSnapShot.nwCb.onLost(TEST_NETWORK);
// Mock the grace period expires
- verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any());
- runnableCaptor.getValue().run();
+ verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
final ArgumentCaptor<LinkProperties> lpCaptor =
ArgumentCaptor.forClass(LinkProperties.class);
- verify(mMockNetworkAgent).doSendLinkProperties(lpCaptor.capture());
+ verify(mMockNetworkAgent, timeout(TEST_TIMEOUT_MS))
+ .doSendLinkProperties(lpCaptor.capture());
final LinkProperties lp = lpCaptor.getValue();
assertNull(lp.getInterfaceName());
@@ -2547,9 +2653,7 @@
// variables(timer counter and boolean) was reset.
((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
NetworkAgent.VALIDATION_STATUS_NOT_VALID);
- final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any());
- runnableCaptor.getValue().run();
+ verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
verify(mIkev2SessionCreator, never()).createIkeSession(
any(), any(), any(), any(), any(), any());
}
@@ -2575,17 +2679,16 @@
NetworkAgent.VALIDATION_STATUS_NOT_VALID);
// Verify reset is scheduled and run.
- final ArgumentCaptor<Runnable> runnableCaptor = ArgumentCaptor.forClass(Runnable.class);
- verify(mExecutor).schedule(runnableCaptor.capture(), anyLong(), any());
+ verify(mExecutor, atLeastOnce()).schedule(any(Runnable.class), anyLong(), any());
// Another invalid status reported should not trigger other scheduled recovery.
reset(mExecutor);
((Vpn.IkeV2VpnRunner) vpnSnapShot.vpn.mVpnRunner).onValidationStatus(
NetworkAgent.VALIDATION_STATUS_NOT_VALID);
- verify(mExecutor, never()).schedule(runnableCaptor.capture(), anyLong(), any());
+ verify(mExecutor, never()).schedule(any(Runnable.class), anyLong(), any());
- runnableCaptor.getValue().run();
- verify(mIkev2SessionCreator).createIkeSession(any(), any(), any(), any(), any(), any());
+ verify(mIkev2SessionCreator, timeout(TEST_TIMEOUT_MS))
+ .createIkeSession(any(), any(), any(), any(), any(), any());
}
@Test
@@ -2857,15 +2960,23 @@
}
@Override
- public long getNextRetryDelaySeconds(int retryCount) {
+ public long getNextRetryDelayMs(int retryCount) {
// Simply return retryCount as the delay seconds for retrying.
- return retryCount;
+ return retryCount * 1000;
}
@Override
public ScheduledThreadPoolExecutor newScheduledThreadPoolExecutor() {
return mExecutor;
}
+
+ public boolean mIgnoreCallingUidChecks = true;
+ @Override
+ public void verifyCallingUidAndPackage(Context context, String packageName, int userId) {
+ if (!mIgnoreCallingUidChecks) {
+ super.verifyCallingUidAndPackage(context, packageName, userId);
+ }
+ }
}
/**
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
index 0ca0835..9c0abfc 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsInterfaceAdvertiserTest.kt
@@ -22,6 +22,7 @@
import android.os.Build
import android.os.HandlerThread
import com.android.net.module.util.HexDump
+import com.android.net.module.util.SharedLog
import com.android.server.connectivity.mdns.MdnsAnnouncer.AnnouncementInfo
import com.android.server.connectivity.mdns.MdnsAnnouncer.BaseAnnouncementInfo
import com.android.server.connectivity.mdns.MdnsAnnouncer.ExitAnnouncementInfo
@@ -75,6 +76,7 @@
private val replySender = mock(MdnsReplySender::class.java)
private val announcer = mock(MdnsAnnouncer::class.java)
private val prober = mock(MdnsProber::class.java)
+ private val sharedlog = mock(SharedLog::class.java)
@Suppress("UNCHECKED_CAST")
private val probeCbCaptor = ArgumentCaptor.forClass(PacketRepeaterCallback::class.java)
as ArgumentCaptor<PacketRepeaterCallback<ProbingInfo>>
@@ -97,7 +99,8 @@
TEST_BUFFER,
cb,
deps,
- TEST_HOSTNAME
+ TEST_HOSTNAME,
+ sharedlog
)
}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceCacheTest.kt b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceCacheTest.kt
new file mode 100644
index 0000000..f091eea
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceCacheTest.kt
@@ -0,0 +1,136 @@
+/*
+ * 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.connectivity.mdns
+
+import android.net.Network
+import android.os.Build
+import android.os.Handler
+import android.os.HandlerThread
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertNotNull
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+private const val SERVICE_NAME_1 = "service-instance-1"
+private const val SERVICE_NAME_2 = "service-instance-2"
+private const val SERVICE_TYPE_1 = "_test1._tcp.local"
+private const val SERVICE_TYPE_2 = "_test2._tcp.local"
+private const val INTERFACE_INDEX = 999
+private const val DEFAULT_TIMEOUT_MS = 2000L
+
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
+class MdnsServiceCacheTest {
+ private val network = mock(Network::class.java)
+ private val thread = HandlerThread(MdnsServiceCacheTest::class.simpleName)
+ private val handler by lazy {
+ Handler(thread.looper)
+ }
+ private val serviceCache by lazy {
+ MdnsServiceCache(thread.looper)
+ }
+
+ @Before
+ fun setUp() {
+ thread.start()
+ }
+
+ @After
+ fun tearDown() {
+ thread.quitSafely()
+ }
+
+ private fun <T> runningOnHandlerAndReturn(functor: (() -> T)): T {
+ val future = CompletableFuture<T>()
+ handler.post {
+ future.complete(functor())
+ }
+ return future.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)
+ }
+
+ private fun addOrUpdateService(serviceType: String, network: Network, service: MdnsResponse):
+ Unit = runningOnHandlerAndReturn {
+ serviceCache.addOrUpdateService(serviceType, network, service) }
+
+ private fun removeService(serviceName: String, serviceType: String, network: Network):
+ Unit = runningOnHandlerAndReturn {
+ serviceCache.removeService(serviceName, serviceType, network) }
+
+ private fun getService(serviceName: String, serviceType: String, network: Network):
+ MdnsResponse? = runningOnHandlerAndReturn {
+ serviceCache.getCachedService(serviceName, serviceType, network) }
+
+ private fun getServices(serviceType: String, network: Network): List<MdnsResponse> =
+ runningOnHandlerAndReturn { serviceCache.getCachedServices(serviceType, network) }
+
+ @Test
+ fun testAddAndRemoveService() {
+ addOrUpdateService(SERVICE_TYPE_1, network, createResponse(SERVICE_NAME_1, SERVICE_TYPE_1))
+ var response = getService(SERVICE_NAME_1, SERVICE_TYPE_1, network)
+ assertNotNull(response)
+ assertEquals(SERVICE_NAME_1, response.serviceInstanceName)
+ removeService(SERVICE_NAME_1, SERVICE_TYPE_1, network)
+ response = getService(SERVICE_NAME_1, SERVICE_TYPE_1, network)
+ assertNull(response)
+ }
+
+ @Test
+ fun testGetCachedServices_multipleServiceTypes() {
+ addOrUpdateService(SERVICE_TYPE_1, network, createResponse(SERVICE_NAME_1, SERVICE_TYPE_1))
+ addOrUpdateService(SERVICE_TYPE_1, network, createResponse(SERVICE_NAME_2, SERVICE_TYPE_1))
+ addOrUpdateService(SERVICE_TYPE_2, network, createResponse(SERVICE_NAME_2, SERVICE_TYPE_2))
+
+ val responses1 = getServices(SERVICE_TYPE_1, network)
+ assertEquals(2, responses1.size)
+ assertTrue(responses1.stream().anyMatch { response ->
+ response.serviceInstanceName == SERVICE_NAME_1
+ })
+ assertTrue(responses1.any { response ->
+ response.serviceInstanceName == SERVICE_NAME_2
+ })
+ val responses2 = getServices(SERVICE_TYPE_2, network)
+ assertEquals(1, responses2.size)
+ assertTrue(responses2.any { response ->
+ response.serviceInstanceName == SERVICE_NAME_2
+ })
+
+ removeService(SERVICE_NAME_2, SERVICE_TYPE_1, network)
+ val responses3 = getServices(SERVICE_TYPE_1, network)
+ assertEquals(1, responses3.size)
+ assertTrue(responses3.any { response ->
+ response.serviceInstanceName == SERVICE_NAME_1
+ })
+ val responses4 = getServices(SERVICE_TYPE_2, network)
+ assertEquals(1, responses4.size)
+ assertTrue(responses4.any { response ->
+ response.serviceInstanceName == SERVICE_NAME_2
+ })
+ }
+
+ private fun createResponse(serviceInstanceName: String, serviceType: String) = MdnsResponse(
+ 0 /* now */, "$serviceInstanceName.$serviceType".split(".").toTypedArray(),
+ INTERFACE_INDEX, network)
+}
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
index 5d58f5d..34b44fc 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsServiceTypeClientTests.java
@@ -41,6 +41,7 @@
import android.net.Network;
import android.text.TextUtils;
+import com.android.net.module.util.SharedLog;
import com.android.server.connectivity.mdns.MdnsServiceInfo.TextEntry;
import com.android.server.connectivity.mdns.MdnsServiceTypeClient.QueryTaskConfig;
import com.android.testutils.DevSdkIgnoreRule;
@@ -99,6 +100,8 @@
private Network mockNetwork;
@Mock
private MdnsResponseDecoder.Clock mockDecoderClock;
+ @Mock
+ private SharedLog mockSharedLog;
@Captor
private ArgumentCaptor<MdnsServiceInfo> serviceInfoCaptor;
@@ -166,7 +169,7 @@
client =
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
- mockDecoderClock, mockNetwork) {
+ mockDecoderClock, mockNetwork, mockSharedLog) {
@Override
MdnsPacketWriter createMdnsPacketWriter() {
return mockPacketWriter;
@@ -701,7 +704,7 @@
final String serviceInstanceName = "service-instance-1";
client =
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
- mockDecoderClock, mockNetwork) {
+ mockDecoderClock, mockNetwork, mockSharedLog) {
@Override
MdnsPacketWriter createMdnsPacketWriter() {
return mockPacketWriter;
@@ -740,7 +743,7 @@
final String serviceInstanceName = "service-instance-1";
client =
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
- mockDecoderClock, mockNetwork) {
+ mockDecoderClock, mockNetwork, mockSharedLog) {
@Override
MdnsPacketWriter createMdnsPacketWriter() {
return mockPacketWriter;
@@ -773,7 +776,7 @@
final String serviceInstanceName = "service-instance-1";
client =
new MdnsServiceTypeClient(SERVICE_TYPE, mockSocketClient, currentThreadExecutor,
- mockDecoderClock, mockNetwork) {
+ mockDecoderClock, mockNetwork, mockSharedLog) {
@Override
MdnsPacketWriter createMdnsPacketWriter() {
return mockPacketWriter;
@@ -898,7 +901,7 @@
@Test
public void testProcessResponse_Resolve() throws Exception {
client = new MdnsServiceTypeClient(
- SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork);
+ SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork, mockSharedLog);
final String instanceName = "service-instance";
final String[] hostname = new String[] { "testhost "};
@@ -992,6 +995,71 @@
mockNetwork);
}
+ @Test
+ public void testProcessResponse_ResolveExcludesOtherServices() {
+ client = new MdnsServiceTypeClient(
+ SERVICE_TYPE, mockSocketClient, currentThreadExecutor, mockNetwork, mockSharedLog);
+
+ final String requestedInstance = "instance1";
+ final String otherInstance = "instance2";
+ final String ipV4Address = "192.0.2.0";
+ final String ipV6Address = "2001:db8::";
+
+ final MdnsSearchOptions resolveOptions = MdnsSearchOptions.newBuilder()
+ // Use different case in the options
+ .setResolveInstanceName("Instance1").build();
+
+ client.startSendAndReceive(mockListenerOne, resolveOptions);
+ client.startSendAndReceive(mockListenerTwo, MdnsSearchOptions.getDefaultOptions());
+
+ // Complete response from instanceName
+ client.processResponse(createResponse(
+ requestedInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS,
+ Collections.emptyMap() /* textAttributes */, TEST_TTL),
+ INTERFACE_INDEX, mockNetwork);
+
+ // Complete response from otherInstanceName
+ client.processResponse(createResponse(
+ otherInstance, ipV4Address, 5353, SERVICE_TYPE_LABELS,
+ Collections.emptyMap() /* textAttributes */, TEST_TTL),
+ INTERFACE_INDEX, mockNetwork);
+
+ // Address update from otherInstanceName
+ client.processResponse(createResponse(
+ otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS,
+ Collections.emptyMap(), TEST_TTL), INTERFACE_INDEX, mockNetwork);
+
+ // Goodbye from otherInstanceName
+ client.processResponse(createResponse(
+ otherInstance, ipV6Address, 5353, SERVICE_TYPE_LABELS,
+ Collections.emptyMap(), 0L /* ttl */), INTERFACE_INDEX, mockNetwork);
+
+ // mockListenerOne gets notified for the requested instance
+ verify(mockListenerOne).onServiceNameDiscovered(matchServiceName(requestedInstance));
+ verify(mockListenerOne).onServiceFound(matchServiceName(requestedInstance));
+
+ // ...but does not get any callback for the other instance
+ verify(mockListenerOne, never()).onServiceFound(matchServiceName(otherInstance));
+ verify(mockListenerOne, never()).onServiceNameDiscovered(matchServiceName(otherInstance));
+ verify(mockListenerOne, never()).onServiceUpdated(matchServiceName(otherInstance));
+ verify(mockListenerOne, never()).onServiceRemoved(matchServiceName(otherInstance));
+
+ // mockListenerTwo gets notified for both though
+ final InOrder inOrder = inOrder(mockListenerTwo);
+ inOrder.verify(mockListenerTwo).onServiceNameDiscovered(
+ matchServiceName(requestedInstance));
+ inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(requestedInstance));
+
+ inOrder.verify(mockListenerTwo).onServiceNameDiscovered(matchServiceName(otherInstance));
+ inOrder.verify(mockListenerTwo).onServiceFound(matchServiceName(otherInstance));
+ inOrder.verify(mockListenerTwo).onServiceUpdated(matchServiceName(otherInstance));
+ inOrder.verify(mockListenerTwo).onServiceRemoved(matchServiceName(otherInstance));
+ }
+
+ private static MdnsServiceInfo matchServiceName(String name) {
+ return argThat(info -> info.getServiceInstanceName().equals(name));
+ }
+
// verifies that the right query was enqueued with the right delay, and send query by executing
// the runnable.
private void verifyAndSendQuery(int index, long timeInMs, boolean expectsUnicastResponse) {
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
index 6e1debe..2d73c98 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketProviderTest.java
@@ -16,6 +16,13 @@
package com.android.server.connectivity.mdns;
+import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
+import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
+import static android.net.NetworkCapabilities.TRANSPORT_VPN;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_ACK;
+import static com.android.net.module.util.netlink.StructNlMsgHdr.NLM_F_REQUEST;
import static com.android.testutils.ContextUtils.mockService;
import static org.junit.Assert.assertEquals;
@@ -25,6 +32,7 @@
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
@@ -35,18 +43,28 @@
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
-import android.net.INetd;
import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.Network;
+import android.net.NetworkCapabilities;
import android.net.TetheringManager;
import android.net.TetheringManager.TetheringEventCallback;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
+import android.system.OsConstants;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.net.module.util.ArrayTrackRecord;
+import com.android.net.module.util.SharedLog;
+import com.android.net.module.util.netlink.NetlinkConstants;
+import com.android.net.module.util.netlink.RtNetlinkAddressMessage;
+import com.android.net.module.util.netlink.StructIfaddrMsg;
+import com.android.net.module.util.netlink.StructNlMsgHdr;
import com.android.server.connectivity.mdns.MdnsSocketProvider.Dependencies;
+import com.android.server.connectivity.mdns.internal.SocketNetlinkMonitor;
import com.android.testutils.DevSdkIgnoreRule;
import com.android.testutils.DevSdkIgnoreRunner;
import com.android.testutils.HandlerUtils;
@@ -59,23 +77,29 @@
import org.mockito.MockitoAnnotations;
import java.io.IOException;
+import java.net.Inet6Address;
+import java.net.InetAddress;
import java.util.Collections;
import java.util.List;
@RunWith(DevSdkIgnoreRunner.class)
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
public class MdnsSocketProviderTest {
+ private static final String TAG = MdnsSocketProviderTest.class.getSimpleName();
private static final String TEST_IFACE_NAME = "test";
private static final String LOCAL_ONLY_IFACE_NAME = "local_only";
private static final String TETHERED_IFACE_NAME = "tethered";
+ private static final int TETHERED_IFACE_IDX = 32;
private static final long DEFAULT_TIMEOUT = 2000L;
private static final long NO_CALLBACK_TIMEOUT = 200L;
private static final LinkAddress LINKADDRV4 = new LinkAddress("192.0.2.0/24");
private static final LinkAddress LINKADDRV6 =
new LinkAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64");
- private static final Network TEST_NETWORK = new Network(123);
- private static final Network LOCAL_NETWORK = new Network(INetd.LOCAL_NET_ID);
+ private static final LinkAddress LINKADDRV6_FLAG_CHANGE =
+ new LinkAddress("2001:0db8:85a3:0000:0000:8a2e:0370:7334/64", 1 /* flags */,
+ 0 /* scope */);
+ private static final Network TEST_NETWORK = new Network(123);
@Mock private Context mContext;
@Mock private Dependencies mDeps;
@Mock private ConnectivityManager mCm;
@@ -88,6 +112,7 @@
private NetworkCallback mNetworkCallback;
private TetheringEventCallback mTetheringEventCallback;
+ private TestNetLinkMonitor mTestSocketNetLinkMonitor;
@Before
public void setUp() throws IOException {
MockitoAnnotations.initMocks(this);
@@ -101,16 +126,33 @@
// Test is using mockito-extended
doCallRealMethod().when(mContext).getSystemService(TetheringManager.class);
}
- doReturn(true).when(mDeps).canScanOnInterface(any());
doReturn(mTestNetworkIfaceWrapper).when(mDeps).getNetworkInterfaceByName(anyString());
+ doReturn(true).when(mTestNetworkIfaceWrapper).isUp();
+ doReturn(true).when(mLocalOnlyIfaceWrapper).isUp();
+ doReturn(true).when(mTetheredIfaceWrapper).isUp();
+ doReturn(true).when(mTestNetworkIfaceWrapper).supportsMulticast();
+ doReturn(true).when(mLocalOnlyIfaceWrapper).supportsMulticast();
+ doReturn(true).when(mTetheredIfaceWrapper).supportsMulticast();
doReturn(mLocalOnlyIfaceWrapper).when(mDeps)
.getNetworkInterfaceByName(LOCAL_ONLY_IFACE_NAME);
doReturn(mTetheredIfaceWrapper).when(mDeps).getNetworkInterfaceByName(TETHERED_IFACE_NAME);
doReturn(mock(MdnsInterfaceSocket.class))
.when(mDeps).createMdnsInterfaceSocket(any(), anyInt(), any(), any());
+ doReturn(TETHERED_IFACE_IDX).when(mDeps).getNetworkInterfaceIndexByName(
+ TETHERED_IFACE_NAME);
final HandlerThread thread = new HandlerThread("MdnsSocketProviderTest");
thread.start();
mHandler = new Handler(thread.getLooper());
+
+ doReturn(mTestSocketNetLinkMonitor).when(mDeps).createSocketNetlinkMonitor(any(), any(),
+ any());
+ doAnswer(inv -> {
+ mTestSocketNetLinkMonitor = new TestNetLinkMonitor(inv.getArgument(0),
+ inv.getArgument(1),
+ inv.getArgument(2));
+ return mTestSocketNetLinkMonitor;
+ }).when(mDeps).createSocketNetlinkMonitor(any(), any(),
+ any());
mSocketProvider = new MdnsSocketProvider(mContext, thread.getLooper(), mDeps);
}
@@ -127,6 +169,23 @@
mNetworkCallback = nwCallbackCaptor.getValue();
mTetheringEventCallback = teCallbackCaptor.getValue();
+
+ mHandler.post(mSocketProvider::startNetLinkMonitor);
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+ }
+
+ private static class TestNetLinkMonitor extends SocketNetlinkMonitor {
+ TestNetLinkMonitor(@NonNull Handler handler,
+ @NonNull SharedLog log,
+ @Nullable MdnsSocketProvider.NetLinkMonitorCallBack cb) {
+ super(handler, log, cb);
+ }
+
+ @Override
+ public void startMonitoring() { }
+
+ @Override
+ public void stopMonitoring() { }
}
private class TestSocketCallback implements MdnsSocketProvider.SocketCallback {
@@ -208,6 +267,24 @@
}
}
+ private static NetworkCapabilities makeCapabilities(int... transports) {
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ for (int transport : transports) {
+ nc.addTransportType(transport);
+ }
+ return nc;
+ }
+
+ private void postNetworkAvailable(int... transports) {
+ final LinkProperties testLp = new LinkProperties();
+ testLp.setInterfaceName(TEST_IFACE_NAME);
+ testLp.setLinkAddresses(List.of(LINKADDRV4));
+ final NetworkCapabilities testNc = makeCapabilities(transports);
+ mHandler.post(() -> mNetworkCallback.onCapabilitiesChanged(TEST_NETWORK, testNc));
+ mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, testLp));
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+ }
+
@Test
public void testSocketRequestAndUnrequestSocket() {
startMonitoringSockets();
@@ -217,12 +294,7 @@
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
- final LinkProperties testLp = new LinkProperties();
- testLp.setInterfaceName(TEST_IFACE_NAME);
- testLp.setLinkAddresses(List.of(LINKADDRV4));
- mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, testLp));
- HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
- verify(mTestNetworkIfaceWrapper).getNetworkInterface();
+ postNetworkAvailable(TRANSPORT_WIFI);
testCallback1.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4));
final TestSocketCallback testCallback2 = new TestSocketCallback();
@@ -244,7 +316,7 @@
verify(mLocalOnlyIfaceWrapper).getNetworkInterface();
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
- testCallback3.expectedSocketCreatedForNetwork(LOCAL_NETWORK, List.of());
+ testCallback3.expectedSocketCreatedForNetwork(null /* network */, List.of());
mHandler.post(() -> mTetheringEventCallback.onTetheredInterfacesChanged(
List.of(TETHERED_IFACE_NAME)));
@@ -252,7 +324,7 @@
verify(mTetheredIfaceWrapper).getNetworkInterface();
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
- testCallback3.expectedSocketCreatedForNetwork(LOCAL_NETWORK, List.of());
+ testCallback3.expectedSocketCreatedForNetwork(null /* network */, List.of());
mHandler.post(() -> mSocketProvider.unrequestSocket(testCallback1));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
@@ -270,14 +342,95 @@
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
- testCallback3.expectedInterfaceDestroyedForNetwork(LOCAL_NETWORK);
+ testCallback3.expectedInterfaceDestroyedForNetwork(null /* network */);
mHandler.post(() -> mSocketProvider.unrequestSocket(testCallback3));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback1.expectedNoCallback();
testCallback2.expectedNoCallback();
// Expect the socket destroy for tethered interface.
- testCallback3.expectedInterfaceDestroyedForNetwork(LOCAL_NETWORK);
+ testCallback3.expectedInterfaceDestroyedForNetwork(null /* network */);
+ }
+
+ private RtNetlinkAddressMessage createNetworkAddressUpdateNetLink(
+ short msgType, LinkAddress linkAddress, int ifIndex, int flags) {
+ final StructNlMsgHdr nlmsghdr = new StructNlMsgHdr();
+ nlmsghdr.nlmsg_type = msgType;
+ nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+ nlmsghdr.nlmsg_seq = 1;
+
+ InetAddress ip = linkAddress.getAddress();
+
+ final byte family =
+ (byte) ((ip instanceof Inet6Address) ? OsConstants.AF_INET6 : OsConstants.AF_INET);
+ StructIfaddrMsg structIfaddrMsg = new StructIfaddrMsg(family,
+ (short) linkAddress.getPrefixLength(),
+ (short) linkAddress.getFlags(), (short) linkAddress.getScope(), ifIndex);
+
+ return new RtNetlinkAddressMessage(nlmsghdr, structIfaddrMsg, ip,
+ null /* structIfacacheInfo */, flags);
+ }
+
+ @Test
+ public void testDownstreamNetworkAddressUpdateFromNetlink() {
+ startMonitoringSockets();
+ final TestSocketCallback testCallbackAll = new TestSocketCallback();
+ mHandler.post(() -> mSocketProvider.requestSocket(null /* network */, testCallbackAll));
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+
+ // Address add message arrived before the interface is created.
+ RtNetlinkAddressMessage addIpv4AddrMsg = createNetworkAddressUpdateNetLink(
+ NetlinkConstants.RTM_NEWADDR,
+ LINKADDRV4,
+ TETHERED_IFACE_IDX,
+ 0 /* flags */);
+ mHandler.post(
+ () -> mTestSocketNetLinkMonitor.processNetlinkMessage(addIpv4AddrMsg,
+ 0 /* whenMs */));
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+
+ // Interface is created.
+ mHandler.post(() -> mTetheringEventCallback.onTetheredInterfacesChanged(
+ List.of(TETHERED_IFACE_NAME)));
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+ verify(mTetheredIfaceWrapper).getNetworkInterface();
+ testCallbackAll.expectedSocketCreatedForNetwork(null /* network */, List.of(LINKADDRV4));
+
+ // Old Address removed.
+ RtNetlinkAddressMessage removeIpv4AddrMsg = createNetworkAddressUpdateNetLink(
+ NetlinkConstants.RTM_DELADDR,
+ LINKADDRV4,
+ TETHERED_IFACE_IDX,
+ 0 /* flags */);
+ mHandler.post(
+ () -> mTestSocketNetLinkMonitor.processNetlinkMessage(removeIpv4AddrMsg,
+ 0 /* whenMs */));
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+ testCallbackAll.expectedAddressesChangedForNetwork(null /* network */, List.of());
+
+ // New address added.
+ RtNetlinkAddressMessage addIpv6AddrMsg = createNetworkAddressUpdateNetLink(
+ NetlinkConstants.RTM_NEWADDR,
+ LINKADDRV6,
+ TETHERED_IFACE_IDX,
+ 0 /* flags */);
+ mHandler.post(() -> mTestSocketNetLinkMonitor.processNetlinkMessage(addIpv6AddrMsg,
+ 0 /* whenMs */));
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+ testCallbackAll.expectedAddressesChangedForNetwork(null /* network */, List.of(LINKADDRV6));
+
+ // Address updated
+ RtNetlinkAddressMessage updateIpv6AddrMsg = createNetworkAddressUpdateNetLink(
+ NetlinkConstants.RTM_NEWADDR,
+ LINKADDRV6,
+ TETHERED_IFACE_IDX,
+ 1 /* flags */);
+ mHandler.post(
+ () -> mTestSocketNetLinkMonitor.processNetlinkMessage(updateIpv6AddrMsg,
+ 0 /* whenMs */));
+ HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
+ testCallbackAll.expectedAddressesChangedForNetwork(null /* network */,
+ List.of(LINKADDRV6_FLAG_CHANGE));
}
@Test
@@ -289,12 +442,7 @@
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
testCallback.expectedNoCallback();
- final LinkProperties testLp = new LinkProperties();
- testLp.setInterfaceName(TEST_IFACE_NAME);
- testLp.setLinkAddresses(List.of(LINKADDRV4));
- mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, testLp));
- HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
- verify(mTestNetworkIfaceWrapper, times(1)).getNetworkInterface();
+ postNetworkAvailable(TRANSPORT_WIFI);
testCallback.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4));
final LinkProperties newTestLp = new LinkProperties();
@@ -302,7 +450,6 @@
newTestLp.setLinkAddresses(List.of(LINKADDRV4, LINKADDRV6));
mHandler.post(() -> mNetworkCallback.onLinkPropertiesChanged(TEST_NETWORK, newTestLp));
HandlerUtils.waitForIdle(mHandler, DEFAULT_TIMEOUT);
- verify(mTestNetworkIfaceWrapper, times(1)).getNetworkInterface();
testCallback.expectedAddressesChangedForNetwork(
TEST_NETWORK, List.of(LINKADDRV4, LINKADDRV6));
}
@@ -406,4 +553,77 @@
verify(mTestNetworkIfaceWrapper, times(2)).getNetworkInterface();
testCallback.expectedSocketCreatedForNetwork(otherNetwork, List.of(otherAddress));
}
+
+ @Test
+ public void testNoSocketCreatedForCellular() {
+ startMonitoringSockets();
+
+ final TestSocketCallback testCallback = new TestSocketCallback();
+ mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
+
+ postNetworkAvailable(TRANSPORT_CELLULAR);
+ testCallback.expectedNoCallback();
+ }
+
+ @Test
+ public void testNoSocketCreatedForNonMulticastInterface() throws Exception {
+ doReturn(false).when(mTestNetworkIfaceWrapper).supportsMulticast();
+ startMonitoringSockets();
+
+ final TestSocketCallback testCallback = new TestSocketCallback();
+ mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
+
+ postNetworkAvailable(TRANSPORT_BLUETOOTH);
+ testCallback.expectedNoCallback();
+ }
+
+ @Test
+ public void testSocketCreatedForMulticastInterface() throws Exception {
+ doReturn(true).when(mTestNetworkIfaceWrapper).supportsMulticast();
+ startMonitoringSockets();
+
+ final TestSocketCallback testCallback = new TestSocketCallback();
+ mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
+
+ postNetworkAvailable(TRANSPORT_BLUETOOTH);
+ testCallback.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4));
+ }
+
+ @Test
+ public void testNoSocketCreatedForPTPInterface() throws Exception {
+ doReturn(true).when(mTestNetworkIfaceWrapper).isPointToPoint();
+ startMonitoringSockets();
+
+ final TestSocketCallback testCallback = new TestSocketCallback();
+ mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
+
+ postNetworkAvailable(TRANSPORT_BLUETOOTH);
+ testCallback.expectedNoCallback();
+ }
+
+ @Test
+ public void testNoSocketCreatedForVPNInterface() throws Exception {
+ // VPN interfaces generally also have IFF_POINTOPOINT, but even if they don't, they should
+ // not be included even with TRANSPORT_WIFI.
+ doReturn(false).when(mTestNetworkIfaceWrapper).supportsMulticast();
+ startMonitoringSockets();
+
+ final TestSocketCallback testCallback = new TestSocketCallback();
+ mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
+
+ postNetworkAvailable(TRANSPORT_VPN, TRANSPORT_WIFI);
+ testCallback.expectedNoCallback();
+ }
+
+ @Test
+ public void testSocketCreatedForWifiWithoutMulticastFlag() throws Exception {
+ doReturn(false).when(mTestNetworkIfaceWrapper).supportsMulticast();
+ startMonitoringSockets();
+
+ final TestSocketCallback testCallback = new TestSocketCallback();
+ mHandler.post(() -> mSocketProvider.requestSocket(TEST_NETWORK, testCallback));
+
+ postNetworkAvailable(TRANSPORT_WIFI);
+ testCallback.expectedSocketCreatedForNetwork(TEST_NETWORK, List.of(LINKADDRV4));
+ }
}
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
new file mode 100644
index 0000000..f584ed5
--- /dev/null
+++ b/tests/unit/java/com/android/server/connectivity/mdns/util/MdnsUtilsTest.kt
@@ -0,0 +1,68 @@
+/*
+ * 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.connectivity.mdns.util
+
+import android.os.Build
+import com.android.server.connectivity.mdns.util.MdnsUtils.equalsIgnoreDnsCase
+import com.android.server.connectivity.mdns.util.MdnsUtils.toDnsLowerCase
+import com.android.testutils.DevSdkIgnoreRule
+import com.android.testutils.DevSdkIgnoreRunner
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(DevSdkIgnoreRunner::class)
+@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
+class MdnsUtilsTest {
+ @Test
+ fun testToDnsLowerCase() {
+ assertEquals("test", toDnsLowerCase("TEST"))
+ assertEquals("test", toDnsLowerCase("TeSt"))
+ assertEquals("test", toDnsLowerCase("test"))
+ assertEquals("tÉst", toDnsLowerCase("TÉST"))
+ assertEquals("ลฃést", toDnsLowerCase("ลฃést"))
+ // Unicode characters 0x10000 (๐), 0x10001 (๐), 0x10041 (๐)
+ // Note the last 2 bytes of 0x10041 are identical to 'A', but it should remain unchanged.
+ assertEquals("test: -->\ud800\udc00 \ud800\udc01 \ud800\udc41<-- ",
+ toDnsLowerCase("Test: -->\ud800\udc00 \ud800\udc01 \ud800\udc41<-- "))
+ // Also test some characters where the first surrogate is not \ud800
+ assertEquals("test: >\ud83c\udff4\udb40\udc67\udb40\udc62\udb40" +
+ "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<",
+ toDnsLowerCase("Test: >\ud83c\udff4\udb40\udc67\udb40\udc62\udb40" +
+ "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<"))
+ }
+
+ @Test
+ fun testEqualsIgnoreDnsCase() {
+ assertTrue(equalsIgnoreDnsCase("TEST", "Test"))
+ assertTrue(equalsIgnoreDnsCase("TEST", "test"))
+ assertTrue(equalsIgnoreDnsCase("test", "TeSt"))
+ assertTrue(equalsIgnoreDnsCase("Tést", "tést"))
+ assertFalse(equalsIgnoreDnsCase("ลขÉST", "ลฃést"))
+ // Unicode characters 0x10000 (๐), 0x10001 (๐), 0x10041 (๐)
+ // Note the last 2 bytes of 0x10041 are identical to 'A', but it should remain unchanged.
+ assertTrue(equalsIgnoreDnsCase("test: -->\ud800\udc00 \ud800\udc01 \ud800\udc41<-- ",
+ "Test: -->\ud800\udc00 \ud800\udc01 \ud800\udc41<-- "))
+ // Also test some characters where the first surrogate is not \ud800
+ assertTrue(equalsIgnoreDnsCase("test: >\ud83c\udff4\udb40\udc67\udb40\udc62\udb40" +
+ "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<",
+ "Test: >\ud83c\udff4\udb40\udc67\udb40\udc62\udb40" +
+ "\udc77\udb40\udc6c\udb40\udc73\udb40\udc7f<"))
+ }
+}
diff --git a/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
index 04db6d3..63daebc 100644
--- a/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
+++ b/tests/unit/java/com/android/server/net/NetworkStatsFactoryTest.java
@@ -472,8 +472,7 @@
256L, 16L, 512L, 32L, 0L)
.insertEntry(TEST_IFACE, UID_GREEN, SET_DEFAULT, TAG_NONE, 64L, 3L, 1024L, 8L, 0L);
- doReturn(stats).when(mDeps).getNetworkStatsDetail(anyInt(), any(),
- anyInt());
+ doReturn(stats).when(mDeps).getNetworkStatsDetail();
final String[] ifaces = new String[]{TEST_IFACE};
final NetworkStats res = mFactory.readNetworkStatsDetail(UID_ALL, ifaces, TAG_ALL);
@@ -488,8 +487,7 @@
mFactory.removeUidsLocked(removedUids);
// Return empty stats for reading the result of removing uids stats later.
- doReturn(buildEmptyStats()).when(mDeps).getNetworkStatsDetail(anyInt(), any(),
- anyInt());
+ doReturn(buildEmptyStats()).when(mDeps).getNetworkStatsDetail();
final NetworkStats removedUidsStats =
mFactory.readNetworkStatsDetail(UID_ALL, ifaces, TAG_ALL);
@@ -574,8 +572,7 @@
final NetworkStats statsFromResource = parseNetworkStatsFromGoldenSample(resourceId,
24 /* initialSize */, true /* consumeHeader */, false /* checkActive */,
true /* isUidData */);
- doReturn(statsFromResource).when(mDeps).getNetworkStatsDetail(anyInt(), any(),
- anyInt());
+ doReturn(statsFromResource).when(mDeps).getNetworkStatsDetail();
return mFactory.readNetworkStatsDetail();
}