Fix cancellation race problem for aysnc DNS API
This problem might cause double-close fd and result in app crash
or unexpected behaviour
Bug: 129317069
Test: atest DnsResolverTest
manual test with delaying response callback/cancel
Change-Id: I223234f527edafc51d34fa6be390419c05def8d8
This commit is contained in:
@@ -205,6 +205,7 @@ public final class DnsResolver {
|
||||
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
final Object lock = new Object();
|
||||
final FileDescriptor queryfd;
|
||||
try {
|
||||
queryfd = resNetworkSend((network != null
|
||||
@@ -214,8 +215,8 @@ public final class DnsResolver {
|
||||
return;
|
||||
}
|
||||
|
||||
maybeAddCancellationSignal(cancellationSignal, queryfd);
|
||||
registerFDListener(executor, queryfd, callback);
|
||||
maybeAddCancellationSignal(cancellationSignal, queryfd, lock);
|
||||
registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,6 +243,7 @@ public final class DnsResolver {
|
||||
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
final Object lock = new Object();
|
||||
final FileDescriptor queryfd;
|
||||
try {
|
||||
queryfd = resNetworkQuery((network != null
|
||||
@@ -251,17 +253,22 @@ public final class DnsResolver {
|
||||
return;
|
||||
}
|
||||
|
||||
maybeAddCancellationSignal(cancellationSignal, queryfd);
|
||||
registerFDListener(executor, queryfd, callback);
|
||||
maybeAddCancellationSignal(cancellationSignal, queryfd, lock);
|
||||
registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
|
||||
}
|
||||
|
||||
private <T> void registerFDListener(@NonNull Executor executor,
|
||||
@NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) {
|
||||
@NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback,
|
||||
@Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
|
||||
Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
|
||||
queryfd,
|
||||
FD_EVENTS,
|
||||
(fd, events) -> {
|
||||
executor.execute(() -> {
|
||||
synchronized (lock) {
|
||||
if (cancellationSignal != null && cancellationSignal.isCanceled()) {
|
||||
return;
|
||||
}
|
||||
byte[] answerbuf = null;
|
||||
try {
|
||||
answerbuf = resNetworkResult(fd);
|
||||
@@ -277,6 +284,7 @@ public final class DnsResolver {
|
||||
} catch (ParseException e) {
|
||||
answerCallback.onParseException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
// Unregister this fd listener
|
||||
return 0;
|
||||
@@ -284,13 +292,15 @@ public final class DnsResolver {
|
||||
}
|
||||
|
||||
private void maybeAddCancellationSignal(@Nullable CancellationSignal cancellationSignal,
|
||||
@NonNull FileDescriptor queryfd) {
|
||||
@NonNull FileDescriptor queryfd, @NonNull Object lock) {
|
||||
if (cancellationSignal == null) return;
|
||||
cancellationSignal.setOnCancelListener(
|
||||
() -> {
|
||||
cancellationSignal.setOnCancelListener(() -> {
|
||||
synchronized (lock) {
|
||||
if (!queryfd.valid()) return;
|
||||
Looper.getMainLooper().getQueue()
|
||||
.removeOnFileDescriptorEventListener(queryfd);
|
||||
resNetworkCancel(queryfd);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -470,6 +470,7 @@ static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz,
|
||||
std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
|
||||
|
||||
int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
|
||||
jniSetFileDescriptorOfFD(env, javaFd, -1);
|
||||
if (res < 0) {
|
||||
throwErrnoException(env, "resNetworkResult", -res);
|
||||
return nullptr;
|
||||
@@ -490,6 +491,7 @@ static jbyteArray android_net_utils_resNetworkResult(JNIEnv *env, jobject thiz,
|
||||
static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
|
||||
int fd = jniGetFDFromFileDescriptor(env, javaFd);
|
||||
resNetworkCancel(fd);
|
||||
jniSetFileDescriptorOfFD(env, javaFd, -1);
|
||||
}
|
||||
|
||||
static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
|
||||
|
||||
Reference in New Issue
Block a user