最近做一个项目,模块分前后台,前台UI用java,后台核心服务用c/c++,分别是两个进程。但是后台由前台启动。其中遇到一个问题,后台核心服务需要调用gethostbyname来访问DNS相关内容,调试发现每次都失败。一开始我们怀疑是权限问题,但是发现AndroidManifest.xml里面已经加上了网络相关的权限。
几个人一起测试规律,发现如果gethostbyname写在jni里面,然后java调用jni成功。如果由java直接启动本地exec则失败。改用jni启动本地exec后,发现也失败。jni调用采取fork + exec的方式。
java -> jni -> gethostbyname 成功
java -> jni -> exec -> gethostbyname 失败
java -> exec -> gethostbyname 失败
java -> jni -> fork -> gethostbyname 成功
没有头绪,于是求教google,发现网上也有人遇到同样问题,说是如果
exec -> fork -> exec -> gethostbyname 失败
exec -> gethostbyname 成功
exec -> system -> gethostbyname成功
那么 system 和 fork + exec方式有什么区别呢?
是否权限的问题?
无解,最后一招,硬着头皮去看源代码了,
查看gethostbyname的源代码
bionic/libc/netbsd/gethnamaddr.c
gethostbyname -> __res_get_state -> _res_thread_get -> __system_property_find
看来DNS的信息和android的property system搭上边了。会不会是访问property system权限的问题呢?呵呵!
接着往下看bionic/libc/bionic/system_properties.c
__system_properties_init -> getenv("ANDROID_PROPERTY_WORKSPACE")
看到这里是不是真相大白了!
process初始化时会读取ANDROID_PROPERTY_WORKSPACE这个环境变量的内容来作为mmap的文件描述符。这样,property system的properties才对系统所有进程是共享的。呵呵,这个共享的文件描述符就存储在ANDROID_PROPERTY_WORKSPACE中。
这样,父进程在fork子进程后,拿到ANDROID_PROPERTY_WORKSPACE这个环境变量,然后在传递给exec就可以解决问题了。
好了,再试一把。
java -> get ANDROID_PROPERTY_WORKSPACE -> set ANDROID_PROPERTY_WORKSPACE to envp ->exec -> gethostbyname
果然ok了。
阅读(7700) | 评论(4) | 转发(0) |