带有 NetworkRequest 的 Android 运行时 exec

Posted

技术标签:

【中文标题】带有 NetworkRequest 的 Android 运行时 exec【英文标题】:Android runtime exec with NetworkRequest 【发布时间】:2016-03-06 19:06:35 【问题描述】:

我正在我的 android 应用程序中运行一个命令行参数,例如:

ProcessBuilder pb = new ProcessBuilder(cmds);
Process process = pb.start();
process.waitFor();

cmds 是要运行的参数列表。我的命令通过 http 连接探测远程 URL。我的设备连接到无法访问互联网的 WiFi 网络,但托管了我要探测的 URL。我的设备还具有可以访问互联网但不能访问 URL 的蜂窝连接。我的设备运行的是 Android 6.0 Marshmallow。

通常在 Lollipop 或更高版本中,Android 默认使用连接到 Internet 的网络。要在没有互联网的情况下访问 WiFi 网络,您需要使用 NetworkRequest,例如:https://***.com/a/27958106/1847734。

如何将获得的Network 传递给上面的Process,以便连接通过我的 WiFi 网络,而不是我的蜂窝网络?

我是否需要改用ConnectivityManager#bindProcessToNetwork?如何加入使用此方法设置网络的过程?似乎没有提供该过程的选项。

【问题讨论】:

棘手的问题。如果您在构建和启动进程之前将网络绑定到您的应用程序进程,您会幸运地继承了网络吗? 不幸的是,不,它似乎没有。 @JonG 你是怎么解决这个问题的?您是否按照建议使用了本机实现?我遇到了完全相同的问题,我能够为 API >= 21 绑定“正常”网络请求,但找不到绑定进程的方法(我还需要使用“ping”进行测试) @soey 你们找到解决方案了吗?我尝试在 Java 中设置默认网络,但没有成功。接下来,我用正确的网络在 Java 中创建了 Socket,并将描述符传递给 Native 子进程,但效果不佳。 @Himanshu 抱歉,我没有找到解决方案。我认为这是一个非常具体的问题。我最终忽略了它,例如在这种情况下不执行该过程,这对我的用例来说已经足够了。我想我在某处看到了一个解决方案,他们使用了本机套接字实现(在 C 中),但我在 atm 中找不到它。另外我对使用本机代码不是很有经验。 【参考方案1】:

从 Lollipop 开始 NetworkParcelable 所以你可以将它写入一个字节数组,然后再读回。让我们从写作部分开始。

final Parcel parcel = Parcel.obtain();
try 
  // Create a byte array from Network.
  parcel.writeParcelable(network, 0);
  final byte[] data = parcel.marshall();

  // Start a process.
  ProcessBuilder pb = new ProcessBuilder(cmds);
  Process process = pb.start();

  // Send serialized Network to the process.
  final DataOutputStream out = new DataOutputStream(process.getOutputStream());
  out.write(data.length);
  out.write(data);

  // Wait until the process terminates.
  process.waitFor();
 finally 
  parcel.recycle();

还有阅读部分。

// Read data from the input stream.
final DataInputStream in = new DataInputStream(System.in);
final int length = in.readInt();
final byte[] data = new byte[length];
in.readFully(data);

final Parcel parcel = Parcel.obtain();
try 
  // Restore Network from a byte array.
  parcel.unmarshall(data, 0, data.length);
  final Network network = parcel.readParcelable(null);

  // Use the Network object to bind the process to it.
  connectivityManager.bindProcessToNetwork(network);
 finally 
  parcel.recycle();

此代码仅适用于 Android 6.0。如果你想让它在 Lollipop 上工作,你应该使用 ConnectivityManager.setProcessDefaultNetwork(Network) 而不是 ConnectivityManager.bindProcessToNetwork(Network)。而且此代码不适用于 Android 5.0 之前的设备。

更新

对于非 Android 进程,您可以创建一个套接字,使用 Network.bindSocket(Socket) 将其绑定到网络,并将套接字描述符传递给子进程。

如果前面的方法不适合您,您可以从 multinetwork.h 调用 NDK 函数 android_setsocknetwork,甚至尝试执行 Android 在将进程绑定到给定网络时所做的事情。您可能感兴趣的一切都发生在netd client。 NetdClientfwmarkd here 发送一条消息,传递一个网络ID。实际消息发送发生在here。但我建议使用这种方法作为解决问题的最后机会。

【讨论】:

我不知道你可以打包一个网络,这很有趣,但是我的进程在命令行上运行一个编译好的二进制文件,所以我不认为我可以在那里通过网络。

以上是关于带有 NetworkRequest 的 Android 运行时 exec的主要内容,如果未能解决你的问题,请参考以下文章

带有渐变背景的工具栏设置标题背景透明

带有可访问性工具的直接输入区域

带有 showSoftInput 的 Android 显示软键盘不起作用?

我的 Android 小部件被杀死,“不再需要 bellander.andro ....”

如何解决这个错误。 com.google.android.gms.tasks.task executors$zza 无法转换为 android.app.activity。我是 Java 和 Andro

java.lang.RuntimeException: Unable to start activity ComponentInfo{XXX}: Error inflating class andro