在Android应用程序中,我们可以通过ConnectivityManager.setProcessDefaultNetwork()来限制当前进程可访问的网络。对于native app,我们有没有办法对native进程进行限制呢?通过什么方法进行限制?
环境
Android系统版本:android-5.1.1_r15 @Nexus 4, 在项目中编译。
代码
一段很简单的代码,发起http请求:
int try_to_get_http_url(const char *hostname, const char *url)
{
int len;
char request[256], response[4096];
int fd = socket_network_client(hostname, 80, SOCK_STREAM);
if (fd < 0) {
printf("Failed to connect: %s, errno=%d(%s)\n", hostname, errno, strerror(errno));
return fd;
}
len = sprintf(request, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", url, hostname);
len = write(fd, request, len);
if (len <= 0) {
printf("Failed to send request: %s, errno=%d(%s)\n", request, errno, strerror(errno));
close(fd);
return len;
}
len = read(fd, response, sizeof(response) - 1);
if (len <= 0) {
printf("Failed to get response, errno=%d(%s)\n", errno, strerror(errno));
close(fd);
return len;
}
response[len] = '\0';
printf(response);
return close(fd);
}
int main(int argc, const char *argv[])
{
return try_to_get_http_url("brobwind.com", "/");
}
执行之后,可以从log中得到如下信息:
03-06 15:33:18.649 14917 14917 E hello-native: HTTP/1.1 301 Moved Permanently
03-06 15:33:18.649 14917 14917 E hello-native: Date: Sun, 06 Mar 2016 15:33:20 GMT
03-06 15:33:18.649 14917 14917 E hello-native: Server: Apache/2.4.7 (Ubuntu)
03-06 15:33:18.649 14917 14917 E hello-native: X-Powered-By: PHP/5.5.9-1ubuntu4.14
03-06 15:33:18.649 14917 14917 E hello-native: Location: http://www.brobwind.com/
03-06 15:33:18.649 14917 14917 E hello-native: Content-Length: 0
03-06 15:33:18.649 14917 14917 E hello-native: Content-Type: text/html; charset=UTF-8
试试这种方法,在JNI代码中去回调JAVA代码:
1. JNI相关代码:
#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \
var = env->GetMethodID(clazz, methodName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find method" methodName);
static struct {
jobject thiz;
jmethodID nativeSetProcessNetwork;
} gNativeApplication;
extern "C" void Java_com_brobwind_brontv_v1_NativeApplication_nNativeSetup(JNIEnv *env, jclass clazz, jobject thiz)
{
gNativeApplication.thiz = env->NewGlobalRef(thiz);
GET_METHOD_ID(gNativeApplication.nativeSetProcessNetwork, clazz, "nativeSetProcessNetwork", "()V");
}
extern "C" void Java_com_brobwind_brontv_v1_NativeApplication_nSayHello(JNIEnv *env, jclass, jstring binDir)
{
pid_t pid;
char path[PATH_MAX];
ScopedUtfChars _binDir(env, binDir);
sprintf(path, "%s/hello-native", _binDir.c_str());
pid = fork();
if (pid == 0) { // Child process
env->CallVoidMethod(gNativeApplication.thiz, gNativeApplication.nativeSetProcessNetwork);
env->DeleteGlobalRef(gNativeApplication.thiz);
exit(execl(path, path, NULL));
}
}
2. JAVA相关代码:
public class NativeApplication extends Application {
private static final String TAG = "NativeApp";
static {
System.loadLibrary("native-jni");
}
@Override
public void onCreate() {
nNativeSetup(this);
final File binDir = new File(getApplicationInfo().dataDir, "/bin");
binDir.mkdir();
binDir.setReadable(true, false);
try {
File binName = new File(binDir, "hello-native");
binName.delete();
if (binName.exists() != true) {
AssetManager am = getAssets();
InputStream is = am.open("bin/armeabi-v7a/" + binName.getName());
FileUtils.copyToFile(is, binName);
FileUtils.setPermissions(binName, FileUtils.S_IRUSR | FileUtils.S_IXUSR, -1, -1);
}
} catch (IOException e) {
e.printStackTrace();
}
nSayHello(binDir.getPath());
}
public void nativeSetProcessNetwork() {
ConnectivityManager cm = (ConnectivityManager)getSystemService(CONNECTIVITY_SERVICE);
Network allNetworks[] = cm.getAllNetworks();
for (Network network : allNetworks) {
NetworkInfo info = cm.getNetworkInfo(network);
if (info.getType() == ConnectivityManager.TYPE_WIFI) {
// cm.bindProcessToNetwork(network);
boolean setOk = cm.setProcessDefaultNetwork(network);
if (!setOk) {
Log.e(TAG, " -> Failed to set process default network: " + network);
}
break;
}
}
}
private static native void nNativeSetup(NativeApplication thiz);
private static native void nSayHello(String binDir);
}
看来这种方法不可行:
03-06 16:24:24.331 17117 17117 F libc : Fatal signal 11 (SIGSEGV), code 1, fault addr 0xb3fcf038 in tid 17117 (bwind.brontv.v1)
03-06 16:24:24.433 187 187 I DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
03-06 16:24:24.433 187 187 I DEBUG : Build fingerprint: 'Android/aosp_mako/mako:5.1.1/LMY48T/rwchen03041349:userdebug/test-keys'
03-06 16:24:24.433 187 187 I DEBUG : Revision: '11'
03-06 16:24:24.433 187 187 I DEBUG : ABI: 'arm'
03-06 16:24:24.433 558 674 W NativeCrashListener: Couldn't find ProcessRecord for pid 17117
03-06 16:24:24.433 187 187 I DEBUG : pid: 17117, tid: 17117, name: bwind.brontv.v1 >>> com.brobwind.brontv.v1 <<<
03-06 16:24:24.433 187 187 E DEBUG : AM write failure (32 / Broken pipe)
03-06 16:24:24.433 187 187 I DEBUG : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0xb3fcf038
03-06 16:24:24.444 187 187 I DEBUG : r0 00000000 r1 00000000 r2 00000000 r3 00000000
03-06 16:24:24.444 187 187 I DEBUG : r4 00000010 r5 00000001 r6 b7f2dd50 r7 b3fcf038
03-06 16:24:24.444 187 187 I DEBUG : r8 b3fcf028 r9 b7f2d980 sl b6e31255 fp 00007205
03-06 16:24:24.444 187 187 I DEBUG : ip b6dadd7c sp be8cfb40 lr b6da603c pc b6e3444e cpsr 800b0030
03-06 16:24:24.445 187 187 I DEBUG :
03-06 16:24:24.445 187 187 I DEBUG : backtrace:
03-06 16:24:24.445 187 187 I DEBUG : #00 pc 0002244e /system/lib/libbinder.so (android::Parcel::ipcSetDataReference(unsigned char const*, unsigned int, unsigned int const*, unsigned int, void (*)(android::Parcel*, unsigned char const*, unsigned int, unsigned int const*, unsigned int, void*), void*)+61)
03-06 16:24:24.445 187 187 I DEBUG : #01 pc 0001fa3f /system/lib/libbinder.so (android::IPCThreadState::waitForResponse(android::Parcel*, int*)+206)
03-06 16:24:24.445 187 187 I DEBUG : #02 pc 0001fb3d /system/lib/libbinder.so (android::IPCThreadState::transact(int, unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+124)
03-06 16:24:24.445 187 187 I DEBUG : #03 pc 0001ad23 /system/lib/libbinder.so (android::BpBinder::transact(unsigned int, android::Parcel const&, android::Parcel*, unsigned int)+30)
03-06 16:24:24.445 187 187 I DEBUG : #04 pc 000877bf /system/lib/libandroid_runtime.so
03-06 16:24:24.445 187 187 I DEBUG : #05 pc 00c1221d /data/dalvik-cache/arm/system@framework@boot.oat
我们再回看一下ConnectivityManager.setProcessDefaultNetwork()做了些什么:->@
public static boolean setProcessDefaultNetwork(Network network) {
int netId = (network == null) ? NETID_UNSET : network.netId;
if (netId == NetworkUtils.getNetworkBoundToProcess()) {
return true;
}
if (NetworkUtils.bindProcessToNetwork(netId)) {
// Set HTTP proxy system properties to match network.
// TODO: Deprecate this static method and replace it with a non-static version.
Proxy.setHttpProxySystemProperty(getInstance().getDefaultProxy());
// Must flush DNS cache as new network may have different DNS resolutions.
InetAddress.clearDnsCache();
// Must flush socket pool as idle sockets will be bound to previous network and may
// cause subsequent fetches to be performed on old network.
NetworkEventDispatcher.getInstance().onNetworkConfigurationChanged();
return true;
} else {
return false;
}
}
1. netId: 这个好办
2. NetworkUtils.bindProcessToNetwork(): 这个方法实际上直接调用的是native的setNetworkForProcess()这个也没问题
3. Proxy.setHttpProxySystemProperty(): 这个可以先暂时不管
4. InetAddress.clearDnsCache(): 貌似也可以不管
=== 待续 ===