ares_android.c
Go to the documentation of this file.
1 /* Copyright (C) 2017 by John Schember <john@nachtimwald.com>
2  *
3  * Permission to use, copy, modify, and distribute this
4  * software and its documentation for any purpose and without
5  * fee is hereby granted, provided that the above copyright
6  * notice appear in all copies and that both that copyright
7  * notice and this permission notice appear in supporting
8  * documentation, and that the name of M.I.T. not be used in
9  * advertising or publicity pertaining to distribution of the
10  * software without specific, written prior permission.
11  * M.I.T. makes no representations about the suitability of
12  * this software for any purpose. It is provided "as is"
13  * without express or implied warranty.
14  */
15 #if defined(ANDROID) || defined(__ANDROID__)
16 
17 #include <jni.h>
18 
19 #include "ares_setup.h"
20 #include "ares.h"
21 #include "ares_android.h"
22 #include "ares_private.h"
23 
24 static JavaVM *android_jvm = NULL;
25 static jobject android_connectivity_manager = NULL;
26 
27 /* ConnectivityManager.getActiveNetwork */
28 static jmethodID android_cm_active_net_mid = NULL;
29 /* ConnectivityManager.getLinkProperties */
30 static jmethodID android_cm_link_props_mid = NULL;
31 /* LinkProperties.getDnsServers */
32 static jmethodID android_lp_dns_servers_mid = NULL;
33 /* LinkProperties.getDomains */
34 static jmethodID android_lp_domains_mid = NULL;
35 /* List.size */
36 static jmethodID android_list_size_mid = NULL;
37 /* List.get */
38 static jmethodID android_list_get_mid = NULL;
39 /* InetAddress.getHostAddress */
40 static jmethodID android_ia_host_addr_mid = NULL;
41 
42 static jclass jni_get_class(JNIEnv *env, const char *path)
43 {
44  jclass cls = NULL;
45 
46  if (env == NULL || path == NULL || *path == '\0')
47  return NULL;
48 
49  cls = (*env)->FindClass(env, path);
50  if ((*env)->ExceptionOccurred(env)) {
51  (*env)->ExceptionClear(env);
52  return NULL;
53  }
54  return cls;
55 }
56 
57 static jmethodID jni_get_method_id(JNIEnv *env, jclass cls,
58  const char *func_name, const char *signature)
59 {
60  jmethodID mid = NULL;
61 
62  if (env == NULL || cls == NULL || func_name == NULL || *func_name == '\0' ||
63  signature == NULL || *signature == '\0')
64  {
65  return NULL;
66  }
67 
68  mid = (*env)->GetMethodID(env, cls, func_name, signature);
69  if ((*env)->ExceptionOccurred(env))
70  {
71  (*env)->ExceptionClear(env);
72  return NULL;
73  }
74 
75  return mid;
76 }
77 
78 void ares_library_init_jvm(JavaVM *jvm)
79 {
80  android_jvm = jvm;
81 }
82 
83 int ares_library_init_android(jobject connectivity_manager)
84 {
85  JNIEnv *env = NULL;
86  int need_detatch = 0;
87  int res;
89  jclass obj_cls = NULL;
90 
91  if (android_jvm == NULL)
92  goto cleanup;
93 
94  res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
95  if (res == JNI_EDETACHED)
96  {
97  env = NULL;
98  res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL);
99  need_detatch = 1;
100  }
101  if (res != JNI_OK || env == NULL)
102  goto cleanup;
103 
104  android_connectivity_manager =
105  (*env)->NewGlobalRef(env, connectivity_manager);
106  if (android_connectivity_manager == NULL)
107  goto cleanup;
108 
109  /* Initialization has succeeded. Now attempt to cache the methods that will be
110  * called by ares_get_android_server_list. */
111  ret = ARES_SUCCESS;
112 
113  /* ConnectivityManager in API 1. */
114  obj_cls = jni_get_class(env, "android/net/ConnectivityManager");
115  if (obj_cls == NULL)
116  goto cleanup;
117 
118  /* ConnectivityManager.getActiveNetwork in API 23. */
119  android_cm_active_net_mid =
120  jni_get_method_id(env, obj_cls, "getActiveNetwork",
121  "()Landroid/net/Network;");
122  if (android_cm_active_net_mid == NULL)
123  goto cleanup;
124 
125  /* ConnectivityManager.getLinkProperties in API 21. */
126  android_cm_link_props_mid =
127  jni_get_method_id(env, obj_cls, "getLinkProperties",
128  "(Landroid/net/Network;)Landroid/net/LinkProperties;");
129  if (android_cm_link_props_mid == NULL)
130  goto cleanup;
131 
132  /* LinkProperties in API 21. */
133  (*env)->DeleteLocalRef(env, obj_cls);
134  obj_cls = jni_get_class(env, "android/net/LinkProperties");
135  if (obj_cls == NULL)
136  goto cleanup;
137 
138  /* getDnsServers in API 21. */
139  android_lp_dns_servers_mid = jni_get_method_id(env, obj_cls, "getDnsServers",
140  "()Ljava/util/List;");
141  if (android_lp_dns_servers_mid == NULL)
142  goto cleanup;
143 
144  /* getDomains in API 21. */
145  android_lp_domains_mid = jni_get_method_id(env, obj_cls, "getDomains",
146  "()Ljava/lang/String;");
147  if (android_lp_domains_mid == NULL)
148  goto cleanup;
149 
150  (*env)->DeleteLocalRef(env, obj_cls);
151  obj_cls = jni_get_class(env, "java/util/List");
152  if (obj_cls == NULL)
153  goto cleanup;
154 
155  android_list_size_mid = jni_get_method_id(env, obj_cls, "size", "()I");
156  if (android_list_size_mid == NULL)
157  goto cleanup;
158 
159  android_list_get_mid = jni_get_method_id(env, obj_cls, "get",
160  "(I)Ljava/lang/Object;");
161  if (android_list_get_mid == NULL)
162  goto cleanup;
163 
164  (*env)->DeleteLocalRef(env, obj_cls);
165  obj_cls = jni_get_class(env, "java/net/InetAddress");
166  if (obj_cls == NULL)
167  goto cleanup;
168 
169  android_ia_host_addr_mid = jni_get_method_id(env, obj_cls, "getHostAddress",
170  "()Ljava/lang/String;");
171  if (android_ia_host_addr_mid == NULL)
172  goto cleanup;
173 
174  (*env)->DeleteLocalRef(env, obj_cls);
175  goto done;
176 
177 cleanup:
178  if (obj_cls != NULL)
179  (*env)->DeleteLocalRef(env, obj_cls);
180 
181  android_cm_active_net_mid = NULL;
182  android_cm_link_props_mid = NULL;
183  android_lp_dns_servers_mid = NULL;
184  android_lp_domains_mid = NULL;
185  android_list_size_mid = NULL;
186  android_list_get_mid = NULL;
187  android_ia_host_addr_mid = NULL;
188 
189 done:
190  if (need_detatch)
191  (*android_jvm)->DetachCurrentThread(android_jvm);
192 
193  return ret;
194 }
195 
196 int ares_library_android_initialized(void)
197 {
198  if (android_jvm == NULL || android_connectivity_manager == NULL)
199  return ARES_ENOTINITIALIZED;
200  return ARES_SUCCESS;
201 }
202 
203 void ares_library_cleanup_android(void)
204 {
205  JNIEnv *env = NULL;
206  int need_detatch = 0;
207  int res;
208 
209  if (android_jvm == NULL || android_connectivity_manager == NULL)
210  return;
211 
212  res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
213  if (res == JNI_EDETACHED)
214  {
215  env = NULL;
216  res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL);
217  need_detatch = 1;
218  }
219  if (res != JNI_OK || env == NULL)
220  return;
221 
222  android_cm_active_net_mid = NULL;
223  android_cm_link_props_mid = NULL;
224  android_lp_dns_servers_mid = NULL;
225  android_lp_domains_mid = NULL;
226  android_list_size_mid = NULL;
227  android_list_get_mid = NULL;
228  android_ia_host_addr_mid = NULL;
229 
230  (*env)->DeleteGlobalRef(env, android_connectivity_manager);
231  android_connectivity_manager = NULL;
232 
233  if (need_detatch)
234  (*android_jvm)->DetachCurrentThread(android_jvm);
235 }
236 
237 char **ares_get_android_server_list(size_t max_servers,
238  size_t *num_servers)
239 {
240  JNIEnv *env = NULL;
241  jobject active_network = NULL;
242  jobject link_properties = NULL;
243  jobject server_list = NULL;
244  jobject server = NULL;
245  jstring str = NULL;
246  jint nserv;
247  const char *ch_server_address;
248  int res;
249  size_t i;
250  char **dns_list = NULL;
251  int need_detatch = 0;
252 
253  if (android_jvm == NULL || android_connectivity_manager == NULL ||
254  max_servers == 0 || num_servers == NULL)
255  {
256  return NULL;
257  }
258 
259  if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL ||
260  android_lp_dns_servers_mid == NULL || android_list_size_mid == NULL ||
261  android_list_get_mid == NULL || android_ia_host_addr_mid == NULL)
262  {
263  return NULL;
264  }
265 
266  res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
267  if (res == JNI_EDETACHED)
268  {
269  env = NULL;
270  res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL);
271  need_detatch = 1;
272  }
273  if (res != JNI_OK || env == NULL)
274  goto done;
275 
276  /* JNI below is equivalent to this Java code.
277  import android.content.Context;
278  import android.net.ConnectivityManager;
279  import android.net.LinkProperties;
280  import android.net.Network;
281  import java.net.InetAddress;
282  import java.util.List;
283 
284  ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext()
285  .getSystemService(Context.CONNECTIVITY_SERVICE);
286  Network an = cm.getActiveNetwork();
287  LinkProperties lp = cm.getLinkProperties(an);
288  List<InetAddress> dns = lp.getDnsServers();
289  for (InetAddress ia: dns) {
290  String ha = ia.getHostAddress();
291  }
292 
293  Note: The JNI ConnectivityManager object and all method IDs were previously
294  initialized in ares_library_init_android.
295  */
296 
297  active_network = (*env)->CallObjectMethod(env, android_connectivity_manager,
298  android_cm_active_net_mid);
299  if (active_network == NULL)
300  goto done;
301 
302  link_properties =
303  (*env)->CallObjectMethod(env, android_connectivity_manager,
304  android_cm_link_props_mid, active_network);
305  if (link_properties == NULL)
306  goto done;
307 
308  server_list = (*env)->CallObjectMethod(env, link_properties,
309  android_lp_dns_servers_mid);
310  if (server_list == NULL)
311  goto done;
312 
313  nserv = (*env)->CallIntMethod(env, server_list, android_list_size_mid);
314  if (nserv > (jint)max_servers)
315  nserv = (jint)max_servers;
316  if (nserv <= 0)
317  goto done;
318  *num_servers = (size_t)nserv;
319 
320  dns_list = ares_malloc(sizeof(*dns_list)*(*num_servers));
321  for (i=0; i<*num_servers; i++)
322  {
323  server = (*env)->CallObjectMethod(env, server_list, android_list_get_mid,
324  (jint)i);
325  dns_list[i] = ares_malloc(64);
326  dns_list[i][0] = 0;
327  if (server == NULL)
328  {
329  continue;
330  }
331  str = (*env)->CallObjectMethod(env, server, android_ia_host_addr_mid);
332  ch_server_address = (*env)->GetStringUTFChars(env, str, 0);
333  strncpy(dns_list[i], ch_server_address, 64);
334  (*env)->ReleaseStringUTFChars(env, str, ch_server_address);
335  (*env)->DeleteLocalRef(env, str);
336  (*env)->DeleteLocalRef(env, server);
337  }
338 
339 done:
340  if ((*env)->ExceptionOccurred(env))
341  (*env)->ExceptionClear(env);
342 
343  if (server_list != NULL)
344  (*env)->DeleteLocalRef(env, server_list);
345  if (link_properties != NULL)
346  (*env)->DeleteLocalRef(env, link_properties);
347  if (active_network != NULL)
348  (*env)->DeleteLocalRef(env, active_network);
349 
350  if (need_detatch)
351  (*android_jvm)->DetachCurrentThread(android_jvm);
352  return dns_list;
353 }
354 
355 char *ares_get_android_search_domains_list(void)
356 {
357  JNIEnv *env = NULL;
358  jobject active_network = NULL;
359  jobject link_properties = NULL;
360  jstring domains = NULL;
361  const char *domain;
362  int res;
363  char *domain_list = NULL;
364  int need_detatch = 0;
365 
366  if (android_jvm == NULL || android_connectivity_manager == NULL)
367  {
368  return NULL;
369  }
370 
371  if (android_cm_active_net_mid == NULL || android_cm_link_props_mid == NULL ||
372  android_lp_domains_mid == NULL)
373  {
374  return NULL;
375  }
376 
377  res = (*android_jvm)->GetEnv(android_jvm, (void **)&env, JNI_VERSION_1_6);
378  if (res == JNI_EDETACHED)
379  {
380  env = NULL;
381  res = (*android_jvm)->AttachCurrentThread(android_jvm, &env, NULL);
382  need_detatch = 1;
383  }
384  if (res != JNI_OK || env == NULL)
385  goto done;
386 
387  /* JNI below is equivalent to this Java code.
388  import android.content.Context;
389  import android.net.ConnectivityManager;
390  import android.net.LinkProperties;
391 
392  ConnectivityManager cm = (ConnectivityManager)this.getApplicationContext()
393  .getSystemService(Context.CONNECTIVITY_SERVICE);
394  Network an = cm.getActiveNetwork();
395  LinkProperties lp = cm.getLinkProperties(an);
396  String domains = lp.getDomains();
397  for (String domain: domains.split(",")) {
398  String d = domain;
399  }
400 
401  Note: The JNI ConnectivityManager object and all method IDs were previously
402  initialized in ares_library_init_android.
403  */
404 
405  active_network = (*env)->CallObjectMethod(env, android_connectivity_manager,
406  android_cm_active_net_mid);
407  if (active_network == NULL)
408  goto done;
409 
410  link_properties =
411  (*env)->CallObjectMethod(env, android_connectivity_manager,
412  android_cm_link_props_mid, active_network);
413  if (link_properties == NULL)
414  goto done;
415 
416  /* Get the domains. It is a common separated list of domains to search. */
417  domains = (*env)->CallObjectMethod(env, link_properties,
418  android_lp_domains_mid);
419  if (domains == NULL)
420  goto done;
421 
422  /* Split on , */
423  domain = (*env)->GetStringUTFChars(env, domains, 0);
424  domain_list = ares_strdup(domain);
425  (*env)->ReleaseStringUTFChars(env, domains, domain);
426  (*env)->DeleteLocalRef(env, domains);
427 
428 done:
429  if ((*env)->ExceptionOccurred(env))
430  (*env)->ExceptionClear(env);
431 
432  if (link_properties != NULL)
433  (*env)->DeleteLocalRef(env, link_properties);
434  if (active_network != NULL)
435  (*env)->DeleteLocalRef(env, active_network);
436 
437  if (need_detatch)
438  (*android_jvm)->DetachCurrentThread(android_jvm);
439  return domain_list;
440 }
441 #else
442 /* warning: ISO C forbids an empty translation unit */
444 #endif
xds_interop_client.str
str
Definition: xds_interop_client.py:487
cleanup
void cleanup(void)
Definition: bloaty/third_party/zlib/examples/enough.c:182
ares.h
ares_strdup
char * ares_strdup(const char *s1)
Definition: ares_strdup.c:23
check_documentation.path
path
Definition: check_documentation.py:57
dummy_make_iso_compilers_happy
int dummy_make_iso_compilers_happy
Definition: ares_android.c:443
ares_malloc
void *(* ares_malloc)(size_t size)=default_malloc
Definition: ares_library_init.c:58
ares_android.h
done
struct tab * done
Definition: bloaty/third_party/zlib/examples/enough.c:176
ARES_ENOTINITIALIZED
#define ARES_ENOTINITIALIZED
Definition: ares.h:129
ARES_SUCCESS
#define ARES_SUCCESS
Definition: ares.h:98
ares_setup.h
server
Definition: examples/python/async_streaming/server.py:1
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
env
Definition: env.py:1
ares_private.h
domains
std::vector< std::string > domains
Definition: xds_server_config_fetcher.cc:337
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230


grpc
Author(s):
autogenerated on Fri May 16 2025 02:57:43