Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dec62b79 authored by Luke Huang's avatar Luke Huang Committed by android-build-merger
Browse files

Merge "API council feedbacks for DnsResolver" am: 5023a618 am: 454fe010

am: a94c6e54

Change-Id: I6923d0188f30dd06372da38a77f6cc654bdc714d
parents 1381a96a a94c6e54
Loading
Loading
Loading
Loading
+11 −20
Original line number Diff line number Diff line
@@ -28754,10 +28754,13 @@ package android.net {
  public final class DnsResolver {
    method @NonNull public static android.net.DnsResolver getInstance();
    method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
    method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
    method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.InetAddressAnswerCallback);
    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
@@ -28766,23 +28769,13 @@ package android.net {
    field public static final int TYPE_AAAA = 28; // 0x1c
  }
  public abstract static class DnsResolver.AnswerCallback<T> {
    ctor public DnsResolver.AnswerCallback(@NonNull android.net.DnsResolver.AnswerParser<T>);
    method public abstract void onAnswer(@NonNull T);
    method public abstract void onParseException(@NonNull android.net.ParseException);
    method public abstract void onQueryException(@NonNull android.system.ErrnoException);
  public static interface DnsResolver.Callback<T> {
    method public void onAnswer(@NonNull T, int);
    method public void onError(@NonNull android.net.DnsResolver.DnsException);
  }
  public static interface DnsResolver.AnswerParser<T> {
    method @NonNull public T parse(@NonNull byte[]) throws android.net.ParseException;
  }
  public abstract static class DnsResolver.InetAddressAnswerCallback extends android.net.DnsResolver.AnswerCallback<java.util.List<java.net.InetAddress>> {
    ctor public DnsResolver.InetAddressAnswerCallback();
  }
  public abstract static class DnsResolver.RawAnswerCallback extends android.net.DnsResolver.AnswerCallback<byte[]> {
    ctor public DnsResolver.RawAnswerCallback();
  public static class DnsResolver.DnsException extends java.lang.Exception {
    field public final int code;
  }
  public class InetAddresses {
@@ -29108,8 +29101,6 @@ package android.net {
  }
  public class ParseException extends java.lang.RuntimeException {
    ctor public ParseException(@NonNull String);
    ctor public ParseException(@NonNull String, @NonNull Throwable);
    field public String response;
  }
+160 −124
Original line number Diff line number Diff line
@@ -93,6 +93,23 @@ public final class DnsResolver {
    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 @@ public final class DnsResolver {
    private DnsResolver() {}

    /**
     * Answer parser for parsing raw answers
     *
     * @param <T> The type of the parsed answer
     */
    public interface AnswerParser<T> {
        /**
         * Creates a <T> answer by parsing the given raw answer.
     * Base interface for answer callbacks
     *
         * @param rawAnswer the raw answer to be parsed
         * @return a parsed <T> answer
         * @throws ParseException if parsing failed
     * @param <T> The type of the answer
     */
        @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 {
       /**
     * 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.
        * DNS error code as one of the ERROR_* constants
        */
    public abstract static class InetAddressAnswerCallback
            extends AnswerCallback<List<InetAddress>> {
        public InetAddressAnswerCallback() {
            super(rawAnswer -> new DnsAddressAnswer(rawAnswer).getAddresses());
        @DnsError public final int code;

        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 @@ public final class DnsResolver {
     * @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;
        }
@@ -222,9 +199,7 @@ public final class DnsResolver {
            queryfd = resNetworkSend((network != null
                ? network.netId : 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 @@ public final class DnsResolver {

    /**
     * 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 @@ public final class DnsResolver {
     * @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;
        }
@@ -265,9 +240,7 @@ public final class DnsResolver {
            queryfd = resNetworkQuery((network != null
                    ? network.netId : 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 @@ public final class DnsResolver {
        }
    }

    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 @@ public final class DnsResolver {

        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);
            maybeReportAnswer();
        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);
            }

        @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 @@ public final class DnsResolver {
     * @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;
        }
@@ -365,9 +348,7 @@ public final class DnsResolver {
                v6fd = resNetworkQuery((network != null
                        ? network.netId : 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,7 +358,9 @@ public final class DnsResolver {
        // 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 {
@@ -385,9 +368,7 @@ public final class DnsResolver {
                        ? network.netId : 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 +394,89 @@ public final class DnsResolver {
        }
    }

    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.netId : 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;
                                exception = e;
                            }

                            try {
                                answerCallback.onAnswer(
                                        answerCallback.parser.parse(answerbuf));
                            } catch (ParseException e) {
                                answerCallback.onParseException(e);
                        }
                        if (exception != null) {
                            answerCallback.onError(new DnsException(ERROR_SYSTEM, exception));
                            return;
                        }
                        answerCallback.onAnswer(resp.answerbuf, resp.rcode);
                    });
                    // Unregister this fd listener
                    return 0;
+3 −2
Original line number Diff line number Diff line
@@ -145,9 +145,10 @@ public class NetworkUtils {
    /**
     * 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.
+2 −2
Original line number Diff line number Diff line
@@ -25,12 +25,12 @@ import android.annotation.NonNull;
public class ParseException extends RuntimeException {
    public String response;

    public ParseException(@NonNull String response) {
    ParseException(@NonNull String response) {
        super(response);
        this.response = response;
    }

    public ParseException(@NonNull String response, @NonNull Throwable cause) {
    ParseException(@NonNull String response, @NonNull Throwable cause) {
        super(response, cause);
        this.response = response;
    }
+6 −3

File changed.

Preview size limit exceeded, changes collapsed.