How to kill an android app from another app? [duplicate] - android

I'm developing my first Android application, and I'm curious if there are any "standard" ways for executing privileged shell commands. I've only been able to find one way to do it, by executing su, and then appending my commands to stdin of the su process.
DataOutputStream pOut = new DataOutputStream(p.getOutputStream());
DataInputStream pIn = new DataInputStream(p.getInputStream());
String rv = "";
// su must exit before its output can be read
pOut.writeBytes(cmd + "\nexit\n");
pOut.flush();
p.waitFor();
while (pIn.available() > 0)
rv += pIn.readLine() + "\n";
I've read about wrapping privileged (superuser) calls up in JNI: is this possible? If so, how would one go about accomplishing it? Other than that, are there any other ways of calling privileged instructions from Java?

As far as I know, you can only run command-line commands using root privileges. You can use this generic class I made that wraps the root access in your code:
http://muzikant-android.blogspot.com/2011/02/how-to-get-root-access-and-execute.html
All you need to do is extend this class and override the getCommandsToExecute method to return the commands you want to execute as root.
public abstract class ExecuteAsRootBase
{
public static boolean canRunRootCommands()
{
boolean retval = false;
Process suProcess;
try
{
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
if (null != os && null != osRes)
{
// Getting the id of the current user to check if this is root
os.writeBytes("id\n");
os.flush();
String currUid = osRes.readLine();
boolean exitSu = false;
if (null == currUid)
{
retval = false;
exitSu = false;
Log.d("ROOT", "Can't get root access or denied by user");
}
else if (true == currUid.contains("uid=0"))
{
retval = true;
exitSu = true;
Log.d("ROOT", "Root access granted");
}
else
{
retval = false;
exitSu = true;
Log.d("ROOT", "Root access rejected: " + currUid);
}
if (exitSu)
{
os.writeBytes("exit\n");
os.flush();
}
}
}
catch (Exception e)
{
// Can't get root !
// Probably broken pipe exception on trying to write to output stream (os) after su failed, meaning that the device is not rooted
retval = false;
Log.d("ROOT", "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}
return retval;
}
public final boolean execute()
{
boolean retval = false;
try
{
ArrayList<String> commands = getCommandsToExecute();
if (null != commands && commands.size() > 0)
{
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
// Execute commands that require root access
for (String currCommand : commands)
{
os.writeBytes(currCommand + "\n");
os.flush();
}
os.writeBytes("exit\n");
os.flush();
try
{
int suProcessRetval = suProcess.waitFor();
if (255 != suProcessRetval)
{
// Root access granted
retval = true;
}
else
{
// Root access denied
retval = false;
}
}
catch (Exception ex)
{
Log.e("ROOT", "Error executing root action", ex);
}
}
}
catch (IOException ex)
{
Log.w("ROOT", "Can't get root access", ex);
}
catch (SecurityException ex)
{
Log.w("ROOT", "Can't get root access", ex);
}
catch (Exception ex)
{
Log.w("ROOT", "Error executing internal operation", ex);
}
return retval;
}
protected abstract ArrayList<String> getCommandsToExecute();
}

A possible solution I know is to sign your application as system, which is not exactly the same as root as far as I know: How to sign Android app with system signature?. But I suppose this is not what you wanted.
Another thing I did is to create a native application that does what is needed, running it as an external process. But it is necessary to give this native application the privileges you need and the suid bit, provided the partition is not nosuid. But this is not what you needed either I suppose.
C code called through JNI should be subject to the same limitations as living in the same process, I suppose.
If you have the su binary available then you can run commands from java with something like: Runtime.getRuntime().exec("su -c reboot").
I don't remember any other way.

I was in the need of doing this in a rooted device recently and found out about libsu, which is a library allowing to execute su commands.
This library is written by the author of Magisk.
I have a rooted device with Magisk and libsu works pretty well from my app. The first time you execute a su command, Magisk will show a dialog where you grant or deny the root capabilities.
Running a command with libsu from an app is as simple as doing the following:
Shell.cmd("find /dev/block -iname boot").exec()

Related

su behaves differently on adb and on program

I have a custom device android 4.3. Problem occurs with some commands, one of an example:
su -c 'pm enable com.android.systemui'
When I run this command over adb it works. However when I run the code programatically using this library it just does not work, no error is shown as well.
Interesting observations:
Shell.SU.available() : false
Shell.SU.isSELinuxEnforcing() : false
Ok so device is rooted. Any reason why you are trying to do that command using that library?
What I am trying to say is why can't you just run the shell command yourself?
runRootCommand method:
static boolean runRootCommand(String command) {
boolean status = true;
DataOutputStream os = null;
try {
Process process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
} catch (IOException | InterruptedException e) {
Log.e(TAG, e.toString());
status = false;
} finally {
try {
if (os != null)
os.close();
} catch (IOException e) {
Log.e(TAG, e.toString());
status = false;
}
}
return status;
}
And then call that method like this:
boolean success = runRootCommand("pm enable com.android.systemui");
if(success) {
// command was successful
} else {
// command was NOT successful
}
This will run the command as "su" (superuser).
Hope this helps.

Getting error "Root access rejected" in android application

I am getting an error while running this code and the error is " Root access rejected [java.io.IOException] : Error running exec(). Command: [su] Working Directory: null Environment: null"
try
{
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream osRes = new DataInputStream(suProcess.getInputStream());
if (null != os && null != osRes)
{
// Getting the id of the current user to check if this is root
os.writeBytes("id\n");
os.flush();
String currUid = osRes.readLine();
boolean exitSu = false;
if (null == currUid)
{
retval = false;
exitSu = false;
Log.d("ROOT", "Can't get root access or denied by user");
}
else if (true == currUid.contains("uid=0"))
{
retval = true;
exitSu = true;
Log.d("ROOT", "Root access granted");
}
else
{
retval = false;
exitSu = true;
Log.d("ROOT", "Root access rejected: " + currUid);
}
if (exitSu)
{
os.writeBytes("exit\n");
os.flush();
}
}
}
catch (Exception e)
{
Log.d("ROOT", "Root access rejected [" + e.getClass().getName()
+ "] : " + e.getMessage());
}
This is because apps do not have a super user permission in the android system.
Well, first of all ... you need to get your device rooted. A little Google Search will help with that.
If your application will be running on anonymous client devices, then you should better check first if the device is rooted or not. My library has a root availability check method which looks like below, but it doesn't work in a few cases.
public static boolean hasRoot() {
String tags = Build.TAGS;
if ((tags != null) && tags.contains("test-keys"))
return true;
try {
if (new File("/system/app/Superuser.apk").exists())
return true;
} catch (Exception exception) {
exception.printStackTrace();
}
String[] commands = {
"/system/xbin/which su",
"/system/bin/which su",
"which su"
};
for (String command : commands) {
try {
Runtime.getRuntime().exec(command);
return true;
} catch (Exception exception) {
exception.printStackTrace();
}
}
return false;
}
Then you can proceed with your procedure to execute a superuser shell & check for uid.
Or if you want to simplify things, you can have a look at my open-source Android CLI library with which, this task would be simpler. You can find the github project here.
If your phone has root access then you can fire shell scripts using Process and Runtime class..
see the below link:-
Run a shell command as root on android?
http://en.wikipedia.org/wiki/Rooting_%28Android_OS%29

Need help for an app to push a file with a button

Okay, Im very new to android programming, and im making a root app to push a specific file to /system/framework with a button
how can i accomplish this? i tried the command style and none are working
There are a number of steps you need to take to be able to do this.
First (of course) the device needs to be rooted. You can check this in a number of ways.
The following code will check if the "su" command returns a command not found error (su binary exists) AND that a super user app is installed to grant the permissions after you request them.
private boolean isDeviceRooted() {
// check for SU command in shell
if ((new ExecShell().executeCommand(ExecShell.SHELL_COMMAND.su_check) != null) && (appInstalled("eu.chainfire.supersu.nonag") || appInstalled("eu.chainfire.supersu") || appInstalled("com.noshufou.android.su") || appInstalled("com.koushikdutta.superuser"))) {
Log.i(TAG, "Device Rooted");
return true;
}
// check for SU application installed
if (appInstalled("eu.chainfire.supersu.nonag") || appInstalled("eu.chainfire.supersu") || appInstalled("com.noshufou.android.su") || appInstalled("com.koushikdutta.superuser")) {
Log.i(TAG, "Device Rooted");
return true;
}
Log.i(TAG, "Device Not Rooted");
return false;
}
private boolean appInstalled(String uri) {
PackageManager pm = getPackageManager();
boolean app_installed = false;
try {
pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
app_installed = true;
} catch (PackageManager.NameNotFoundException e) {
app_installed = false;
}
return app_installed;
}
If this code returns false you could set a flag or display and error, else continue.
Then, once you know the device is rooted, you want to execute the necessary root commands to do what you need.
The following code takes as input String[] of commands, and executes them sequentially as root.
public boolean RunAsRoot(String[] cmds) {
Process p;
try {
p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
try {
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd + "\n");
}
os.writeBytes("exit\n");
os.flush();
return true;
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return false;
}
}
In your case you will first want to mount /system as rw. There is lots of information on the web to help you find the command you want but it will look something like
mount -o remount rw /system mount -o remount rw /system
You then want to move the file you want using either mv or cp.
An example of the use of the root commands would be
String[] cmds = {"mount -o remount rw /system mount -o remount rw /system", "cp /sdcard/myfile /system/framework/myfile"};
if(!RunAsRoot(cmds)){
//Commands failed to run, show an error/retry
}
This covers the "hard" bit which is the root functionality.
An easy tutorial for the button can be found here.
Program flow could be
onCreate(){
checkIsRooted();
Button x = (Button) findViewById(R.id.x);
x.setOnClickListener(onClickListener());
}
onClickListener(){
onClick(){
String[] cmds = {...};
if(!runAsRoot(cmds))
AlertDialog.Builder.makeText(...).show();
}
}
NOTE, THIS IS PSEUDO CODE, YOU CAN'T COPY AND PASTE THIS CODE TO MAKE IT WORK, YOU NEED TO DO IT PROPERLY YOURSELF!

Clear android application user data

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();
}

How do I open a socket below 1024

I'm trying to create a ServerSocket on a port below 1024.
Obviously, this is restricted to root access only.
But I'm struggling on getting the right permissions for my app.
I'm using this code, for example, to test if I have root access (or trigger the dialog)
But it still doesn't let me ServerSocket work.
AFAIK, the process that is created with the SU command has the root access, not my app. How do I get root access into my own process?
public stat
ic boolean getRoot() {
try {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
os.writeBytes("echo \"Do I have root?\" >/system/sd/temporary.txt\n");
os.writeBytes("exit\n");
os.flush();
try {
p.waitFor();
if (p.exitValue() != 255) {
return true;
} else {
return false;
}
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
Afaik you cannot open a port below 1024 under *nix systems if you're not root...

Categories

Resources