Problems with specific unix commands while using Jsch (Exec) on Android - android

Hello i was doing a couple of days and research and some problem analysis, but i have no clue how to solve my Problem right now.
Maybe someone can help....
I am using Jsch for Android devices to access my raspberry pi in order to set some specific commands.
I began with Jsch shell command and everything worked fine besides the fact that i was never able to close a connection due to an infinite loop.
I tried to switch to Exec especially because i just want to send a couple of commands and do not really need to nood what happens on the shell.
Anyways... here is my code:
The intention is to send a cec sleep signal to my tv...
public c_jsch(String userName, String password,
String connectionIP, String knownHostsFileName)
{
JSch jsch = new JSch();
System.out.println("com.jcraft.jsch BBÄÄÄHHMM");
try
{
Session session = jsch.getSession("pi", "192.168.188.23", 22);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword("raspberry");
session.connect();
String command = "/home/pi/.xbmc-current/xbmc-bin/bin/cec-client -s -d 1";
String command2 = "tx 10 36 \r \n";
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(command);
channel.setInputStream(null);
channel.connect();
InputStream in = channel.getInputStream();
//NOT YET USEFUL
OutputStream out = channel.getOutputStream();
System.out.println("com.jcraft.jsch Unix system connected...");
byte[] tmp = new byte[1024];
while (true)
{
while (in.available() > 0)
{
int i = in.read(tmp, 0, 1024);
if (i < 0){
break;
}
System.out.print("com.jcraft.jsch Feedback: " + new String(tmp, 0, i));
// NOT WORKING
out.write(command2.getBytes());
out.flush();
System.out.println("com.jcraft.jsch Command flushed");
}
if (channel.isClosed())
{
System.out.println("com.jcraft.jsch exit-status: " + channel.getExitStatus());
break;
}
try
{
Thread.sleep(1000);
}
catch (Exception ee)
{
}
}
channel.disconnect();
session.disconnect();
System.out.println("com.jcraft.jsch exit-status: DONE");
}
catch (Exception e)
{
System.out.println("com.jcraft.jsch exit-status: " + e.getMessage());
}
}
Trying this code throws no error messages but a disappointing exit status-message: 127.
This means command not found.... so i assume there is a big difference between shell and exec commands ... with shell i works like a charm on ssh.
I hope you can help me.
:::Update, as i was first working with Pipes | that are not sufficient for exec and had to add Outputstream in order to send commands after connected to the channel i was able to realise sending commands to my Tv... thank you

I updated my code above and added /r /n to the string that i was going to flush. this was actually the open issue. – DerKai

Related

Connect to ELM327 // Select protocol

I am trying to connect to a ELM327 device via bluetooth.
The library I am using:
https://github.com/eltonvs/java-obd-api
Establishing a bluetooth connection works fine and I can reset the device:
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress);
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
final BluetoothSocket socket;
try {
socket = device.createInsecureRfcommSocketToServiceRecord(uuid);
socket.connect();
Log.d("xx", "1. Reset");
ObdResetCommand obdResetCommand = new ObdResetCommand();
obdResetCommand.run(socket.getInputStream(), socket.getOutputStream());
System.out.println(obdResetCommand.getFormattedResult());
Log.d("xx", "2. Echo Off");
EchoOffCommand echoOffCommand = new EchoOffCommand();
echoOffCommand.run(socket.getInputStream(), socket.getOutputStream());
System.out.println(echoOffCommand.getFormattedResult());
Log.d("xx", "3. LineFeed Off");
LineFeedOffCommand lineFeedOffCommand = new LineFeedOffCommand();
lineFeedOffCommand.run(socket.getInputStream(), socket.getOutputStream());
System.out.println(lineFeedOffCommand.getFormattedResult());
}
Output:
D/xx: 1. Reset
I/System.out: ELM327v1.5
D/xx: 2. Echo Off
I/System.out: OK
D/xx: 3. LineFeed Off
I/System.out: OK
The part that is not working is to select the protocol and read a voltage value:
SelectProtocolCommand selectProtocolCommand = new SelectProtocolCommand(ObdProtocols.AUTO);
try {
selectProtocolCommand.run(socket.getInputStream(), socket.getOutputStream());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
ModuleVoltageCommand moduleVoltageCommand = new ModuleVoltageCommand();
try {
moduleVoltageCommand.run(socket.getInputStream(), socket.getOutputStream());
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
What I observe is that the protocol selection is finished very quickly without any output. When I compare the protocol selection part to other apps like "torque lite", this takes much longer and I see flashing lights on my ELM327 device, which is not the case when running my code.
The ModuleVoltageCommand crashes then with:
br.ufrn.imd.obd.exceptions.UnableToConnectException: Error running
Control Module Power Supply [01 42], response: ...UNABLETOCONNECT
I verified the dongle is working with other apps, so this must be an issue with my code.
What am I doing wrong?
I'm the creator of this library, thanks for using my project!
This is an issue with the ECU, when you change the protocol, the next command will usually fail. What I usually do is sending a dump command that's expected to fail (so you just ignore any raised exception for this command) and then I send the commands I really want to run.
Hope it solves your issue!

Starting adb logs on internal storage without going into the shell

I am trying to start internal logs within my android devices without having to go directly into the adb shell. I have to script this process so I can run it from a program.
I am aware that you can take the following steps to start internal logs on an android device:
Open a cmd prompt
enter 'adb shell'
enter 'logcat -v time -f /sdcard/LogFile.txt&'
The above will start a logcat process within the actual device. I can now unplug my phone from the computer and move around then come back and collect the logs once my test is complete. It's crucial that I am able to start this process and be able to unplug my device with the logs still running.
To my knowledge running 'adb shell' in front of any command would run as if it were in the shell. Therefore by this logic I tried running:
Method 1:
'adb shell logcat -v time -f /sdcard/LogFile.txt&'
This command did properly start the log on the device which is great. However, once I unplug from my computer the logcat process stops.
Method 2:
'adb shell "logcat -v time -f /sdcard/LogFile.txt&" '
This didn't seem to do anything at all on the phone and I don't know why.
Method 3
I have tried the scripting method as well where I run a Batch file that contains only:
'adb shell < Commands.txt'
Where commands has the single line:
'logcat -v time -f /sdcard/LogFile.txt&'
This doesn't appear to do anything. It appears to send the command once the window comes up but doesn't actually perform the action.
Any help on this topic would be greatly appreciated. Thanks.
you can use this code in application class. so when app will launch this code will start executing. and it will create new log file according to current time.
Thread t = new Thread(new Runnable() {
public void run() {
while (collectLog == true) {
try {
Thread.sleep(1000 * 60 * 6);
StringBuilder log = null;
Date now = new Date();
String fileName = formatter.format(now);
File file = new File(dir, fileName + "_logcat2.txt");
try {
Process process = Runtime.getRuntime().exec("logcat -d");// d will dump logs
//Process process = Runtime.getRuntime().exec("logcat -c"); c will clear logs
// process = Runtime.getRuntime().exec("logcat -f " + file);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
log = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
log.append("\n");
}
} catch (IOException e) {
}
try {
//to write logcat in text file
FileOutputStream fOut = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fOut)
// Write the string to the file
osw.append(log.toString());
osw.flush();
osw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();

LuaSocket server don't accept clients

Im making a lua script running at my pc, and need to connect from my android.
So in the lua script I just put this:
local socket = require 'socket'
local server = socket.tcp()
print("createdserver")
server:bind('*',7070)
print("binded")
while 1 do
server:listen(32)
local client = server:accept()
-- make sure we don't block waiting for this client's line
client:settimeout(10)
-- receive the line
local line, err = client:receive()
-- if there was no error, send it back to the client
if not err then client:send(line .. "\n") end
-- done with client, close the object
client:close()
end
And at android I got a really simple socket connection:
public Connection(String ip, int _port) {
//inMessage = new NetworkMessage();
buffer = new byte[16394];
try {
serverAddres = InetAddress.getByName(ip);
socket = new Socket(serverAddres, _port);
socketOut = socket.getOutputStream();
} catch (IOException e) {
Log.e("Connect", e.getMessage());
}
}
At android it just stays at "new Socket" and dont connect.
Im not familiar with lua but my understanding is that you are writing a new line to the socket and you want to receive on the Android side.
Normally if that is the case you need to get the inputStream not the output one since you are waiting for results. Furthermore you need to indefinitely (or till some conditions are met) to listen to the input stream for data on a separate thread (a standard in):
while(true){
if (inputStreamReader().read() != -1){
// do you processing
}
}
My notebook was changing its IP address so I couldnt reach it from the android, already solved!

How would you format the sending of a serial command from Android over bluetooth?

I have an iRobot with a RooTooth installed, which is a bluetooth to serial converter. It is said to operate just like a serial port and data should be received as such. I have been able to use a terminal program to send serial commands directly to it over a serial cable, and it works fine.
I can also use the app I have written to send commands from my phone to my computer which is monitoring incoming bluetooth commands, and it receives them exactly as intended.
However, when I send it from my phone to the rootooth, nothing happens. Is there something wrong about how I am sending the commands? Shown below is how I do it:
This is within a handler:
case SUCCESS_CONNECT:
ConnectedThread connectedThread = new ConnectedThread((BluetoothSocket)msg.obj);
String s = "128 131";
byte[] command = s.getBytes();
connectedThread.write(command);
Toast.makeText(getApplicationContext(), s, 0).show();
s = "137 0 100 128 0";
byte[] command1 = s.getBytes();
connectedThread.write(command1);
Toast.makeText(getApplicationContext(), s, 0).show();
This is my write() function
public void write(byte[] bytes) {
Log.i(tag, "In write");
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
The issue must be formatting, no? Anybody with experience here, your help would be greatly appreciated!
Recently I have attempted this:
String [] s = new String[2];
s[0] = "128";
s[1] = "131";
for(int i = 0; i < s.length; i++){
byte[] command = s[i].getBytes();
connectedThread.write(command);
Thread.yield();
}
String [] t = new String[5];
t[0] = "137";
t[1] = "0";
t[2] = "100";
t[3] = "128";
t[4] = "0";
for(int i = 0; i < t.length; i++){
byte[] command = t[i].getBytes();
connectedThread.write(command);
Thread.yield();
}
I have also tried this recent version including a "/n" string but that has not done anything either.
For anybody else that happens to run into this problem, it turns out that a .write() from an OutputStream will take ints even though it says it will only take byte[]. Creating an array of ints for each command and sending them int by int ended up working. No need to include spaces or new lines.

Getting output from busybox commands within Android app

For the life of me, I can't get my app to get the response from a process calling busybox from within su shell.
I've tried three different methods, as well as tried a combination of the three to get it to work, but I can never get the output from anything using busybox, only the rest of the commands.
To be more specific, I can get it to return commands like ls /data and cat suchandsuch.file, but anything that starts with "busybox" (i.e. busybox mount, busybox free) just won't show anything.
This was the method that got the closest for me, this code works with ls /data, but not "busybox free"
This one would run the command (for the most part), and return an empty string instead of loop endlessly from the inputstream.
Process p;
try {
p = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/sh"});
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
stdin.writeBytes("ls /data\n");
DataInputStream stdout = new DataInputStream(p.getInputStream());
byte[] buffer = new byte[4096];
int read = 0;
String out = new String();
while(true){
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<4096){
break;
}
}
Toast.makeText(getApplicationContext(), out, Toast.LENGTH_SHORT).show();
} catch (IOException e) {
e.printStackTrace();
}
The toast near the bottom shows everything from ls /data, but when changed to anything for busybox, its blank or null.
I've also tried both of these, but neither of them worked. (I was passing the process to them after the command was run.)
Both of these would always result in the app freezing right when you hit the button for the methods.
String termReader(Process process){
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
try {
int i;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((i = reader.read(buffer)) > 0)
output.append(buffer, 0, i);
reader.close();
return output.toString();
} catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
}
String processReader(Process process){
InputStream stdout = process.getInputStream();
byte[] buffer = new byte[1024];
int read;
String out = new String();
while(true){
try {
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<1024){
break;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return out;
}
There's no stack traces to work with, so I'm starting to get a bit stumped.
Edited with the code proposed below, uhm, below :D
I changed it around a small bit to make it a oneclick run thing for easier troubleshooting and testing.
This also freezes when it tries to read the inputstream, and if I call stdin.writeBytes("exit\n") before trying to read the stream it gives me the blank answer from closing the terminal, if I call it after, it loops endlessly.
void Run() {
String command = "busybox traceroute\n";
StringBuffer theRun = null;
try {
Process process = Runtime.getRuntime().exec("su");
DataOutputStream stdin = new DataOutputStream(process.getOutputStream());
stdin.writeBytes(command);
BufferedReader reader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
while ((read = reader.read(buffer)) > 0) {
theRun = output.append(buffer, 0, read);
}
reader.close();
process.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Toast.makeText(getApplicationContext(), theRun, Toast.LENGTH_SHORT).show();
}
It seems like its skipping the first line (the busybox info line you get every time you invoke the command) and not catching the rest of the data. Ive tried all variations I can think of to get this working right :/
If anybody's got some insight on this, I'd be greatly appreciative :)
Here is a quick solution... It is a utility class I created just for this. You can use the native shell, a root shell if the device is rooted, or set a custom shell. Here you go.
https://github.com/jjNford/android-shell
I've found a sort of a workaround for this.
First of all, running commands linked to busybox in my case would never return their output through their InputStream, no matter what method I tried (And I tried ALOT lol).
This is what I found out I could do. It's a bit tedious, and doesn't give you the full output, but if you want something to rely on whether a command fired off properly (in my case, my app just wouldn't work right if I couldn't compare how everything ran.)
You cant get the input from the process, but you CAN get the exit value if you work it right :) this works for anything that doesn't give you a complex response (like using cat on a large file)
The difference between the two is easy to find, for instance:
command = "cat /sys" // works, exits with 1
command = "cat /init.rc" doesnt work, exits with 0
This is how I set it up to work easily. Run the commands as normal using the method provided by MasterJB:
process p;
try {
p = Runtime.getRuntime().exec(new String[]{"su", "-c", "/system/bin/sh"});
DataOutputStream stdin = new DataOutputStream(p.getOutputStream());
stdin.writeBytes(command);
stdin.writeBytes("echo $?\n");
DataInputStream stdout = new DataInputStream(p.getInputStream());
byte[] buffer = new byte[4096];
int read = 0;
String out = new String();
while(true){
read = stdout.read(buffer);
out += new String(buffer, 0, read);
if(read<4096){
break;
}
// here is where you catch the error value
int len = out.length();
char suExitValue = out.charAt(len-2);
Toast.makeText(getApplicationContext(), String.valueOf(suExitValue), Toast.LENGTH_SHORT).show();
return0or1(Integer.valueOf(suExitValue), command); // 0 or 1 Method
// end catching exit value
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
I also found it easier to make a "0 or 1" method to return what happened. In this example it's fired as a toast. You may also want to test if the char is actually an integer, as some commands give no exit value whatsoever (weird, I know. One instance is ls /sys, this returns a blank exit value when run through a su terminal.)
String return0or1 (int returnValue, String command){
String message = command + " - Cannot get return value.";
if (returnValue == 0){
message = command + " - successful.";
return message;
}
if (returnValue == 1){
message = command + " - failed.";
return message;
}
return message;
}
With a little bit of research you can match just about any exit value with proper responses, just gotta capture them right :)
These methods return just whether the command ran (0), but if it gets a double or triple char exit code, the last digit may be 0 when it failed (i.e. when exit value is 10), so this will work in most cases, but needs to be expanded upon to catch double and triple values.

Categories

Resources