Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support to new Android DNS functions android_res_nquery android_res_nresult (API 29+) #4333

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

micha102
Copy link

@micha102 micha102 commented Mar 3, 2025

Add support to new Android DNS functions android_res_nquery android_res_nresult (API 29+) in pjlib/src/pj/addr_resolv_sock.c
New macro
#define PJ_GETADDRINFO_USE_ANDROID 1

I looked at the Android documentation to enhance default getaddrinfo (very slow in recent Android APIs), and found that a native method for DNS resolution is available starting Android API 29, based on android_res_nquery and android_res_nresult functions.

I implemented it and it's definitely faster than default getaddrinfo, the delay between clicking on "Start Library" and actual TLS socket establishment is next to nothing (110 ms)

Add support android_res_nquery for DNS (Android API 29+)
@CLAassistant
Copy link

CLAassistant commented Mar 3, 2025

CLA assistant check
All committers have signed the CLA.

@micha102
Copy link
Author

micha102 commented Mar 4, 2025

Need to implement the check on Android API Level too
If >= 29 then run the DNS lookup with android_res_nquery/android_res_nresult
if < 29 then run the DNS lookup with getaddrinfo

Use dlopen libandroid.so then dlsym to load functions android_res_nquery, android_res_nresult and android_res_cancel.
This avoids devices with Android API < 29 to fail to load the library due to absence of the 29+ functions, and let them fallback directly to call the default getaddrinfo()
@micha102
Copy link
Author

micha102 commented Mar 5, 2025

I found it's trickier than I thought to "hide" the API 29+ functions from devices with API < 29.
If I just do a check on API Level, then older devices will throw "dlopen failed: cannot locate symbol "android_res_nquery" referenced by libpjsua2" even though it shouldn't see it (because of the if statement).

So, I dynamically loaded the functions android_res_nquery, android_res_nresult and android_res_cancel and did this only in case of API >= 29
Otherwise for older APIs, I cloned the same default getaddrinfo() to be used.

I tested it on :
Xiaomi Mi 9T with LineageOS API 35 arm64-v8a : works good with API 29+ functions
Emulated Pixel 6 Pro with API 35 x86_64 : works good with API 29+ functions
Emulated Pixel 6 Pro with API 32 x86_64 : works good with API 29+ functions
Emulated Pixel 6 Pro with API 28 x86 : works good with fallback getaddrinfo()

@micha102 micha102 marked this pull request as ready for review March 5, 2025 01:50
@sauwming sauwming added this to the release-2.16 milestone Mar 5, 2025
#include <sys/system_properties.h> // For getting Android Device API Version
#include <dlfcn.h>
#endif

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use #elif here, to make it obvious that only one condition can be satisfied

also indent the #include.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review.
I put the statement below PJ_GETADDRINFO_USE_CFHOST and changed it to #elif.
I also indented the #include

if (atoi(sdk_value) >= 29) {
void *libandroid_handle = dlopen("libandroid.so", RTLD_NOW);
if (libandroid_handle) {
android_res_nquery_ptr = (android_res_nquery_fn) dlsym(libandroid_handle, "android_res_nquery");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: all col needs to be <= 80

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reviewed all the lines where columns were over 80 and added linSorry, I've just learnt this for C. Thank you.

struct pollfd fds;
fds.fd = resp_handle;
fds.events = POLLIN;
int ret = poll(&fds, 1, 5000); // 5-second timeout
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create a compile-time macro for the timeout (under all the #include above), so user can easily modify it should they wish to.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a macro ANDROID_DNS_TIMEOUT_MS for this.
Also I created the macro THIS_FILE as in other source files, for logging usage.

*/
res->ai_socktype != 0)
{
continue;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indentation

android_res_cancel_ptr(resp_handle);
return PJ_ERESOLVE;
}
// Step 3: Get DNS response
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I corrected the comments so that they match the requirement.

@sauwming sauwming requested review from bennylp and nanangizz March 5, 2025 05:14
char sdk_value[8] = "";
__system_property_get("ro.build.version.sdk", sdk_value);
if (atoi(sdk_value) >= 29) {
void *libandroid_handle = dlopen("libandroid.so", RTLD_NOW);
Copy link
Member

@nanangizz nanangizz Mar 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why it is loaded manually? If modifying build config, e.g: adding library or LD_FLAGS, is needed, perhaps we can help.

Update: ah sorry, just read the discussion above, I guess it is better to also put comments about this in the code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review. I corrected it in the last commit and added a comment over that block to explain the reason why I used function pointers to load API 29+ functions only when Android API Level verification is done.

Format for max 80 cols
transform the PJ_GETADDRINFO_USE_ANDROID to elif
indentation correction
add comments for dynamic function loading
@micha102 micha102 requested review from sauwming and nanangizz March 5, 2025 21:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Slow destination DNS resolution in Android API 32+ (fail for Emulated API 32)
4 participants