Merge "Restrict access to dangerous methods to <= P" into qt-dev
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 06c32c6..68826cb 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -93,6 +93,23 @@
public static final int FLAG_NO_CACHE_STORE = 1 << 1;
public static final int FLAG_NO_CACHE_LOOKUP = 1 << 2;
+ @IntDef(prefix = { "ERROR_" }, value = {
+ ERROR_PARSE,
+ ERROR_SYSTEM
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface DnsError {}
+ /**
+ * Indicates that there was an error parsing the response the query.
+ * The cause of this error is available via getCause() and is a ParseException.
+ */
+ public static final int ERROR_PARSE = 0;
+ /**
+ * Indicates that there was an error sending the query.
+ * The cause of this error is available via getCause() and is an ErrnoException.
+ */
+ public static final int ERROR_SYSTEM = 1;
+
private static final int NETID_UNSET = 0;
private static final DnsResolver sInstance = new DnsResolver();
@@ -107,97 +124,57 @@
private DnsResolver() {}
/**
- * Answer parser for parsing raw answers
+ * Base interface for answer callbacks
*
- * @param <T> The type of the parsed answer
+ * @param <T> The type of the answer
*/
- public interface AnswerParser<T> {
- /**
- * Creates a <T> answer by parsing the given raw answer.
- *
- * @param rawAnswer the raw answer to be parsed
- * @return a parsed <T> answer
- * @throws ParseException if parsing failed
- */
- @NonNull T parse(@NonNull byte[] rawAnswer) throws ParseException;
- }
-
- /**
- * Base class for answer callbacks
- *
- * @param <T> The type of the parsed answer
- */
- public abstract static class AnswerCallback<T> {
- /** @hide */
- public final AnswerParser<T> parser;
-
- public AnswerCallback(@NonNull AnswerParser<T> parser) {
- this.parser = parser;
- };
-
+ public interface Callback<T> {
/**
* Success response to
- * {@link android.net.DnsResolver#query query()}.
+ * {@link android.net.DnsResolver#query query()} or
+ * {@link android.net.DnsResolver#rawQuery rawQuery()}.
*
* Invoked when the answer to a query was successfully parsed.
*
- * @param answer parsed answer to the query.
+ * @param answer <T> answer to the query.
+ * @param rcode The response code in the DNS response.
*
* {@see android.net.DnsResolver#query query()}
*/
- public abstract void onAnswer(@NonNull T answer);
-
+ void onAnswer(@NonNull T answer, int rcode);
/**
* Error response to
- * {@link android.net.DnsResolver#query query()}.
+ * {@link android.net.DnsResolver#query query()} or
+ * {@link android.net.DnsResolver#rawQuery rawQuery()}.
*
* Invoked when there is no valid answer to
* {@link android.net.DnsResolver#query query()}
+ * {@link android.net.DnsResolver#rawQuery rawQuery()}.
*
- * @param exception a {@link ParseException} object with additional
+ * @param error a {@link DnsException} object with additional
* detail regarding the failure
*/
- public abstract void onParseException(@NonNull ParseException exception);
-
- /**
- * Error response to
- * {@link android.net.DnsResolver#query query()}.
- *
- * Invoked if an error happens when
- * issuing the DNS query or receiving the result.
- * {@link android.net.DnsResolver#query query()}
- *
- * @param exception an {@link ErrnoException} object with additional detail
- * regarding the failure
- */
- public abstract void onQueryException(@NonNull ErrnoException exception);
+ void onError(@NonNull DnsException error);
}
/**
- * Callback for receiving raw answers
+ * Class to represent DNS error
*/
- public abstract static class RawAnswerCallback extends AnswerCallback<byte[]> {
- public RawAnswerCallback() {
- super(rawAnswer -> rawAnswer);
- }
- }
+ public static class DnsException extends Exception {
+ /**
+ * DNS error code as one of the ERROR_* constants
+ */
+ @DnsError public final int code;
- /**
- * Callback for receiving parsed {@link InetAddress} answers
- *
- * Note that if the answer does not contain any IP addresses,
- * onAnswer will be called with an empty list.
- */
- public abstract static class InetAddressAnswerCallback
- extends AnswerCallback<List<InetAddress>> {
- public InetAddressAnswerCallback() {
- super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses());
+ DnsException(@DnsError int code, @Nullable Throwable cause) {
+ super(cause);
+ this.code = code;
}
}
/**
* Send a raw DNS query.
- * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
+ * The answer will be provided asynchronously through the provided {@link Callback}.
*
* @param network {@link Network} specifying which network to query on.
* {@code null} for query on default network.
@@ -206,13 +183,13 @@
* @param executor The {@link Executor} that the callback should be executed on.
* @param cancellationSignal used by the caller to signal if the query should be
* cancelled. May be {@code null}.
- * @param callback an {@link AnswerCallback} which will be called to notify the caller
+ * @param callback a {@link Callback} which will be called to notify the caller
* of the result of dns query.
*/
- public <T> void query(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
+ public void rawQuery(@Nullable Network network, @NonNull byte[] query, @QueryFlag int flags,
@NonNull @CallbackExecutor Executor executor,
@Nullable CancellationSignal cancellationSignal,
- @NonNull AnswerCallback<T> callback) {
+ @NonNull Callback<? super byte[]> callback) {
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
@@ -220,11 +197,9 @@
final FileDescriptor queryfd;
try {
queryfd = resNetworkSend((network != null
- ? network.netId : NETID_UNSET), query, query.length, flags);
+ ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags);
} catch (ErrnoException e) {
- executor.execute(() -> {
- callback.onQueryException(e);
- });
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
@@ -237,7 +212,7 @@
/**
* Send a DNS query with the specified name, class and query type.
- * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
+ * The answer will be provided asynchronously through the provided {@link Callback}.
*
* @param network {@link Network} specifying which network to query on.
* {@code null} for query on default network.
@@ -248,14 +223,14 @@
* @param executor The {@link Executor} that the callback should be executed on.
* @param cancellationSignal used by the caller to signal if the query should be
* cancelled. May be {@code null}.
- * @param callback an {@link AnswerCallback} which will be called to notify the caller
+ * @param callback a {@link Callback} which will be called to notify the caller
* of the result of dns query.
*/
- public <T> void query(@Nullable Network network, @NonNull String domain,
+ public void rawQuery(@Nullable Network network, @NonNull String domain,
@QueryClass int nsClass, @QueryType int nsType, @QueryFlag int flags,
@NonNull @CallbackExecutor Executor executor,
@Nullable CancellationSignal cancellationSignal,
- @NonNull AnswerCallback<T> callback) {
+ @NonNull Callback<? super byte[]> callback) {
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
@@ -263,11 +238,9 @@
final FileDescriptor queryfd;
try {
queryfd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
+ ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags);
} catch (ErrnoException e) {
- executor.execute(() -> {
- callback.onQueryException(e);
- });
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
synchronized (lock) {
@@ -277,27 +250,28 @@
}
}
- private class InetAddressAnswerAccumulator extends InetAddressAnswerCallback {
+ private class InetAddressAnswerAccumulator implements Callback<byte[]> {
private final List<InetAddress> mAllAnswers;
- private ParseException mParseException;
- private ErrnoException mErrnoException;
- private final InetAddressAnswerCallback mUserCallback;
+ private int mRcode;
+ private DnsException mDnsException;
+ private final Callback<? super List<InetAddress>> mUserCallback;
private final int mTargetAnswerCount;
private int mReceivedAnswerCount = 0;
- InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerCallback callback) {
+ InetAddressAnswerAccumulator(int size,
+ @NonNull Callback<? super List<InetAddress>> callback) {
mTargetAnswerCount = size;
mAllAnswers = new ArrayList<>();
mUserCallback = callback;
}
- private boolean maybeReportException() {
- if (mErrnoException != null) {
- mUserCallback.onQueryException(mErrnoException);
+ private boolean maybeReportError() {
+ if (mRcode != 0) {
+ mUserCallback.onAnswer(mAllAnswers, mRcode);
return true;
}
- if (mParseException != null) {
- mUserCallback.onParseException(mParseException);
+ if (mDnsException != null) {
+ mUserCallback.onError(mDnsException);
return true;
}
return false;
@@ -305,34 +279,43 @@
private void maybeReportAnswer() {
if (++mReceivedAnswerCount != mTargetAnswerCount) return;
- if (mAllAnswers.isEmpty() && maybeReportException()) return;
+ if (mAllAnswers.isEmpty() && maybeReportError()) return;
// TODO: Do RFC6724 sort.
- mUserCallback.onAnswer(mAllAnswers);
+ mUserCallback.onAnswer(mAllAnswers, mRcode);
}
@Override
- public void onAnswer(@NonNull List<InetAddress> answer) {
- mAllAnswers.addAll(answer);
+ public void onAnswer(@NonNull byte[] answer, int rcode) {
+ // If at least one query succeeded, return an rcode of 0.
+ // Otherwise, arbitrarily return the first rcode received.
+ if (mReceivedAnswerCount == 0 || rcode == 0) {
+ mRcode = rcode;
+ }
+ try {
+ mAllAnswers.addAll(new DnsAddressAnswer(answer).getAddresses());
+ } catch (ParseException e) {
+ mDnsException = new DnsException(ERROR_PARSE, e);
+ }
maybeReportAnswer();
}
@Override
- public void onParseException(@NonNull ParseException e) {
- mParseException = e;
- maybeReportAnswer();
- }
-
- @Override
- public void onQueryException(@NonNull ErrnoException e) {
- mErrnoException = e;
+ public void onError(@NonNull DnsException error) {
+ mDnsException = error;
maybeReportAnswer();
}
}
/**
- * Send a DNS query with the specified name, get back a set of InetAddresses asynchronously.
- * The answer will be provided asynchronously through the provided
- * {@link InetAddressAnswerCallback}.
+ * Send a DNS query with the specified name on a network with both IPv4 and IPv6,
+ * get back a set of InetAddresses asynchronously.
+ *
+ * This method will examine the connection ability on given network, and query IPv4
+ * and IPv6 if connection is available.
+ *
+ * If at least one query succeeded with valid answer, rcode will be 0
+ *
+ * The answer will be provided asynchronously through the provided {@link Callback}.
*
* @param network {@link Network} specifying which network to query on.
* {@code null} for query on default network.
@@ -341,13 +324,13 @@
* @param executor The {@link Executor} that the callback should be executed on.
* @param cancellationSignal used by the caller to signal if the query should be
* cancelled. May be {@code null}.
- * @param callback an {@link InetAddressAnswerCallback} which will be called to notify the
+ * @param callback a {@link Callback} which will be called to notify the
* caller of the result of dns query.
*/
public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
@NonNull @CallbackExecutor Executor executor,
@Nullable CancellationSignal cancellationSignal,
- @NonNull InetAddressAnswerCallback callback) {
+ @NonNull Callback<? super List<InetAddress>> callback) {
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
@@ -363,11 +346,10 @@
if (queryIpv6) {
try {
v6fd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
+ ? network.getNetIdForResolv() : NETID_UNSET),
+ domain, CLASS_IN, TYPE_AAAA, flags);
} catch (ErrnoException e) {
- executor.execute(() -> {
- callback.onQueryException(e);
- });
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
queryCount++;
@@ -377,17 +359,18 @@
// Avoiding gateways drop packets if queries are sent too close together
try {
Thread.sleep(SLEEP_TIME_MS);
- } catch (InterruptedException ex) { }
+ } catch (InterruptedException ex) {
+ Thread.currentThread().interrupt();
+ }
if (queryIpv4) {
try {
v4fd = resNetworkQuery((network != null
- ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
+ ? network.getNetIdForResolv() : NETID_UNSET),
+ domain, CLASS_IN, TYPE_A, flags);
} catch (ErrnoException e) {
if (queryIpv6) resNetworkCancel(v6fd); // Closes fd, marks it invalid.
- executor.execute(() -> {
- callback.onQueryException(e);
- });
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
return;
}
queryCount++;
@@ -413,34 +396,89 @@
}
}
- private <T> void registerFDListener(@NonNull Executor executor,
- @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback,
+ /**
+ * Send a DNS query with the specified name and query type, get back a set of
+ * InetAddresses asynchronously.
+ *
+ * The answer will be provided asynchronously through the provided {@link Callback}.
+ *
+ * @param network {@link Network} specifying which network to query on.
+ * {@code null} for query on default network.
+ * @param domain domain name to query
+ * @param nsType dns resource record (RR) type as one of the TYPE_* constants
+ * @param flags flags as a combination of the FLAGS_* constants
+ * @param executor The {@link Executor} that the callback should be executed on.
+ * @param cancellationSignal used by the caller to signal if the query should be
+ * cancelled. May be {@code null}.
+ * @param callback a {@link Callback} which will be called to notify the caller
+ * of the result of dns query.
+ */
+ public void query(@Nullable Network network, @NonNull String domain,
+ @QueryType int nsType, @QueryFlag int flags,
+ @NonNull @CallbackExecutor Executor executor,
+ @Nullable CancellationSignal cancellationSignal,
+ @NonNull Callback<? super List<InetAddress>> callback) {
+ if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+ return;
+ }
+ final Object lock = new Object();
+ final FileDescriptor queryfd;
+ try {
+ queryfd = resNetworkQuery((network != null
+ ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags);
+ } catch (ErrnoException e) {
+ executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
+ return;
+ }
+ final InetAddressAnswerAccumulator accumulator =
+ new InetAddressAnswerAccumulator(1, callback);
+ synchronized (lock) {
+ registerFDListener(executor, queryfd, accumulator, cancellationSignal, lock);
+ if (cancellationSignal == null) return;
+ addCancellationSignal(cancellationSignal, queryfd, lock);
+ }
+ }
+
+ /**
+ * Class to retrieve DNS response
+ *
+ * @hide
+ */
+ public static final class DnsResponse {
+ public final @NonNull byte[] answerbuf;
+ public final int rcode;
+ public DnsResponse(@NonNull byte[] answerbuf, int rcode) {
+ this.answerbuf = answerbuf;
+ this.rcode = rcode;
+ }
+ }
+
+ private void registerFDListener(@NonNull Executor executor,
+ @NonNull FileDescriptor queryfd, @NonNull Callback<? super byte[]> answerCallback,
@Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
queryfd,
FD_EVENTS,
(fd, events) -> {
executor.execute(() -> {
+ DnsResponse resp = null;
+ ErrnoException exception = null;
synchronized (lock) {
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
return;
}
- byte[] answerbuf = null;
try {
- answerbuf = resNetworkResult(fd); // Closes fd, marks it invalid.
+ resp = resNetworkResult(fd); // Closes fd, marks it invalid.
} catch (ErrnoException e) {
Log.e(TAG, "resNetworkResult:" + e.toString());
- answerCallback.onQueryException(e);
- return;
- }
-
- try {
- answerCallback.onAnswer(
- answerCallback.parser.parse(answerbuf));
- } catch (ParseException e) {
- answerCallback.onParseException(e);
+ exception = e;
}
}
+ if (exception != null) {
+ answerCallback.onError(new DnsException(ERROR_SYSTEM, exception));
+ return;
+ }
+ answerCallback.onAnswer(resp.answerbuf, resp.rcode);
});
// Unregister this fd listener
return 0;
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index db87c97..c06a132 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -145,9 +145,10 @@
/**
* DNS resolver series jni method.
* Read a result for the query associated with the {@code fd}.
- * @return a byte array containing blob answer
+ * @return DnsResponse containing blob answer and rcode
*/
- public static native byte[] resNetworkResult(FileDescriptor fd) throws ErrnoException;
+ public static native DnsResolver.DnsResponse resNetworkResult(FileDescriptor fd)
+ throws ErrnoException;
/**
* DNS resolver series jni method.
diff --git a/core/java/android/net/TestNetworkInterface.java b/core/java/android/net/TestNetworkInterface.java
index 30e68f5..8455083 100644
--- a/core/java/android/net/TestNetworkInterface.java
+++ b/core/java/android/net/TestNetworkInterface.java
@@ -27,8 +27,6 @@
*/
@TestApi
public final class TestNetworkInterface implements Parcelable {
- private static final String TAG = "TestNetworkInterface";
-
private final ParcelFileDescriptor mFileDescriptor;
private final String mInterfaceName;
diff --git a/core/java/android/net/TestNetworkManager.java b/core/java/android/net/TestNetworkManager.java
index cd58e66..e274005 100644
--- a/core/java/android/net/TestNetworkManager.java
+++ b/core/java/android/net/TestNetworkManager.java
@@ -17,7 +17,6 @@
import android.annotation.NonNull;
import android.annotation.TestApi;
-import android.content.Context;
import android.os.IBinder;
import android.os.RemoteException;
@@ -33,11 +32,9 @@
@NonNull private static final String TAG = TestNetworkManager.class.getSimpleName();
@NonNull private final ITestNetworkManager mService;
- @NonNull private final Context mContext;
/** @hide */
- public TestNetworkManager(@NonNull Context context, @NonNull ITestNetworkManager service) {
- mContext = Preconditions.checkNotNull(context, "missing Context");
+ public TestNetworkManager(@NonNull ITestNetworkManager service) {
mService = Preconditions.checkNotNull(service, "missing ITestNetworkManager");
}
@@ -88,4 +85,21 @@
throw e.rethrowFromSystemServer();
}
}
+
+ /**
+ * Create a tap interface for testing purposes
+ *
+ * @return A ParcelFileDescriptor of the underlying TAP interface. Close this to tear down the
+ * TAP interface.
+ * @hide
+ */
+ @TestApi
+ public TestNetworkInterface createTapInterface() {
+ try {
+ return mService.createTapInterface();
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
}
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index dd754f3..28c59db 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -270,7 +270,7 @@
return jniCreateFileDescriptor(env, fd);
}
-static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
+static jobject android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz, jobject javaFd) {
int fd = jniGetFDFromFileDescriptor(env, javaFd);
int rcode;
std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
@@ -291,7 +291,10 @@
reinterpret_cast<jbyte*>(buf.data()));
}
- return answer;
+ jclass class_DnsResponse = env->FindClass("android/net/DnsResolver$DnsResponse");
+ jmethodID ctor = env->GetMethodID(class_DnsResponse, "<init>", "([BI)V");
+
+ return env->NewObject(class_DnsResponse, ctor, answer, rcode);
}
static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
@@ -354,7 +357,7 @@
{ "setupRaSocket", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_setupRaSocket },
{ "resNetworkSend", "(I[BII)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkSend },
{ "resNetworkQuery", "(ILjava/lang/String;III)Ljava/io/FileDescriptor;", (void*) android_net_utils_resNetworkQuery },
- { "resNetworkResult", "(Ljava/io/FileDescriptor;)[B", (void*) android_net_utils_resNetworkResult },
+ { "resNetworkResult", "(Ljava/io/FileDescriptor;)Landroid/net/DnsResolver$DnsResponse;", (void*) android_net_utils_resNetworkResult },
{ "resNetworkCancel", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_resNetworkCancel },
};
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6405254..e4c39cc 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -108,7 +108,6 @@
import android.net.metrics.IpConnectivityLog;
import android.net.metrics.NetworkEvent;
import android.net.netlink.InetDiagMessage;
-import android.net.shared.NetworkMonitorUtils;
import android.net.shared.PrivateDnsConfig;
import android.net.util.MultinetworkPolicyTracker;
import android.net.util.NetdService;
@@ -133,6 +132,7 @@
import android.os.ShellCallback;
import android.os.ShellCommand;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
@@ -237,6 +237,16 @@
private static final boolean LOGD_BLOCKED_NETWORKINFO = true;
+ /**
+ * Default URL to use for {@link #getCaptivePortalServerUrl()}. This should not be changed
+ * by OEMs for configuration purposes, as this value is overridden by
+ * Settings.Global.CAPTIVE_PORTAL_HTTP_URL.
+ * R.string.config_networkCaptivePortalServerUrl should be overridden instead for this purpose
+ * (preferably via runtime resource overlays).
+ */
+ private static final String DEFAULT_CAPTIVE_PORTAL_HTTP_URL =
+ "http://connectivitycheck.gstatic.com/generate_204";
+
// TODO: create better separation between radio types and network types
// how long to wait before switching back to a radio's default network
@@ -1628,8 +1638,11 @@
*/
private boolean disallowedBecauseSystemCaller() {
// TODO: start throwing a SecurityException when GnssLocationProvider stops calling
- // requestRouteToHost.
- if (isSystem(Binder.getCallingUid())) {
+ // requestRouteToHost. In Q, GnssLocationProvider is changed to not call requestRouteToHost
+ // for devices launched with Q and above. However, existing devices upgrading to Q and
+ // above must continued to be supported for few more releases.
+ if (isSystem(Binder.getCallingUid()) && SystemProperties.getInt(
+ "ro.product.first_api_level", 0) > Build.VERSION_CODES.P) {
log("This method exists only for app backwards compatibility"
+ " and must not be called by system services.");
return true;
@@ -1767,11 +1780,8 @@
// caller type. Need to re-factor NetdEventListenerService to allow multiple
// NetworkMonitor registrants.
if (nai != null && nai.satisfies(mDefaultRequest)) {
- try {
- nai.networkMonitor().notifyDnsResponse(returnCode);
- } catch (RemoteException e) {
- e.rethrowFromSystemServer();
- }
+ Binder.withCleanCallingIdentity(() ->
+ nai.networkMonitor().notifyDnsResponse(returnCode));
}
}
@@ -6542,7 +6552,7 @@
uid, newRules, metered, mRestrictBackground);
}
if (oldBlocked == newBlocked) {
- return;
+ continue;
}
final int arg = encodeBool(newBlocked);
for (int i = 0; i < nai.numNetworkRequests(); i++) {
@@ -6700,9 +6710,20 @@
@Override
public String getCaptivePortalServerUrl() {
enforceConnectivityInternalPermission();
- final String defaultUrl = mContext.getResources().getString(
- R.string.config_networkDefaultCaptivePortalServerUrl);
- return NetworkMonitorUtils.getCaptivePortalServerHttpUrl(mContext, defaultUrl);
+ String settingUrl = mContext.getResources().getString(
+ R.string.config_networkCaptivePortalServerUrl);
+
+ if (!TextUtils.isEmpty(settingUrl)) {
+ return settingUrl;
+ }
+
+ settingUrl = Settings.Global.getString(mContext.getContentResolver(),
+ Settings.Global.CAPTIVE_PORTAL_HTTP_URL);
+ if (!TextUtils.isEmpty(settingUrl)) {
+ return settingUrl;
+ }
+
+ return DEFAULT_CAPTIVE_PORTAL_HTTP_URL;
}
@Override
diff --git a/services/core/java/com/android/server/TestNetworkService.java b/services/core/java/com/android/server/TestNetworkService.java
index e64ab78..40bf7bc 100644
--- a/services/core/java/com/android/server/TestNetworkService.java
+++ b/services/core/java/com/android/server/TestNetworkService.java
@@ -60,6 +60,7 @@
@NonNull private static final String TAG = TestNetworkService.class.getSimpleName();
@NonNull private static final String TEST_NETWORK_TYPE = "TEST_NETWORK";
@NonNull private static final String TEST_TUN_PREFIX = "testtun";
+ @NonNull private static final String TEST_TAP_PREFIX = "testtap";
@NonNull private static final AtomicInteger sTestTunIndex = new AtomicInteger();
@NonNull private final Context mContext;
@@ -70,7 +71,7 @@
@NonNull private final Handler mHandler;
// Native method stubs
- private static native int jniCreateTun(@NonNull String iface);
+ private static native int jniCreateTunTap(boolean isTun, @NonNull String iface);
@VisibleForTesting
protected TestNetworkService(
@@ -85,23 +86,23 @@
}
/**
- * Create a TUN interface with the given interface name and link addresses
+ * Create a TUN or TAP interface with the given interface name and link addresses
*
- * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
- * TUN interface.
+ * <p>This method will return the FileDescriptor to the interface. Close it to tear down the
+ * interface.
*/
- @Override
- public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+ private TestNetworkInterface createInterface(boolean isTun, LinkAddress[] linkAddrs) {
enforceTestNetworkPermissions(mContext);
checkNotNull(linkAddrs, "missing linkAddrs");
- String iface = TEST_TUN_PREFIX + sTestTunIndex.getAndIncrement();
+ String ifacePrefix = isTun ? TEST_TUN_PREFIX : TEST_TAP_PREFIX;
+ String iface = ifacePrefix + sTestTunIndex.getAndIncrement();
return Binder.withCleanCallingIdentity(
() -> {
try {
ParcelFileDescriptor tunIntf =
- ParcelFileDescriptor.adoptFd(jniCreateTun(iface));
+ ParcelFileDescriptor.adoptFd(jniCreateTunTap(isTun, iface));
for (LinkAddress addr : linkAddrs) {
mNetd.interfaceAddAddress(
iface,
@@ -116,6 +117,28 @@
});
}
+ /**
+ * Create a TUN interface with the given interface name and link addresses
+ *
+ * <p>This method will return the FileDescriptor to the TUN interface. Close it to tear down the
+ * TUN interface.
+ */
+ @Override
+ public TestNetworkInterface createTunInterface(@NonNull LinkAddress[] linkAddrs) {
+ return createInterface(true, linkAddrs);
+ }
+
+ /**
+ * Create a TAP interface with the given interface name
+ *
+ * <p>This method will return the FileDescriptor to the TAP interface. Close it to tear down the
+ * TAP interface.
+ */
+ @Override
+ public TestNetworkInterface createTapInterface() {
+ return createInterface(false, new LinkAddress[0]);
+ }
+
// Tracker for TestNetworkAgents
@GuardedBy("mTestNetworkTracker")
@NonNull
@@ -310,7 +333,7 @@
public void teardownTestNetwork(int netId) {
enforceTestNetworkPermissions(mContext);
- TestNetworkAgent agent;
+ final TestNetworkAgent agent;
synchronized (mTestNetworkTracker) {
agent = mTestNetworkTracker.get(netId);
}
@@ -325,14 +348,10 @@
agent.teardown();
}
- // STOPSHIP: Change this back to android.Manifest.permission.MANAGE_TEST_NETWORKS
- private static final String PERMISSION_NAME = "dummy";
+ private static final String PERMISSION_NAME =
+ android.Manifest.permission.MANAGE_TEST_NETWORKS;
public static void enforceTestNetworkPermissions(@NonNull Context context) {
- // STOPSHIP: Re-enable these checks. Disabled until adoptShellPermissionIdentity() can be
- // called from CTS test code.
- if (false) {
- context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
- }
+ context.enforceCallingOrSelfPermission(PERMISSION_NAME, "TestNetworkService");
}
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 948c690..a1a8e35 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -33,6 +33,7 @@
import android.util.Pair;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.TrafficStatsConstants;
import libcore.io.IoUtils;
@@ -381,7 +382,8 @@
protected void setupSocket(
int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
throws ErrnoException, IOException {
- final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+ final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+ TrafficStatsConstants.TAG_SYSTEM_PROBE);
try {
mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
} finally {
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index da1360d..b694602 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -469,7 +469,10 @@
*/
@VisibleForTesting
void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
-
+ if (mNetd == null) {
+ Log.e(TAG, "Failed to get the netd service");
+ return;
+ }
ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
diff --git a/services/core/jni/com_android_server_TestNetworkService.cpp b/services/core/jni/com_android_server_TestNetworkService.cpp
index b90ff23..36a6fde 100644
--- a/services/core/jni/com_android_server_TestNetworkService.cpp
+++ b/services/core/jni/com_android_server_TestNetworkService.cpp
@@ -54,12 +54,12 @@
jniThrowException(env, "java/lang/IllegalStateException", msg.c_str());
}
-static int createTunInterface(JNIEnv* env, const char* iface) {
+static int createTunTapInterface(JNIEnv* env, bool isTun, const char* iface) {
base::unique_fd tun(open("/dev/tun", O_RDWR | O_NONBLOCK));
ifreq ifr{};
// Allocate interface.
- ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+ ifr.ifr_flags = (isTun ? IFF_TUN : IFF_TAP) | IFF_NO_PI;
strlcpy(ifr.ifr_name, iface, IFNAMSIZ);
if (ioctl(tun.get(), TUNSETIFF, &ifr)) {
throwException(env, errno, "allocating", ifr.ifr_name);
@@ -80,23 +80,23 @@
//------------------------------------------------------------------------------
-static jint create(JNIEnv* env, jobject /* thiz */, jstring jIface) {
+static jint create(JNIEnv* env, jobject /* thiz */, jboolean isTun, jstring jIface) {
ScopedUtfChars iface(env, jIface);
if (!iface.c_str()) {
jniThrowNullPointerException(env, "iface");
return -1;
}
- int tun = createTunInterface(env, iface.c_str());
+ int tun = createTunTapInterface(env, isTun, iface.c_str());
- // Any exceptions will be thrown from the createTunInterface call
+ // Any exceptions will be thrown from the createTunTapInterface call
return tun;
}
//------------------------------------------------------------------------------
static const JNINativeMethod gMethods[] = {
- {"jniCreateTun", "(Ljava/lang/String;)I", (void*)create},
+ {"jniCreateTunTap", "(ZLjava/lang/String;)I", (void*)create},
};
int register_android_server_TestNetworkService(JNIEnv* env) {
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
index 70b4089..c8ef82e 100644
--- a/tests/net/Android.bp
+++ b/tests/net/Android.bp
@@ -4,6 +4,7 @@
java_defaults {
name: "FrameworksNetTests-jni-defaults",
static_libs: [
+ "FrameworksNetCommonTests",
"frameworks-base-testutils",
"framework-protos",
"androidx.test.rules",
diff --git a/tests/net/common/Android.bp b/tests/net/common/Android.bp
new file mode 100644
index 0000000..0a1ac75
--- /dev/null
+++ b/tests/net/common/Android.bp
@@ -0,0 +1,29 @@
+//
+// Copyright (C) 2019 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.
+//
+
+// Tests in this folder are included both in unit tests and CTS.
+// They must be fast and stable, and exercise public or test APIs.
+java_library {
+ name: "FrameworksNetCommonTests",
+ srcs: ["java/**/*.java"],
+ static_libs: [
+ "androidx.test.rules",
+ "junit",
+ ],
+ libs: [
+ "android.test.base.stubs",
+ ],
+}
\ No newline at end of file
diff --git a/tests/net/java/android/net/IpPrefixTest.java b/tests/net/common/java/android/net/IpPrefixTest.java
similarity index 84%
rename from tests/net/java/android/net/IpPrefixTest.java
rename to tests/net/common/java/android/net/IpPrefixTest.java
index abf019a..719960d 100644
--- a/tests/net/java/android/net/IpPrefixTest.java
+++ b/tests/net/common/java/android/net/IpPrefixTest.java
@@ -39,7 +39,7 @@
@SmallTest
public class IpPrefixTest {
- private static InetAddress Address(String addr) {
+ private static InetAddress address(String addr) {
return InetAddress.parseNumericAddress(addr);
}
@@ -58,59 +58,59 @@
try {
p = new IpPrefix((byte[]) null, 9);
fail("Expected NullPointerException: null byte array");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix((InetAddress) null, 10);
fail("Expected NullPointerException: null InetAddress");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix((String) null);
fail("Expected NullPointerException: null String");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
byte[] b2 = {1, 2, 3, 4, 5};
p = new IpPrefix(b2, 29);
fail("Expected IllegalArgumentException: invalid array length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.4");
fail("Expected IllegalArgumentException: no prefix length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.4/");
fail("Expected IllegalArgumentException: empty prefix length");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("foo/32");
fail("Expected IllegalArgumentException: invalid address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1/32");
fail("Expected IllegalArgumentException: deprecated IPv4 format");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("1.2.3.256/32");
fail("Expected IllegalArgumentException: invalid IPv4 address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("foo/32");
fail("Expected IllegalArgumentException: non-address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
try {
p = new IpPrefix("f00:::/32");
fail("Expected IllegalArgumentException: invalid IPv6 address");
- } catch(IllegalArgumentException expected) {}
+ } catch (IllegalArgumentException expected) { }
}
@Test
@@ -132,17 +132,17 @@
try {
p = new IpPrefix(IPV4_BYTES, 33);
fail("Expected IllegalArgumentException: invalid prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV4_BYTES, 128);
fail("Expected IllegalArgumentException: invalid prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV4_BYTES, -1);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
p = new IpPrefix(IPV6_BYTES, 128);
assertEquals("2001:db8:dead:beef:f00::a0/128", p.toString());
@@ -162,12 +162,12 @@
try {
p = new IpPrefix(IPV6_BYTES, -1);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
try {
p = new IpPrefix(IPV6_BYTES, 129);
fail("Expected IllegalArgumentException: negative prefix length");
- } catch(RuntimeException expected) {}
+ } catch (RuntimeException expected) { }
}
@@ -226,28 +226,28 @@
@Test
public void testContainsInetAddress() {
IpPrefix p = new IpPrefix("2001:db8:f00::ace:d00d/127");
- assertTrue(p.contains(Address("2001:db8:f00::ace:d00c")));
- assertTrue(p.contains(Address("2001:db8:f00::ace:d00d")));
- assertFalse(p.contains(Address("2001:db8:f00::ace:d00e")));
- assertFalse(p.contains(Address("2001:db8:f00::bad:d00d")));
- assertFalse(p.contains(Address("2001:4868:4860::8888")));
- assertFalse(p.contains(Address("8.8.8.8")));
+ assertTrue(p.contains(address("2001:db8:f00::ace:d00c")));
+ assertTrue(p.contains(address("2001:db8:f00::ace:d00d")));
+ assertFalse(p.contains(address("2001:db8:f00::ace:d00e")));
+ assertFalse(p.contains(address("2001:db8:f00::bad:d00d")));
+ assertFalse(p.contains(address("2001:4868:4860::8888")));
+ assertFalse(p.contains(address("8.8.8.8")));
p = new IpPrefix("192.0.2.0/23");
- assertTrue(p.contains(Address("192.0.2.43")));
- assertTrue(p.contains(Address("192.0.3.21")));
- assertFalse(p.contains(Address("192.0.0.21")));
- assertFalse(p.contains(Address("8.8.8.8")));
- assertFalse(p.contains(Address("2001:4868:4860::8888")));
+ assertTrue(p.contains(address("192.0.2.43")));
+ assertTrue(p.contains(address("192.0.3.21")));
+ assertFalse(p.contains(address("192.0.0.21")));
+ assertFalse(p.contains(address("8.8.8.8")));
+ assertFalse(p.contains(address("2001:4868:4860::8888")));
IpPrefix ipv6Default = new IpPrefix("::/0");
- assertTrue(ipv6Default.contains(Address("2001:db8::f00")));
- assertFalse(ipv6Default.contains(Address("192.0.2.1")));
+ assertTrue(ipv6Default.contains(address("2001:db8::f00")));
+ assertFalse(ipv6Default.contains(address("192.0.2.1")));
IpPrefix ipv4Default = new IpPrefix("0.0.0.0/0");
- assertTrue(ipv4Default.contains(Address("255.255.255.255")));
- assertTrue(ipv4Default.contains(Address("192.0.2.1")));
- assertFalse(ipv4Default.contains(Address("2001:db8::f00")));
+ assertTrue(ipv4Default.contains(address("255.255.255.255")));
+ assertTrue(ipv4Default.contains(address("192.0.2.1")));
+ assertFalse(ipv4Default.contains(address("2001:db8::f00")));
}
@Test
@@ -315,10 +315,10 @@
p = new IpPrefix(b, random.nextInt(129));
}
if (p.equals(oldP)) {
- assertEquals(p.hashCode(), oldP.hashCode());
+ assertEquals(p.hashCode(), oldP.hashCode());
}
if (p.hashCode() != oldP.hashCode()) {
- assertNotEquals(p, oldP);
+ assertNotEquals(p, oldP);
}
}
}
@@ -332,9 +332,9 @@
new IpPrefix("0.0.0.0/0"),
};
for (int i = 0; i < prefixes.length; i++) {
- for (int j = i + 1; j < prefixes.length; j++) {
- assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
- }
+ for (int j = i + 1; j < prefixes.length; j++) {
+ assertNotEquals(prefixes[i].hashCode(), prefixes[j].hashCode());
+ }
}
}
@@ -371,8 +371,8 @@
}
public void assertParcelingIsLossless(IpPrefix p) {
- IpPrefix p2 = passThroughParcel(p);
- assertEquals(p, p2);
+ IpPrefix p2 = passThroughParcel(p);
+ assertEquals(p, p2);
}
@Test
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
index 68ff777..22a2c94 100644
--- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
@@ -134,11 +135,11 @@
IBinder binderMock = mock(IBinder.class);
doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
- RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
-
- // Verify that cleanup is performed (Spy limitations prevent verification of method calls
- // for binder death scenario; check refcount to determine if cleanup was performed.)
- assertEquals(-1, refcountedResource.mRefCount);
+ try {
+ getTestRefcountedResource(binderMock);
+ fail("Expected exception to propogate when binder fails to link to death");
+ } catch (RuntimeException expected) {
+ }
}
@Test
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index b5c3e92..4a35015 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -156,10 +156,21 @@
@Test
public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
- int localport = findUnusedPort();
+ int localport = -1;
+ IpSecUdpEncapResponse udpEncapResp = null;
- IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
+ localport = findUnusedPort();
+
+ udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ assertNotNull(udpEncapResp);
+ if (udpEncapResp.status == IpSecManager.Status.OK) {
+ break;
+ }
+
+ // Else retry to reduce possibility for port-bind failures.
+ }
+
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
assertEquals(localport, udpEncapResp.port);
@@ -204,12 +215,11 @@
@Test
public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
- int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
+ int localport = udpEncapResp.port;
mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
udpEncapResp.fileDescriptor.close();
@@ -226,12 +236,11 @@
*/
@Test
public void testUdpEncapPortNotReleased() throws Exception {
- int localport = findUnusedPort();
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
+ int localport = udpEncapResp.port;
udpEncapResp.fileDescriptor.close();
@@ -273,14 +282,11 @@
@Test
public void testOpenUdpEncapsulationSocketTwice() throws Exception {
- int localport = findUnusedPort();
-
IpSecUdpEncapResponse udpEncapResp =
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ mIpSecService.openUdpEncapsulationSocket(0, new Binder());
assertNotNull(udpEncapResp);
assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
- assertEquals(localport, udpEncapResp.port);
- mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+ int localport = udpEncapResp.port;
IpSecUdpEncapResponse testUdpEncapResp =
mIpSecService.openUdpEncapsulationSocket(localport, new Binder());