Qt/C++: interrupt QProcess arbitrarily with button (simulate ^c) - android

So I need to make a Qt Application (with GUI) that executes the "adb logcat" command (it's a log that keeps being generated until ^c is pressed).
I need a GUI button to make the process stop and pass the output to a Text Browser.
This is the code I use to get the QProcess output:
QProcess process;
process.start("adb logcat");
process.waitForFinished(-1);
QByteArray logcatOut = process.readAllStandardOutput();
ui->devicesOutput->setText(logcatOut);
Thank you

process.waitForFinished(-1);
would prevent your program of being executed further, till the process "adb" has finished.
So your GUI will be frozen.
You should define QProcess process as a class variable. Use QProcess
*process; instead of creating it on stack. (Best practice for all QObject derivates)
Declare a slot which handles clicked-signal of your button.
call process->terminate() in the slot.

use QProcess::terminate to stop running app

Related

How can i avoid android background process starvation?

I'm running a native background process from an android app with Runtime.exec().
It seems like every few seconds the process is put to sleep for like 200 ms.
It looks like the android operating system is just starving that process.
Is there some way I can change the process priority from a background process to some other type of priority?
Assume the application that's running the process can get super user access.
Edit:
The command I'm using to run the process:
String fullCommand = "export LD_LIBRARY_PATH=LD_LIBRARY_PATH:. && ./MyProc";
Runtime.getRuntime().exec(new String[]{"su", "-c ", fullCommand });
If you know the PID of the process, you can change its priority with renice
(taken from this answer).
You can call renice like this:
renice priority [[-p] pid ...] [[-g] pgrp ...] [[-u] user ...]
Trying using the .setPriority() method.
Thread t=new Thread();
t.setPriority(Thread.MAX_PRIORITY);

Android- performing su commands programatically does not work

I need my app to perform some su commands programatically (phone is rooted).
When done using adb, the commands work.
For instance:
su -c "mkdir /sdcard/testdir" creates a directory called "testdir" in /sdcard.
When I call:
p = Runtime.getRuntime().exec("su -c \"mkdir /sdcard/testdir\"");
p.waitFor();
It just moves on and no change happens.
I tried reading the input:
DataInputStream dis = new DataInputStream(p.getInputStream());
while((temp = dis.readLine())!=null)
Log.d(ctx.TAG,"shell:"+temp);
But it reports nothing (loop does 0 iterations).
Has anyone ever faced this issue before? How can it be solved?
Needless to day, non-su commands do work programatically with this method.
Note: I gave mkdir as an example (I know it doesn't necessarily require su). I need a lot of varied commands to be performed under su
Thank you!
EDIT: when I call su -c "id" programatically, there's output that uid=0.
I can get stuck on a problem for days, and the moment I gather up the courage to ask about it on StackOverflow, it is solved within minutes.
The fix is:
p=Runtime.getRuntime().exec("su");
DataOutputStream dos = new DataOutputStream(p.getOutputStream());
dos.writeBytes("mkdir /sdcard/testdir\n");
dos.writeBytes("exit\n");
dos.flush();
dos.close();
p.waitFor();
Don't forget \n at the end of each command you write to the DataOutputStream, as it will not work without it.
You wrote that you "need varied commands to be performed under su". Note that the use of "Runtime.exec()" is discouraged by Chainfire, the developer of the most famous SuperSU root app.
It is tempting to use Runtime.getRuntime().exec("su -c [command]");, but you should be aware that [command] should be a single parameter, and thus may require quoting. Unfortunately both quoting the [command] parameter as well as passing the paramaters as separate variables to either Runtime.exec() or ProcessBuilder does not work consistently across all Android versions, and thus this construct should be avoided entirely. It is not impossible to do this right - but there's a high risk of problems.
See the How to SU Document. So you might want to follow his recommendation here:
3.2. Making the call
A common method to call su that avoids the known issues listed above is by creating an interactive shell and piping commands to it. This is done by calling Runtime.getRuntime().exec("su");, and retrieving input and output streams from the returned Process object. Doing this is a fairly straight-forward piece of code, but including the debug logs and checks it's a bit long to reproduce here.
The core code is located here: [libsuperuser :: Shell.java # GitHub]. Shell.run() is a generic call to run shell code, the following more specific (static) utility functions are the ones you will probably end up using:
List<String> Shell.SH.run(String command)
List<String> Shell.SH.run(List<String> commands)
List<String> Shell.SH.run(String[] commands)
List<String> Shell.SU.run(String command)
List<String> Shell.SU.run(List<String> commands)
List<String> Shell.SU.run(String[] commands)
The SH variants are used for a non-root shell, where the SU variants are used for a root shell. These calls return a List containing the output of the shell commands. If there was no output, the list is empty, but not null. The result is only null in case an error occured - including the user not granting your app su access. These are blocking calls.
Note that in debug compiles, all shell STDIN/STDOUT/STDERR will be logged to logcat, and these calls will (intentionally) crash your app if called from the main thread. The reason for this will be discussed in section 4. When to call su.
If you use double quotes, it will work:
su -c ""command with args""
You might be calling Runtime.getRuntime().exec() in main thread and p.waitFor() makes your main thread wait until it executes. Try calling in another thread, like the following snippet.
new Thread(){
#override
public void run(){
p = Runtime.getRuntime().exec("su -c \"mkdir /sdcard/testdir\"");
p.waitFor();
}.start();
}

Application Works Fine In Debugging But On Run

I'm trying to execute a command within an application. I'm doing it using a library called RootTools. The command I'm using is:
RootTools.getShell(true).add(new CommandCapture(0, 'dd if=boot.img of=/dev/block/platform/omap/omap_hsmmc.0/by-name/boot')).waitForFinish();
The application works fine when I enabled Eclipse debugging mode. However that line did not work when it runs normal mode.
This class uses AsyncTask which allows me to execute another command once the main task is completed in a method called onPostExecute().
I noticed that under any mode the method onPostExecute works perfectly. But not the main method, doInBackground().
I tried placing a Thread.sleep to add some delay but that didn't help either.
Try turning RootTools debugging on when running that command and verify that the command is being executed by examining the debug output in logcat.
RootTools.debugMode = true;
try to use the Async task in a function to get rid of this problem as follows
private void anyfunction()
{
new AsyncTask().execute();
}

Handle main commands in android native activity

In android native activity you can handle main commands from system in your own method. I know how to do this, but i dont know what all states i can handle. I know few states like APP_CMD_SAVE_STATE, APP_CMD_INIT_WINDOW... but that´s not all. I cant find list of states or android_native_app_glue.h header file anywhere. Can someone refer me or write list of events with their numebers and when they´r called?Thanks
void CMDMethod(struct android_app* app, int32_t state)
{
switch(state)
{
case APP_CMD_SAVE_STANE: //some code
break;
//what can be next cases?
}
}
void android_main(struct android_app* state)
{
state->onAppCmd = CMDMethod;
}
Heres the enum found in android_native_app_glue.h
enum {
APP_CMD_INPUT_CHANGED,
APP_CMD_INIT_WINDOW,
APP_CMD_TERM_WINDOW,
APP_CMD_WINDOW_RESIZED,
APP_CMD_WINDOW_REDRAW_NEEDED,
APP_CMD_CONTENT_RECT_CHANGED,
APP_CMD_GAINED_FOCUS,
APP_CMD_LOST_FOCUS,
APP_CMD_CONFIG_CHANGED,
APP_CMD_LOW_MEMORY,
APP_CMD_START,
APP_CMD_RESUME,
APP_CMD_SAVE_STATE,
APP_CMD_PAUSE,
APP_CMD_STOP,
APP_CMD_DESTROY,
};
APP_CMD_INPUT_CHANGED - Command from main thread: the AInputQueue has changed. Upon processing this command, android_app->inputQueue will be updated to the new queue (or NULL).
APP_CMD_INIT_WINDOW - Command from main thread: a new ANativeWindow is ready for use. Upon receiving this command, android_app->window will contain the new window surface.
APP_CMD_TERM_WINDOW - Command from main thread: the existing ANativeWindow needs to be terminated. Upon receiving this command, android_app->window still contains the existing window; after calling android_app_exec_cmd it will be set to NULL.
APP_CMD_WINDOW_RESIZED - Command from main thread: the current ANativeWindow has been resized. Please redraw with its new size.
APP_CMD_WINDOW_REDRAW_NEEDED - Command from main thread: the system needs that the current ANativeWindow be redrawn. You should redraw the window before handing this to android_app_exec_cmd() in order to avoid transient drawing glitches.
APP_CMD_CONTENT_RECT_CHANGED - Command from main thread: the content area of the window has changed, such as from the soft input window being shown or hidden. You can find the new content rect in android_app::contentRect.
APP_CMD_GAINED_FOCUS - Command from main thread: the app's activity window has gained input focus.
APP_CMD_LOST_FOCUS - Command from main thread: the app's activity window has lost input focus.
APP_CMD_CONFIG_CHANGED - Command from main thread: the current device configuration has changed.
APP_CMD_LOW_MEMORY - Command from main thread: the system is running low on memory. Try to reduce your memory use.
APP_CMD_START - Command from main thread: the app's activity has been started.
APP_CMD_RESUME - Command from main thread: the app's activity has been resumed.
APP_CMD_SAVE_STATE - Command from main thread: the app should generate a new saved state for itself, to restore from later if needed. If you have saved state, allocate it with malloc and place it in android_app.savedState with the size in android_app.savedStateSize. The will be freed for you later.
APP_CMD_PAUSE - Command from main thread: the app's activity has been paused.
APP_CMD_STOP - Command from main thread: the app's activity has been stopped.
APP_CMD_DESTROY - Command from main thread: the app's activity is being destroyed, and waiting for the app thread to clean up and exit before proceeding.
I think I saw something about that in this book http://www.packtpub.com/android-ndk-beginners-guide/book. But can be wrong. In there there definitely is a chapter about creating a completely native activity with that loop processing all those states.

Runtime.exec() bug: hangs without providing a Process object

Whether I use this:
process = Runtime.getRuntime().exec("logcat -d time");
or that:
process = new ProcessBuilder()
.command("logcat", "-d", "time")
.redirectErrorStream(true)
.start();
I get the same results: it often hangs within the exec() or start() call, no matter what I tried to do!
The thread running this cannot even be interrupted with Thread.interrupt()! The child process is definitely started and if killed the above commands return.
These calls may fail on first attempt, so THERE IS NO WAY TO READ THEIR OUTPUT! I can also use a simple "su -c kill xxx" command line, same result!
EDIT: Started debugging the java_lang_ProcessManager.cpp file in an NDK project with some debugging logs! So here is what I found so far, after the fork() the parent does this:
int result;
int count = read(statusIn, &result, sizeof(int)); <- hangs there
close(statusIn);
Though the child process is not supposed to block on it: That's what the child does (if started at all!):
// Make statusOut automatically close if execvp() succeeds.
fcntl(statusOut, F_SETFD, FD_CLOEXEC); <- make the parent will not block
// Close remaining unwanted open fds.
closeNonStandardFds(statusOut, androidSystemPropertiesFd); <- hangs here sometimes
...
execvp(commands[0], commands);
// If we got here, execvp() failed or the working dir was invalid.
execFailed:
int error = errno;
write(statusOut, &error, sizeof(int));
close(statusOut);
exit(error);
The child can fail for 2 reproducible reasons:
1- child code is not running, but the parent believes it is!
2- child blocks on
closeNonStandardFds(statusOut, androidSystemPropertiesFd);
In either case the read(statusIn...) in the parent ends in deadlock! and a child process is left dead (and cannot be accessed, pid unknown, no Process object)!
This problem is fixed in Jelly Bean (Android 4.1) but not in ICS (4.0.4) and I guess it will never be fixed in ICS.
Above solution didn't prove to be reliable in any ways, causing more issues on some devices!
So I reverted back to the standard .exec() and kept digging...
Looking at the child code that hangs, I noticed the child process will hang while trying to close all file descriptors inherited from the parent (except the one created within the exec() call) !
So I search the whole app code for any BufferedReader/Writer and similar classes to make sure those would be closed when calling exec()!
The frequency of the issue was considerably reduced, and actually never occured again when I removed the last opened file descriptor before calling exec().
NB: Make sure SU binary is up-to-date, it can actually cause this issue too!
Enjoy your search ;)
Bug fix in Bionic was commited monthes ago, but it still hasn't been included in Android 4.0.4.
I have the same problem on ICS (seem to works fine on Android < 4). Did you find a solution?
A simple workaround could be to call the "exec" method in a dedicated thread with a timeout-join so that this situation could be "detected" (yes I know it's not very elegant...)

Categories

Resources