Python - How to hide output after killed specified process - android

now i try to create a python script to get Android logcats automatically
below seciton is part of my codes
logcat_process = subprocess.Popen('adb logcat -v time > logcat.log', shell=True)
time.sleep(5)
os.kill((logcat_process.pid)+1, signal.SIGKILL)
however, every time after os.kill terminate the process,
it will print message like
"/bin/sh: line 1: 13961 Killed: 9 adb logcat -v time > logcat.log"**
on the screen.
Does anybody have any idea how to hide this message?
I want the result print of script more simple and clear....

You can do something like this:
logcat_process = subprocess.Popen('adb logcat -v time > logcat.log', shell=True)
time.sleep(5)
save_stdout = sys.stdout
sys.stdout = open(r'/youlib..../trash.txt', 'w')
os.kill((logcat_process.pid)+1, signal.SIGKILL)
# regain stdout to screen
sys.stdout.close()
sys.stdout = save_stdout
It will divert the stdout to the trash.txt file at the kill operation.

redirect the stdout/stderr in python and add a filter.

Related

subprocess.check_output fails to execute a command but the same works in windows

I am trying to connect two devices to my pc and run some commands on them using python and adb.
when I run the command from the command prompt, it goes through fine, but when i put those in the python script, they give me errors.
this is causing the errors all the time:
from subprocess import check_output, CalledProcessError
try:
adb_ouput = check_output(["adb","devices","-l","|", "grep", "\"model\""])
print adb_ouput
except CalledProcessError as e:
print e
The error message I get is this:
Usage: adb devices [-l]
Command '['adb', 'devices', '-l', '|', 'grep', '"model"']' returned non-zero exit status 1
When I try the same code without the grep command, it works
adb_ouput = check_output(["adb","devices","-l"])
It gives me the right output.
When I try the same in windows command prompt, It works fine (I am replacing grep with FINDSTR because i'm using it in windows, and I have tried doing the same in the python script as well, with 'shell = True' and also without.)
eg:
adb devices -l | FINDSTR "model"
This gives me an ouptut without any problems.
The output I get is
123ab6ef device product:xxxxxxxxx model:xxxxxxxxx device:xxxxxxxxx
bd00051a4 device product:yyyyyyyyyy model:yyyyyyyyyy device:yyyyyyyyy
I am trying to understand where I am going wrong here, but can't figure it out.
So far I have checked the docs: https://docs.python.org/3/library/subprocess.html
https://docs.python.org/3/library/subprocess.html#subprocess.CalledProcessError
These just give me the error codes.
I have also looked at these answers:
Python, adb and shell execution query
I took some error checking from here and added to my code.
Python subprocess.check_output(args) fails, while args executed via Windows command line work OK
python check_output fails with exit status 1 but Popen works for same command
I think i am close but just can't put my finger on it.
Any help would be appreciated.
First
adb_ouput = check_output(["adb","devices","-l","|", "grep", "\"model\""])
certainly requires shell=True, but even with that it's not equivalent to
adb devices -l | FINDSTR "model"
When using check_output, you're passing "model" as grep argument literally but you should pass just model. "model" is not in your output (with quotes) so grep fails to find it, and returns exitcode 1 which is not really an error for grep but makes check_output trigger an exception because it expects 0.
So I would to this as a quickfix:
adb_ouput = check_output(["adb","devices","-l","|", "grep", "model"],shell=True)
And as a longfix I'd perform the grep command directly with python.
adb_output = check_output(["adb","devices","-l"])
for l in adb_output.splitlines():
if "model" in l:
print(l)

Execute a command if new line is found in script output

I am having huge difficulties writing a simple bash script.
I basically want to monitor a debug log 24/7 and listen for a new line. If there is a new line I want it to execute a command.
logcat | grep com.amazon.firelauncher/.Launcher
When I run this code, I get a live debug window, I want to execute a command (reboot for an example) whenever a new line pops up in that command.
How can this be done? I tried sending the output to a file and monitoring that file for filesize change, but it does not work. I really need assistance!
You should be able to use read for this:
#!/bin/bash
while logcat | grep "com.amazon.firelauncher/.Launcher" | read -r line; do
echo "Text read from logcat"
/path/to/executable
done
This was my final answer, but I would not have concluded it if it was not for the help of Martin Konecny, he did all the heavy lifting.
#!/bin/bash
am monitor | while read -r line; do
if [[ $line == *"firelauncher"* ]]
then
am start com.newlauncher.launcher
fi
done

Python can not capture full adb logs

What I want to achieve -
running adb log (logs are running),
doing some activity on android,
stop/end log capture (ctrl+c),
post processing of logs.
Only issue which i face -
can not capture full logcat log in file
import sys
import subprocess
import time
import ctypes
# start
print "test start"
time.sleep(5)
# log capturing start, log does not stop it will keep on running
proc = subprocess.Popen("adb logcat -v time",stdout=subprocess.PIPE )
time.sleep(3) # just so it runs for a while
print "calc start"
time.sleep(5)
#START test************************************
Some code for testing
#CTRL C*************************************************
try:
ctypes.windll.kernel32.GenerateConsoleCtrlEvent(0, 0)
proc.wait()
except KeyboardInterrupt:
print "ignoring ctrlc"
print "still running"
#********************adb log saving******************
text = proc.stdout.read()
f = open('C:\Python27\out_logs_dd\log.txt', 'w')
f.write(text)
with open('C:\Python27\out_logs_dd\log.txt', 'w') as f:
f.write(text)
f.close()
When I run this code, everything is running but log size is so small.
I searched and came to know that "proc.communicate()"might be the solution.
I tried 'communicate' but could not solve the issue.
any help pointer pls.
Replacing proc.stdout.read() with proc.stdout.readline() solved it for me. stdout.read() reads everything until EOF - slowing down the speed drastically. A similar question: Communicate with subprocess without waiting for the subprocess to terminate on windows
you can use adb shell logcat instead of abd logcat in
proc = subprocess.Popen("adb shell logcat -v time",stdout=subprocess.PIPE)
it will give all logs.
i hope it will work.

How can I execute all the possible unix(shell) commands in android programmatically?

I have this .php file sending commands to my android application:
I have tried working with:
Runtime.getRuntime().exec(commandLine);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));
but the commands echo, pwd and some others are not working.
I get the following exception:
java.io.IOException: Error running exec(). Command: [pwd] Working Directory: null Environment: null
As far as I understand this is because there is not any shell environment.
Then I have tried writing in a .sh file the command I want and then execute the command this way:
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("sh /runCmds/shTest.sh");
InputStream is = proc.getInputStream();
and got solved the problem with pwd, echo and most of the commands.
But later on I realized that I want to keep the state of the commands I execute.
For example I want to change directory(cd data) and execute the command mkdir Apoel
And here is when I face my problem. What to do?
I came up with another idea:
Make a shell script (.sh) and each time the user wants to execute a command append the new command in it (and run the hole script(.sh) again). But I think is not a very good way to do it!
Is there any easy way to it? Can my application open a terminal easily?
Here is a code I found for a Terminal Emulator, but it is too complicated!
https://github.com/jackpal/Android-Terminal-Emulator
An interactive shell is one which remains running, waiting for new commands which it receives from stdin, while producing it's output to stdout and stderr - as a result, it's environment including any changes is retained for the duration of the session. For the shell to be useful to a user, stdin, stoud, stderr need to be connected through to the user - via the console, a serial line, or xterm, etc.
On Android, typically what you do is hook onto the pipes corresponding to stdin, stdout, stderr for the shell process that you've created, and use them to push in commands provided by your java program and accept output for your program to interpret/display.
The idea of creating a script and running it would only work in the case where all the commands are entered before any of them execute.
First, some background. On any Posix system, in the shell, there are 2 types of commands:
Internal commands (pwd,cd,echo)
external commands (ls,cp,mv, sometimes echo as well)
All the directory context commands (cd,pwd etc) are commands implemented inside the shell and thus require the shell to remain running, if the changes are to hold (for eg. cd /data/local/tmp).
On the other hand, external commands are standalone and can run indepenedently, but acquire their directory context from their parent process (in most cases, the shell).
Now to solve the problem. Yes, using a script is a good idea, but it is painful to implement, as it requires an overhead of file editing. However, we can use the shell to create a script on the fly and execute it using the -c option. For example:
/system/bin/sh -c 'cd /data/local/tmp; touch abc; cp abc def; cd /; rm /data/local/tmp/abc'
In summery:
String sPrefix="/system/bin/sh -c 'cd someplace;";
String sInputCmd=getCommand(); // this is simulating your command input
String sPostfix="'";
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(sPrefix+sInputCmd+sPostfix); // sh -c 'cd someplace; echo do something'
InputStream is = proc.getInputStream();
However, this does not give us the capability to set a directory context, so we need to simulate that. Directory contexts can be added by using the Runtime.exec(String command, String[] envp, File dir) method. With this we have the possibility of maintaining directory
context between commands. But how do we actually do that? One solution is to append pwd to the command and take the last line of the output as the new directory context. Thus
String sPath = "/"; // start in root directory
String sPrefix = "/system/bin/sh -c 'cd someplace;";
String sInputCmd; // this is simulating your command input
String sPostfix = ";echo;pwd'";
Runtime rt = Runtime.getRuntime();
while(!(sInputCmd=getCommand()).equals("")) {
File dir= new File(sPath);
Process proc = rt.exec(sPrefix+sInputCmd+sPostfix, NULL, dir);
InputStream is = proc.getInputStream();
// Do processing on input.
sPath= last_line_of_is ;
}
Finally, the last option is to integrate one of the terminal emulators into you app.
[1] http://docs.oracle.com/javase/6/docs/api/java/lang/Runtime.html#exec%28java.lang.String,%20java.lang.String%5B%5D,%20java.io.File%29

ADB Error codes

We have an android device and as part of testing I need to excute a console test application on the target device. If the test application detects an error it returns -1.
I can use adb shell to run the test applications remotely on the target but I can't find a way of getting back the return code. I need this so I that I can build this into an automated test suite.
I could try grepping the console output for some failure text but that is a bit grubby. Does anyone know of a more elegant solution?
This is a workaround to get the exit code:
adb shell '{your command here} > /dev/null 2>&1; echo $?'
This is a wrapper around adb in Ruby:
def adb(opt)
input = "#{adb_command} #{opt[:command]} #{opt[:params]}"
puts "Executing #{input}...\n"
output = nil
exit_code = 0
def wait_for(secs)
if secs
begin
Timeout::timeout(secs) { yield }
rescue
print 'execution expired'
end
else
yield
end
end
wait_for(opt[:timeout]) do
case opt[:command]
when :install, :push, :uninstall
output, exit_code = `#{input}`, $?.to_i
when :shell
input = "#{adb_command} shell \"#{opt[:params]}; echo \\$?\""
output = `#{input}`.split("\n")
exit_code = output.pop.to_i
output = output.join("\n")
else
raise 'Error: param command to adb not defined!'
end
end
return if opt[:ignore_fail] and output =~ /#{opt[:ignore_fail]}/
raise output unless exit_code == 0
end
You could use Facebook's fb-adb, a "A better shell for Android devices" which "propagates program exit status instead of always exiting with status 0".

Categories

Resources