For some reason I cannot reboot Android devices using Runtime.getRuntime().exec("/system/bin/reboot");. I have tried the following code on 3 devices now without luck. One was built from rowboat-android source. The other two are the Motorola Droid Pro (Rooted, stock) and the HTC Ledgent (Rooted, Cynogen Mod). All devices are running Android 2.2 Froyo.
Does anyone know why? su works as well as the Super User application is visible. I should note various other shell commands do work, like netcfg (chmod' to 777) and ls.
public static boolean executeCommand(SHELL_CMD iShellCmd){
String cmd = null;
String line = null;
String fullResponse = null;
Process lPs = null;
Log.d(Global.TAG,"--> !!!!! Running shell command");
if (iShellCmd == SHELL_CMD.restart_device){
cmd = "reboot";
}
Log.d(Global.TAG,"--> About to exec: " + cmd);
try {
lPs = Runtime.getRuntime().exec("su");
lPs = Runtime.getRuntime().exec("/system/bin/reboot");
} catch (Exception e) {
e.printStackTrace();
}
BufferedWriter out = new BufferedWriter(new OutputStreamWriter(lPs.getOutputStream()));
BufferedReader in = new BufferedReader(new InputStreamReader(lPs.getInputStream()));
try {
while ((line = in.readLine()) != null) {
Log.d(Global.TAG,"--> Command result line: " + line);
if (fullResponse == null){
fullResponse = line;
}else{
fullResponse = fullResponse + "\n" + line;
}
}
} catch (Exception e) {
e.printStackTrace();
}
Log.d(Global.TAG,"--> Full response was: " + fullResponse);
return true;
}
Depending on how you've obtained root permission on your device, you can do any of the following:
Runtime.getRuntime().exec(new String[]{"/system/xbin/su","-c","reboot"});
or
Runtime.getRuntime().exec(new String[]{"/system/bin/su","-c","reboot"});
or
Runtime.getRuntime().exec(new String[]{"su","-c","reboot"});
Probably better to test all three scenarios in your application.
Finally after weeks of searching:
Runtime.getRuntime().exec(new String[]{"/system/bin/su","-c","reboot now"});
Try running "su /system/bin/reboot" instead of su and the command on different lines. That might help :)
If you want a button to be pressed try:
final Button button = (Button) findViewById(R.id.button1);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// Perform action on click
try {
Runtime.getRuntime().exec(new String[]{"/system/bin/su","-c","reboot"});
} catch (IOException e) {
}
}
});
By the way for this code to work the button has to be called button1.
instead of {"/system/bin/su","-c","reboot"} i changed the "/system/bin/su" part to just "su" and then it worked for me.
Like this Runtime.getRuntime().exec(new String[]{"su","-c","reboot"});
Related
I need to read and filter logcat logs within my application, of others applications. I found other questions and the most useful if Read logcat programmatically within application.
So I tried to write my code, but the result is always the same, that is it returns the logcat logs that made until the application was started.
public void getLog() {
edLog.setText("");
Log.e("imgspa", "ciao");
try {
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "*:I"});
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "B4A:I"});
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "-v", "time", "-e", "*VFY*"});
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "-v", "time", "*:I"});
//Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d"});
Process logcat = Runtime.getRuntime().exec(new String[]{"logcat", "-d", "-v", "threadtime", "*:*"});
BufferedReader br = new BufferedReader(new InputStreamReader(logcat.getInputStream()));
String line;
final StringBuilder sb = new StringBuilder();
String separator = System.getProperty("line.separator");
sb.append("inizio");
sb.append(separator);
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append(separator);
}
sb.append("fine");
edLog.setText(sb.toString());
} catch (IOException e) {
e.printStackTrace();
}
}
As you can see I tried different solutions but no one can help me.
I need to get the logcat, where the application name is "B4A".
Let me point out that:
- I have a rooted device
- I already added the READ_LOGS permissions
As of JellyBean, you cannot access the log in logcat that was not add there by your application.
link
Since Android 4.1 it's no possible to read logs of other applications.
See an explanation
For rooted device you need to obtain the READ_LOGS permission manually
String pname = getPackageName();
String[] CMDLINE = { "su", "-c", null };
if(getPackageManager().checkPermission(android.Manifest.permission.READ_LOGS, pname) != 0) {
try {
CMDLINE[2] = String.format("pm grant %s android.permission.READ_LOGS", pname);
java.lang.Process p = Runtime.getRuntime().exec(CMDLINE);
int res = p.waitFor();
Log.d(TAG, "exec returned: " + res);
if (res != 0)
throw new Exception("failed to become root");
} catch (Exception e) {
Log.d(TAG, "exec(): " + e);
}
}
Or just try it with .exec("su -c logcat -d")
The change is that third party applications can no longer get the read logs permission, however every app can read the logs containing only the lines they have written, without needing any permission.
Unless you rooted you cannot do this since Jelly Bean. See this Android bug report and this related discussion. Quote:
img.simone For more query you have to read this
Hope it will help you!!
I have an Activity which every second write a counter to the logcat:
Runnable rLog = new Runnable() {
#Override
public void run() {
i++;
Log.d("bbb", "i= " + i);
handler.postDelayed(this, 1000);
}
};
In addition - I have a service which read from "logcat -s bbb" and log it:
Runnable rGetLog = new Runnable() {
#Override
public void run() {
Runtime rt = Runtime.getRuntime();
Process process = null;
try {
process = rt.exec("logcat -s bbb");
} catch (IOException e1) {
e1.printStackTrace();
}
BufferedReader bufferedReader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
try {
while ((line = bufferedReader.readLine()) != null)
{
Log.d("aaa", "get line = " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
This code works well. The problem starts when I change the tag "bbb" to a real tag such as "AndroidRuntime" or another tag... I got an empty response from logcat
(if I run at the same time "logcat -s AndroidRuntime" from adb I got lots of lines...)
Who knows what the problem is? what can be different?
Thanks!
From Android Jelly Bean, applications cannot read log entries from other applications, unless your device is rooted and you read the logs as superuser.
try using sudo to get permissions:
process = rt.exec("su && logcat -s YOUR_TAG");
TL:DR; version ;)
my app should run without user interaction (autostart etc works)
it should update itself (via apk) without any user interaction
rooted devices are possible
.
problem:
querying a newer apk from a server works
when starting the apk with a (view?) intent, the "install app" prompt pops and needs a user confirmation
How do I solve this without any user interaction?
http://code.google.com/p/auto-update-apk-client/
This seems to be a solution, but there must be better approach.
I already found this: Install Application programmatically on Android
but that doesn't solve my problem.
Solved it! :D
It just works in rooted devices but works perfectly.
Using the unix cmd "pm" (packageManager) allows you to install apks from sdcard, when executing it as root.
Hope this could help some people in the future.
public static void installNewApk()
{
try
{
Runtime.getRuntime().exec(new String[] {"su", "-c", "pm install -r /mnt/internal/Download/fp.apk"});
}
catch (IOException e)
{
System.out.println(e.toString());
System.out.println("no root");
}
}
Required permissions:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
My suggestion is to use plugin mechanism instad of updating the app. You can dynamically load classes from the Web and run them inside your app without any user interaction. There is a lot of resources spread across the Internet:
How to load a Java class dynamically on android/dalvik?
http://android-developers.blogspot.com/2011/07/custom-class-loading-in-dalvik.html
If su -c doesn't work, try su 0 (only rooted devices can do su!)
The full answer looks like this:
private void installNewApk()
{
String path = mContext.getFilesDir().getAbsolutePath() + "/" + LOCAL_FILENAME;
mQuickLog.logD("Install at: " + path);
ProcessUtils.runProcessNoException(mQuickLog, "su", "0", "pm", "install", "-r", path);
}
With this class defined:
public class ProcessUtils {
Process process;
int errCode;
public ProcessUtils(String ...command) throws IOException, InterruptedException{
ProcessBuilder pb = new ProcessBuilder(command);
this.process = pb.start();
this.errCode = this.process.waitFor();
}
public int getErrCode() {
return errCode;
}
public String getOutput() throws IOException {
InputStream inputStream = process.getInputStream();
InputStream errStream = process.getErrorStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
String line;
StringBuilder sb = new StringBuilder();
while ((line = br.readLine()) != null) {
sb.append(line + System.getProperty("line.separator"));
}
br = new BufferedReader(new InputStreamReader(errStream));
while ((line = br.readLine()) != null) {
sb.append(line + System.getProperty("line.separator"));
}
return sb.toString();
}
public static String runProcess(String ...command) throws IOException, InterruptedException {
ProcessUtils p = new ProcessUtils(command);
if (p.getErrCode() != 0) {
// err
}
return p.getOutput();
}
public static void runProcessNoException(String ...command) {
try {
runProcess(command);
} catch (InterruptedException | IOException e) {
// err
}
}
}
On a rooted android device, I tried to run a cat command that read kernel log, as follow:
Process p = Runtime.getRuntime().exec("su");
p = Runtime.getRuntime().exec("/system/bin/cat /proc/kmsg");
The su command was successfully executed but not the cat.
I tried to read the output of the command using getInputStream() but nothing was there, as follow:
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((read = err.read(buffer)) > 0)
{ //read error to buffer
catOutput.append(buffer, 0, read);
}
in.close();
I used the same code with ls command instead of displaying the kernel log, it worked just fine and show me the result.
I wonder if what error I am getting and wantted to see the error message on the shell when executing the cat command. Tried the p.getErrorStream() but it doesn't give me any result.
Could any one help me with this ? Thanks.
Here's a comprehensive example on how to do this - note that I got the idea from this answer:
public void catKmsg() {
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
StringBuilder sbstdOut = new StringBuilder();
StringBuilder sbstdErr = new StringBuilder();
String command="/system/bin/cat /proc/kmsg";
try { // Run Script
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(command);
osw.flush();
osw.close();
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (osw != null) {
try {
osw.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
if (proc != null) {
proc.waitFor();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
sbstdOut.append(ReadBufferedReader(new InputStreamReader
(proc.getInputStream())));
sbstdErr.append(ReadBufferedReader(new InputStreamReader
(proc.getErrorStream())));
if (proc.exitValue() != 0) {
}
}
I finally found the solution for the problem by using RootTools library.
Recently released (few months after my question was asked), RootTools provides a easy-to-use tool set that helps running commands that required root privilege. I created a wrapper to check if root access is available before executing shell command:
void testRootToolsCommand(String command){
if (RootTools.isRootAvailable())
toastMessage("Root is available !!!");
else {
toastMessage("NO ROOT !!! ");
return;
}
int timeOut = 1000;
try {
List<String> output = RootTools.sendShell(command,timeOut);
toastMessage("OUTPUT of the command \n" + output.toString());
} catch (RootToolsException re) {
toastMessage("Funny thing happened with RootTools!!! ");
} catch (TimeoutException te)
{
toastMessage("Timeout exception - Increase timeout !!! !!! ");
}
catch (Exception e) {
toastMessage(e.getMessage().toString());
}
}
An example of a function call is:
testRootToolsCommand("cat /proc/kmsg > /sdcard/jun11_4h51.txt");
Note: The Tool also support running multiple commands at once.
Please Tell me it is possible to run a shell script file from My Android application.
and read the data from script file.
If it is possible than how to proceed , Please give me some guideline.
You can use this code snippet (from Aaron C)
void execCommandLine(String command)
{
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
try
{
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(command);
osw.flush();
osw.close();
}
catch (IOException ex)
{
Log.e("execCommandLine()", "Command resulted in an IO Exception: " + command);
return;
}
finally
{
if (osw != null)
{
try
{
osw.close();
}
catch (IOException e){}
}
}
try
{
proc.waitFor();
}
catch (InterruptedException e){}
if (proc.exitValue() != 0)
{
Log.e("execCommandLine()", "Command returned error: " + command + "\n Exit code: " + proc.exitValue());
}
}
But this requires root access I think.
You could also try to use GScript
I've been using this to run shell scripts in my android app. Only thing I've yet to figure out how to do is direct the output to where I want it. You don't need root for this, which is why I'm posting.
Process process = Runtime.getRuntime().exec("top -n 1");
//Get the output of top so that it can be read
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));