To use sudo feature, what should I write in the my application? Should I write something? If yes, can you tell me how I can write sudo application? Do I need to change manifest.xml, or add some Java code?
Assuming the device is rooted and your app has been granted superuser permissions, you can use the following method to run commands as root:
public static void runAsRoot(String[] cmds){
Process p;
try {
p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
BufferedReader bf = new BufferedReader(new InputStreamReader(p.getInputStream()));
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd+"\n");
String test;
while((test = bf.readLine()) != null)
{
Log.i(TAG, test);
}
}
//os.writeBytes("exit\n");
os.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
Just pass it a list of commands in a String array.
Related
I'm trying to reboot programmatically my Galaxy S3.
Things that I've tried:
try {
Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", "reboot" });
proc.waitFor();
} catch (Exception ex) {
Log.i("RebootActivity", "Could not reboot", ex);
}
try {
Runtime.getRuntime().exec(new String[]{"su","-c","reboot now"});
} catch (IOException e) {
e.printStackTrace();
}
try
{
Process process = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(process.getOutputStream());
os.writeBytes("reboot now\n");
}
catch (Throwable t)
{
t.printStackTrace();
}
Do you guys have any idea how to accomplish this?
Thanks.
Try to do one normal string looking like 《su \n reboot; \n》 instead of an array.
Try to get the answer from the shell, that helps a lot for debugging.
What are the permissions of your su binary? If they would be wrong, you could try to 《chmod 7777 /system/xbin/su》 after 《mount -o remount,rw /system》
Here is some example code: (to run the string command, which is a \n and or ; separated list of linux shell commands)
StringBuffer commandOutput = new StringBuffer();
try {
Process process = Runtime.getRuntime().exec("su\n");
DataOutputStream out = new DataOutputStream(process.getOutputStream());
out.writeBytes("export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/vendor/lib:/system/lib\n");
out.writeBytes(command+"\n");
out.flush();
process.waitFor();
BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()));
int numRead;
char[] buffer = new char[1000];
while ((numRead = in.read(buffer)) > 0) {
commandOutput.append(buffer, 0, numRead);
}
in.close();
process.waitFor();
} catch ...
return commandOutput.toString();
You could possibly use the PowerManager to make it reboot (this does not guarantee that it'll reboot - OS may cancel it):
http://developer.android.com/reference/android/os/PowerManager.html#reboot(java.lang.String
http://developer.android.com/reference/android/Manifest.permission.html#REBOOT
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
}
}
}
Using adb shell we can clear application data.
adb shell pm clear com.android.browser
But when executing that command from the application
String deleteCmd = "pm clear com.android.browser";
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec(deleteCmd);
} catch (IOException e) {
e.printStackTrace();
}
Issue:
It doesn't clear the user data nor give any exception though I have given the following permission.
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA"/>
Question:
How to clear another app application data using adb shell?
This command worked for me:
adb shell pm clear packageName
Afaik the Browser application data is NOT clearable for other apps, since it is store in private_mode. So executing this command could probalby only work on rooted devices. Otherwise you should try another approach.
The command pm clear com.android.browser requires root permission.
So, run su first.
Here is the sample code:
private static final String CHARSET_NAME = "UTF-8";
String cmd = "pm clear com.android.browser";
ProcessBuilder pb = new ProcessBuilder().redirectErrorStream(true).command("su");
Process p = pb.start();
// We must handle the result stream in another Thread first
StreamReader stdoutReader = new StreamReader(p.getInputStream(), CHARSET_NAME);
stdoutReader.start();
out = p.getOutputStream();
out.write((cmd + "\n").getBytes(CHARSET_NAME));
out.write(("exit" + "\n").getBytes(CHARSET_NAME));
out.flush();
p.waitFor();
String result = stdoutReader.getResult();
The class StreamReader:
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.CountDownLatch;
class StreamReader extends Thread {
private InputStream is;
private StringBuffer mBuffer;
private String mCharset;
private CountDownLatch mCountDownLatch;
StreamReader(InputStream is, String charset) {
this.is = is;
mCharset = charset;
mBuffer = new StringBuffer("");
mCountDownLatch = new CountDownLatch(1);
}
String getResult() {
try {
mCountDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
return mBuffer.toString();
}
#Override
public void run() {
InputStreamReader isr = null;
try {
isr = new InputStreamReader(is, mCharset);
int c = -1;
while ((c = isr.read()) != -1) {
mBuffer.append((char) c);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (isr != null)
isr.close();
} catch (IOException e) {
e.printStackTrace();
}
mCountDownLatch.countDown();
}
}
}
To clear Application Data Please Try this way.
public void clearApplicationData() {
File cache = getCacheDir();
File appDir = new File(cache.getParent());
if (appDir.exists()) {
String[] children = appDir.list();
for (String s : children) {
if (!s.equals("lib")) {
deleteDir(new File(appDir, s));Log.i("TAG", "**************** File /data/data/APP_PACKAGE/" + s + " DELETED *******************");
}
}
}
}
public static boolean deleteDir(File dir) {
if (dir != null && dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
return dir.delete();
}
To reset/clear application data on Android, you need to check available packages installed on your Android device-
Go to adb shell by running adb shell on terminal
Check available packages by running pm list packages
If package name is available which you want to reset, then run pm clear packageName by replacing packageName with the package name which you want to reset, and same is showing on pm list packages result.
If package name isn't showing, and you will try to reset, you will get Failed status.
On mac you can clear the app data using this command
adb shell pm clear com.example.healitia
To clear the cache for all installed apps:
use adb shell to get into device shell ..
run the following command : cmd package list packages|cut -d":" -f2|while read package ;do pm clear $package;done
// To delete all the folders and files within folders recursively
File sdDir = new File(sdPath);
if(sdDir.exists())
deleteRecursive(sdDir);
// Delete any folder on a device if exists
void deleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory())
for (File child : fileOrDirectory.listFiles())
deleteRecursive(child);
fileOrDirectory.delete();
}
This question has been asked here before but the solutions provided are not working..I am trying to display the contents of /data/dalvik-cache folder. I know that to do this we need to become su. I even did that but still i am unable to execute a shell command..
package org.linuxconfidg.Example2;
import android.app.Activity;
import android.widget.*;
import android.os.Bundle;
import java.io.*;
public class Example2Activity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String lsreturn=myFunLs();
TextView tv=new TextView(this);
tv.setText("Hello Sindhu !! Try to get it \n"+lsreturn);
setContentView(tv);
}
public String myFunLs()
{
try {
// Executes the command.
Process process;
process = Runtime.getRuntime().exec("/system/bin/su");
process = Runtime.getRuntime().exec("/system/bin/ls /data/dalvik-cache > /data/local");
pr
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) {
output.append(buffer, 0, read);
}
reader.close();
// Waits for the command to finish.
process.waitFor();
return output.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
Can anyone please help me out in finding out how to run linux commands in android application. I am testing this app in my emulator which is defaultly rooted
You can't simply run 'su' on the emulator, there's no root access by default. You'll need to install the 'su' program as well as the SuperUser.apk, and you'll have to do this each time you start the emulator unless using snapshots.
More information and links to the files you need can be found here on SO as well as this blog post by Russell Davis
I think the problem comes from the fact that you are using TWO different process instances.
You have to be on the su process to carry on sending commands:
You can check the question "Read command output inside su process"
for an answer.
Then I tried & managed to make working code (I'm sure it works!)
public void runAsRoot(String[] cmds) throws Exception {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
InputStream is = p.getInputStream();
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd+"\n");
int readed = 0;
byte[] buff = new byte[4096];
// if cmd requires an output
// due to the blocking behaviour of read(...)
boolean cmdRequiresAnOutput = true;
if (cmdRequiresAnOutput) {
while( is.available() <= 0) {
try { Thread.sleep(200); } catch(Exception ex) {}
}
while( is.available() > 0) {
readed = is.read(buff);
if ( readed <= 0 ) break;
String seg = new String(buff,0,readed);
console.println("#> "+seg);
}
}
}
os.writeBytes("exit\n");
os.flush();
}
In the below example, I try to execute "/system/bin/screencap" to capture android screen.
via adb:
> adb shell
# /system/bin/screencap -p /sdcard/myscreenshot.png
via Android app:
sh = Runtime.getRuntime().exec("su", null,null);
OutputStream os = sh.getOutputStream();
os.write(("/system/bin/screencap -p " + path).getBytes("ASCII"));
os.flush();
os.close();
sh.waitFor();
Hope this helps.
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"});