Wednesday, April 13, 2016

Android runtime exec with NetworkRequest

Leave a Comment

I am running a command line argument in my Android application like:

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

Where cmds are a list of arguments to run. My commands probe a remote URL over a http connection. My device is connected to a WiFi network that does not have access to the internet, but does host the URL I want to probe. My device also has a cellular connection that does have access to the internet, but not the URL. My device is running Android 6.0 Marshmallow.

Normally in Lollipop or above, Android defaults to the network with a connection to the internet. To access WiFi networks without internet you need to use NetworkRequest, e.g: http://stackoverflow.com/a/27958106/1847734.

How can I pass an obtained Network to the above Process, so that the connection goes over my WiFi network, not my cellular network?

Do I instead need to use ConnectivityManager#bindProcessToNetwork? How do I join the process to set the network using this method? There doesn't seem to be an option to give the process.

1 Answers

Answers 1

Starting from Lollipop Network is Parcelable so you can write it to a byte array and then read back. Let's start from the writing part.

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(); } 

And the reading part.

// 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(); } 

This code will work on Android 6.0 only. If you want it to work on Lollipop you should use ConnectivityManager.setProcessDefaultNetwork(Network) instead of ConnectivityManager.bindProcessToNetwork(Network). And this code is not going to work on devices before Android 5.0.

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment