Android runtime exec with NetworkRequest - android

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: https://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.

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.
UPDATE:
For a non-Android process you can create a socket, bind it to the nework with Network.bindSocket(Socket) and pass a socket descriptor to the child process.
If the previous approach doesn't work for you, you can call NDK function android_setsocknetwork from multinetwork.h or even try and do what Android does when you bind a process to a given network. Everything you might be interested in happens in netd client. NetdClient sends a message to fwmarkd here passing a network id. Actual message sending happens here. But I would recommend to use this approach as the last chance way to solve your problem.

Related

How to get my own endpointId with Nearby Connections?

With Nearby Connections, each device has an endpointId, something similar to zkHk.
Getting the endpointId of others is trivial since it is returned by the API when scanning or connecting to other devices.
I must miss something, but I cannot find a way to get my own endpointId (apart implementing a mechanism where a connected peer echoes my id). It can be useful for some protocols where I want to follow what is sent to who.
The only thing I found is getLocalEndpointName but it returns my name, not my id. Even though it seems the C++ version of Nearby have it!
Do you have some ideas for Java/Kotlin? I specifically seek to get the endpointId, and not use alternatives like using a kind of GUID in the localendpoint name as a replacement.
Edit: Some example of usage
1) For instance, it can be interesting to implement some network mesh protocols. Several devices are interconnected making a global network, and each device add its endpointId in the incoming payload before sending it again, so others can check if they should send the payload to a device that already has it.
2) I may also want to specifically send a packet from device A to C through B acting as a relay, and add some "from: A" and "to: C" field in the payload so the network would know how to route the data and avoid some retransmission cycles. It is simpler to do that with endpointId since each device has a list of endpointId to which it is connected.
3) It can also be interesting for debug purpose. If I do some tests with a phone connected to several others (e.g. star network), it is easier to know from which phone a new piece of data is coming, all the more if I want to use name for another purpose.
Note: all of that could be done differently (e.g. use some unique identifier for the "name" of the devices and check that instead of the endpointId) but it seems a little cumbersome. All the more since endpointId guarantee a kind of unicity, whereas I must enforce it for the name. Moreover there isn't lots of information I can have on another device before exchanging data (only endpointId and name), so I feel I remove my last metadata slot if I use name as a substitute for endpointId.
As of today, you can't get your own endpoint id. We didn't see a reason you'd need it. Can you give a more detailed example of an algorithm where you need to know your own id?
i think you want to get your endpointId and sent its to other devices to know you again ?
if yes
let's think like that :
other devices will get your EndpointID and save it every time you connect to them
1)you have an Arrylist<EndPointObject> listOfUsers where EndPointObject it's an Object contain informations about Connected Endpoint Device (you create this class).
we w'ill use this Arry list to save recieved Endpoint informations
2)you need to make EndPointObject class Serializable by implements Serializable,you are doing that to make it able to be converted to Byte[] and send it in payload
public class EndPointObject implements Serializable
{
String endpointId ;
.
.
.
}
3)this is the Converting class add it to your project
public class SerializeHelperForPayLoad {
public static byte[] serialize(Object object) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
// transform object to stream and then to a byte array
objectOutputStream.writeObject(object);
objectOutputStream.flush();
objectOutputStream.close();
return byteArrayOutputStream.toByteArray();
}
public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException{
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return objectInputStream.readObject();
}
}
4) now the strategy is every time you connect to an endpoint Device you will exchange yours EndpointObject informations,so in payloadcallback
PayloadCallback mPayloadCallback =
new PayloadCallback() {
#Override
public void onPayloadReceived(String endpointId, Payload payload) {
if (payload.getType() == Payload.Type.BYTES) {
try{
onDataReceived(endpointId, SerializeHelperForPayLoad.deserialize(payload.asBytes()));
} catch (IOException | ClassNotFoundException e) { e.getMessage(); }
}
}
// onData recieved void
void onDataReceived(String endpointId, Object object) {
// do something with your Object
EndPointObject recieved_user_info = new EndPointObject();
if (object.getClass() == EndPointObject.class){
//casting
recieved_user_info = (EndPointObject) object;
//now add his end pointid to his information
recieved_user_info.setEndpointId(endpointId);
listOfUsers.add(recieved_user_info);
}
}
i'm very new in nearby technology ,but i hope that's helpful ,
by this way you can ask other end endpoint to send you your own endpointid every time

Hundreds of streams are allocated on the server when using gRPC in Android requests

I use gRPC from Google for work with server, but after some time I notices that streams are allocated on server and only when I close my app they closes.
GatewayGrpc.GatewayBlockingStub stub = getGatewayBlockingStub();
Gw.GetRequest request = new Gw.GetRequest();
request.authToken = authToken;
request.requestId = requestId;
Gw.GetResponse response = stub.get(request);
How to release this connections?
If by "hundreds of streams" you meant "hundreds of connections," then you probably aren't shutting down the ManagedChannel. getGatewayBlockingStub() is probably internally creating a ManagedChannel. You need to call ManagedChannel.shutdown().
Normally Channels are to be reused. Channels lazily initialize any TCP connections and don't reconnect unless there are new RPCs.

EADDRINUSE When creating server socket on google glass

I am developing a google glass/android application. It is a video streaming application that has a server/client setup where the phone/glasses is the server and hooks the pc up with the session description for playing the video. It works great on the android and everything runs fine but as soon as I try to test it on the google glass it throws an error at this line
sSocket = new ServerSocket(sPort);
The exception message says "EADDRINUSE" which I'm assuming means the port is already opened but I never opened it. Even if I had opened it and my program didn't close it I changed the port a couple of times and it still says it's in use.
Thanks
Tyler,
Google Glass, like android, consistently will have many of it's ports occupied by applications running in the background. When creating a socket for your server to listen on, you have two choices:
1) Have a predetermined list of ports you can choose to have your server listen on.
If you choose to do this, then you can simply have a datastructure (list, queue, heap [if you have some priority of which ports you would like to use], etc) which contain all of your ports, then you can simply traverse them until you find an open port.
This can be achieved in the following manner:
private ServerSocket allocatePort(List<Integer> myArray) throws IOException {
for (int individualPort : myArray) {
try {
return new ServerSocket(individualPort);
} catch (IOException io) {
continue; // An exception will be thrown if this port is currently in use. It's OK, let's try another port.
}
}
// When no ports are available, let's throw an exception stating we were unable to find an open port.
throw new IOException("we were unable to find an open port");
}
Then simply invoke this method within your as follows:
int[] arrayOfPorts = {5000, 5001, 5002, 8000, 8001, 8002, 8003};
List<Integer> myArray = new ArrayList<>();
myArray = IntStream.of(arrayOfPorts).boxed().collect(Collectors.toList());
ServerSocket sSocket = allocatePort(myArray);
2) If you don't mind which port to listen in on, you can use the constructor to pick any available port.
This can be achieved as follows:
ServerSocket sSocket = new ServerSocket(0);
You can read up more on ServerSocket's Javadocs. Notice under the parameter's subsection:
port - the port number, or 0 to use a port number that is automatically allocated.
Please let me know if you have any questions!

createRfcommSocketToServiceRecord works but listenUsingRfcommWithServiceRecord does not

I am trying to control a Hands-Free link with my device. The following works just fine:
UUID HFP_UUID_GET_HF = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
BluetoothSocket aBluetoothSocket = mDevice
.createRfcommSocketToServiceRecord(HFP_UUID_GET_HF);
and I get a socket that I can read and right to. No problem. However, I also want to listen for an incoming connection and get that socket. I tried this:
UUID HFP_UUID = UUID.fromString("0000111F-0000-1000-8000-00805F9B34FB");
UUID HFP_UUID_GET_HF = UUID.fromString("0000111E-0000-1000-8000-00805F9B34FB");
BluetoothServerSocket tmp = mBluetoothAdapter.listenUsingRfcommWithServiceRecord("HFP", HFP_UUID);
BluetoothSocket aBluetoothSocket = tmp.accept();
However, even though the two devices connect I never get a socket back. BTW if I use the UUID that starts with 111E in this second code block here I get a service discovery io error, which makes sense -- I know that my device is using uuid 111F and the other device uses UUID 111E.
Has anyone ran into this issue before? I need to be able to have complete control over all data that gets sent from the phone on that rfcomm channel. I cannot use reflection ; i.e.
Class<?>[] args = new Class[] { int.class };
int HFP_CHANNEL = 10;
Method listenOn = BluetoothAdapter.class.getDeclaredMethod("listenUsingRfcommOn", args);
BluetoothServerSocket my_server = (BluetoothServerSocket) (listenOn.invoke(mBluetoothAdapter,
new Object[] { HFP_CHANNEL }));
BluetoothSocket m_BluetoothSocket = my_server.accept();
because that also throws an io error -- channel already in use, unless anyone knows a way to turn off the hands-free system service. Afaik that is part of bluetoothd (Im using Android 4.1 here) and I need that to remain running (Im not sure if I even can turn it off)

Android usb host: asynchronous interrupt transfer

I'm trying to connect a USB-Device ( build by myself ) to communicate with my development board ( ODROID-X )
Unfortunately, the examples are very little, as far as the asynchronous communication. I'd some problems with the interrupt driven data exchange - how to build the connection by using the asynchronous interrupt mode?
In one direction, the transmission was possible ... but in both it doesn't work. Is there an example like this:
send a ByteBuffer with endpoint_OUT
get a message from device on endpoint_IN
both in interrupt mode.
Thanks a lot for your support.
Hardy
Perhaps I am misunderstanding the question here.
The sample missile lanucher app that is part of the API package from level 12 onwards uses the queue() and requestWait() methods to handle interrupt type endpoints.
Requests are either In or Out and depend on the direction of the EndPoint.
The code for a pretty noddy request->reply looks something like this. You would want to structure real code differently but this gives you the gist of what needs to happen (I hope)
public void run() {
int bufferMaxLength=mEndpointOut.getMaxPacketSize();
ByteBuffer buffer = ByteBuffer.allocate(bufferMaxLength);
UsbRequest request = new UsbRequest(); // create an URB
request.initialize(mConnection, mEndpointOut);
buffer.put(/* your payload here */;
// queue the outbound request
boolean retval = request.queue(buffer, 1);
if (mConnection.requestWait() == request) {
// wait for confirmation (request was sent)
UsbRequest inRequest = new UsbRequest();
// URB for the incoming data
inRequest.initialize(mConnection, mEndpointIn);
// the direction is dictated by this initialisation to the incoming endpoint.
if(inRequest.queue(buffer, bufferMaxLength) == true){
mConnection.requestWait();
// wait for this request to be completed
// at this point buffer contains the data received
}
}
}
If you are actually looking for a way to run this IO in an asynchronous manner without binding a thread to it, then I think you need to consider using the DeviceConnection.getFilehandle() method to return a standard file handle which in theory you can then use as if it were any other file type resource. I would note however that I have not tried this.
If neither of these addresses the issue please revise the question to clarify what you are struggling to find examples of.
I hope this helps.

Categories

Resources