How can I run Linux commands on an Android device? - android

On some Android devices, in the ADB shell, I can only run echo, cd, ls. When I run:
tar -cvf //mnt/sdcard/BackUp1669/apk/test.tar /mnt/sdcard/test.apk
Or the command cp, it returns:
sh: tar: not found
Why can I not run these commands? Some devices support these commands. My end goal is to copy a file from the /data/data folder to SD card. I got su and I got the following code:
int timeout = 1000;
String command = "tar -cvf /" + Environment.getExternalStorageDirectory() + "/cp/"
+ packageName + ".tar" + " " + path;
DataOutputStream os = new DataOutputStream(process.getOutputStream());
BufferedReader is = new BufferedReader(new InputStreamReader(new DataInputStream(
process.getInputStream())), 64);
String inLine;
try {
StringBuilder sbCommand = new StringBuilder();
sbCommand.append(command).append(" ");
sbCommand.append("\n");
os.writeBytes(command.toString());
if (is != null) {
for (int i = 0; i < timeout; i++) {
if (is.ready())
break;
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
if (is.ready()) {
inLine = is.readLine();
} else {
}
}
} catch (IOException e) {
e.printStackTrace();
}
It always stops in is.ready(), and when I changed it to process.waitfor() it also stopped. Why?

As far as i know, the only way to run shell commands is:
Process proc = Runtime.getRuntime().exec("your command");

You can run Linux commands on Android. But there are usually just very few pre-installed.
If you want to add more commands you might want to root your device and install busybox on it.
This is not for productive use within an application but can help you to work with your device.

If you have the binaries for your system, you can run anything on your system.
Saying that you have to understand that you have to find the binaries for tar.
Look here http://forum.xda-developers.com/showthread.php?t=872438
And possibly other places..

You can probably get this done by using a Terminal Emulator app. As you wrote above, I don't know how well DOS commands will work. But, a Terminal Emulator works without root.

You can install Termux app on your android device and run Linux command by using that app

Install busybox, then type the command in the following format:
busybox [linux command]
You cannot use all the linux commands without busybox, because Android doesn't have all the binaries that are available in a standard linux operating system.
FYI, a binary is just a file that contains compiled code. A lot of the default binaries are stored in /system/bin/sh directory. All these commands like 'cp' 'ls' 'get' etc, are actually binaries. You can view them through:
ls -a /system/bin/sh
Hope this helps.

In reply to Igor Ganapolsky, You would have to have a database set up for locate.
Probably find would be adequate for your needs.
example:
find -name *.apk

Related

Can't run exec("su") on a rooted Android Marshmallow device, other commands run fine

I have gone over all the possible answers to this questions, and none of them has worked for me. Seems like Android has very tightly blocked the running of the shell commands from within an app, even when the device is rooted.
I can do su and run commands perfectly fine from adb, but I cannot run them from the app itself. It fails with error:
Error running exec(). Command: [su] Working Directory: null Environment: null
I have searched for these errors and the solutions work for older versions of Android, not Marshmallow.
I have also tried libsuperuser (SuperSu), but it also fails on Marshmallow.
Other things I tried were like, e.g. for the device reboot:
Process p = Runtime.getRuntime().exec("su");
Process proc = Runtime.getRuntime().exec(new String[] { "su", "-c", "reboot" });
or
PowerManager pm = (PowerManager)...
Same with other operations. The commands fail right at su. I can't issue an adb command either from the app. But I can do both perfectly fine otherwise from the command line via adb shell.
The example which Android has on its website doesn't work either.
I read about disabling SELinux security and setting it to permissive mode. But that also require to run su first, where the app fails.
Now I am totally lost and don't know what to do next. I am really looking for a working solution since for this particular project, which requires the app to interact with the underlying hardware.
You need to first ensure you have busybox installed as that would install the list of most commonly used shell commands and then use the following code to run the command.
Runtime.getRuntime().exec("ls");
try {
Process chmod = Runtime.getRuntime().exec("/system/bin/chmod 777 " +fileName);
BufferedReader reader = new BufferedReader(new InputStreamReader(nfiq.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();
chmod.waitFor();
outputString = output.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Try this
Process command = Runtime.getRuntime().exec("su");
DataOutputStream dos = new DataOutputStream(p.getOutputStream());
dos.writeBytes("-c reboot\n");
dos.writeBytes("exit\n");
dos.flush();
dos.close();
p.waitFor();
It can take time to execute so u might wanna run this on worker thread
There is nothing that blocks shell commands in "Marshmallow" . I am using it inside my app and all commands work flawlessly. There is something else you are missing. First confirm that in your "/system/bin/" directory all files are present. Alternatively check in other device.
Try to add "sh -c " as the beginning of your shell command. Otherwise you will get the error message about null directory and environment.
Example: sh -c su

How to delete root app/app/ files?

My phone is rooted. I'm trying to do a very simple program. The program should delete file from app/app folder. How can I do this? I'm newbie, so example code is valued.
If your phone is rooted, you can issue commands as root through su—provided that the su binary is present and in your PATH—since Android is a variant of Linux. Simply execute the delete commands through Runtime.exec(), and Superuser should take care of the permission prompt.
Here's a simple example of its usage I took from this question:
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
You can delete all files inside a folder recursively using the below method.
private void DeleteRecursive(File fileOrDirectory) {
if (fileOrDirectory.isDirectory())
for (File child : fileOrDirectory.listFiles())
{
child.delete();
DeleteRecursive(child);
}
fileOrDirectory.delete();
}
On his github, Chainfire provides a sample implementation of a Shell class that you can use to execute the rm command as root. The rm command is the Linux variant of the command to delete files (and folders).
Code Snippet:
if(Shell.SU.available()){
Shell.SU.run("rm /data/app/app.folder.here/fileToDelete.xml"); //Delete command
else{
System.out.println("su not found");
Or if you are certain that the su binary is available, you can just run the delete command (commented line) and skip the check
Source: How-To SU

executing ffmpeg command with getRuntime().exec() command

i want to run ffmepg command directly on android.
a simple command
ffmpeg -i vid.mp4 out.mp4
now the issue is that i have searched the internet and found the best android ffmpeg can be found here
http://bambuser.com/opensource
I have downloaded it and read the readme file and compiled it. the folder is ffmpeg. I have kept it in <--projectfolder-->/ffmpeg/
there is a ffmpeg executeable file in ffmpeg folder called ffmpeg folder
i have copied it in files folder and run this command
try {
Toast.makeText(this, "Working", Toast.LENGTH_SHORT).show();
Process p = Runtime.getRuntime().exec("/data/data/com.koder.testffmpeg/files/ffmpeg -i /sdcard/vid.mp4 /sdcard/out.mp4");
} catch (IOException e) {
txt.setText(e.toString());
Toast.makeText(this, e.toString(), Toast.LENGTH_LONG).show();
e.printStackTrace();
}
according to this link
How do I reduce the video size captured by the default camera using FFMPEG in Android?
but still it does not work always exception i dont know what is going wrong
can someone plz help me with this
java.io.IOException: Error running exec(). Command:[/data/data/com.koder.testffmpeg/files/ffmpeg -i /sdcard/vid.mp4 /sdcard/out.mp4] Working Directory: null Environment:null
You should use getBaseContext().getApplicationInfo().nativeLibraryDir instead of "/data/data/com.example.ffmpegnew/files/"
Give executable permission to ffmpeg like so:
chmod 700 ffmpeg
Try using this:
Process proc = null;
ProcessBuilder pb = new ProcessBuilder();
proc = pb.command("String...yourCommand")
.redirectErrorStream(true).start();
BufferedReader bReader = new BufferedReader(new InputStreamReader(
proc.getInputStream()));
This code work for me for get system wakelock details in android.may be this will useful to you.
You could combine above answers like this:
Process p = Runtime.getRuntime().exec("chmod 700 "+getBaseContext().getApplicationInfo().nativeLibraryDir + "/ffmpeg ...");

Native Subprocess Can't Create File in Application Folder or on SDcard

Since this turned out to be a long read, I'll start with a very truncated version:
Are native processes not allowed to create/edit files created by their spawning java process regardless of having appropriate location/ permission/ file ownership?
The full question:
My application consists of a set of native binaries compiled with the NDK toolchain and a typical java Android interface. The native programs are packaged in the /assets folder and copied by the java application out into a /data/data/com.domain.app/nativeApplication folder.
There are two native application in question. One which modifies a jpeg created by the java layer, and a second which analyzes that jpeg and returns an int as output. The issue is this: When called by the java layer, the jpeg modifier doesn't work.
I've done a good amount of troubleshooting on it already so I'll try to dissuade you from some of the obvious potential answers starting with the most obvious.
Correct Compilation:
Through adb shell I can call both of the programs in question, as is, from the phone's disk. The second image analyzer program runs without a hitch when called either via adb or as designed in the software IF I do the intermediary step manually from adb.
Permissions:
Jpg Permission - The application has permission to write to external storage. I've tried to have the file read in from both the SDcard and /data/data/com.domain.app/nativeApp/img/name.jpg; no joy. As stated the second program operates as designed when the image is in either location, if I manually run the first program through adb.
File/Folder Permissions: All of the folders in ~/nativeApplication/* have been created BY the android application itself, it is the owner and it has chmodded all of the sub-directories and files to 777.
Supporting Code:
Calling the jpg converter process:
NativeSetup.changePermission("/data/data/com.domain.program/nativeApp/img/img1.jpg");
try {
Process jpegConvert = Runtime.getRuntime().exec("/data/data/com.domain.program/nativeApp/bin/jpegtransformer -opts /data/data/com.domain.program/nativeApp/img/img1.jpg > /data/data/com.domain.program/nativeApp/img/img2.jpg");
jpegConvert.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
Call used to create the files in ~/nativeApp/*
private static void copyFile(String assetPath, String localPath, Context context) {
try {
InputStream in = context.getAssets().open(assetPath);
FileOutputStream out = new FileOutputStream(localPath);
int read;
byte[] buffer = new byte[4096];
while ((read = in.read(buffer)) > 0) {
out.write(buffer, 0, read);
}
chmod call: (it works according to ls -l through adb)
static void changePermission(String localPath) {
try {
Process chmod = Runtime.getRuntime().exec("/system/bin/chmod 777 " +localPath);
chmod.waitFor();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
out.close();
in.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
Permissions of the file the program can't edit and then output a changed copy:
~/nativeApp/img $ ls -l
-rwxrwxrwx app_89 app_89 93061 2011-07-23 18:38 img1.jpg
Permission of the application that can't edit the above jpg:
~/nativeApp/bin $ ls -l jpegtransformer
-rwxrwxrwx app_89 app_89 95268 2011-07-23 18:01 jpegtransformer
Permissions of folders in ~/nativeApp/
~/nativeApp $ ls -l
drwxrwxrwx app_89 app_89 2011-07-23 17:57 bin
drwxrwxrwx app_89 app_89 2011-07-23 18:27 img
Theories:
At this point my only viable theory is that there is some android policy not governed by chmod which is keeping the jpegtransformer from editing the image when called by the java layer. Since the image analyzer doesn't change the image I imagine it skirts this? Are native processes not allowed to create files? Any ideas would be great. Sorry for the long read.
-SS
When you spawn a process from your app, it runs under the same uid as you do, so all of the same Android and filesystem permissions apply. I think you need to look for something else going on, such as using bad paths.
If you want to verify, just use "adb shell ps" to see the running processes and you should see that your process has the same uid as your main app.
That said... Android really does not support spawning processes like this, and it is strongly discouraged. Please consider doing this just by loading the native code as a shared library and using JNI to call it. This will also be a lot more efficient, and communication with your native code potentially simpler since JNI is a much richer and more direct way to call in to it.
I think your problem is not related to permissions - you try to redirect the output using >, while this is a shell operator and does not work from java. grab the process output stream and write it to a file using Java standard file I/O API.
Though I'm not sure this is the problem, you shouldn't have problem to modify files in your app folder and the issue I described is an issue I met more than once.

How do I get the logfile from an Android device?

I would like to pull the log file from a device to my PC. How can I do that?
Logcollector is a good option but you need to install it first.
When I want to get the logfile to send by mail, I usually do the following:
connect the device to the pc.
Check that I already setup my os for that particular device.
Open a terminal
Run adb shell logcat > log.txt
I hope this code will help someone. It took me 2 days to figure out how to log from device, and then filter it:
public File extractLogToFileAndWeb(){
//set a file
Date datum = new Date();
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd", Locale.ITALY);
String fullName = df.format(datum)+"appLog.log";
File file = new File (Environment.getExternalStorageDirectory(), fullName);
//clears a file
if(file.exists()){
file.delete();
}
//write log to file
int pid = android.os.Process.myPid();
try {
String command = String.format("logcat -d -v threadtime *:*");
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder result = new StringBuilder();
String currentLine = null;
while ((currentLine = reader.readLine()) != null) {
if (currentLine != null && currentLine.contains(String.valueOf(pid))) {
result.append(currentLine);
result.append("\n");
}
}
FileWriter out = new FileWriter(file);
out.write(result.toString());
out.close();
//Runtime.getRuntime().exec("logcat -d -v time -f "+file.getAbsolutePath());
} catch (IOException e) {
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
//clear the log
try {
Runtime.getRuntime().exec("logcat -c");
} catch (IOException e) {
Toast.makeText(getApplicationContext(), e.toString(), Toast.LENGTH_SHORT).show();
}
return file;
}
as pointed by #mehdok
add the permission to the manifest for reading logs
<uses-permission android:name="android.permission.READ_LOGS" />
I would use something of this sort :
$adb logcat -d > logcat.txt
The -d option dumps the entire circular buffer into the text file and if you are looking for a particular action/intent try
$adb logcat -d | grep 'com.whatever.you.are.looking.for' -B 100 -A 100 > shorterlog.txt
Hope this helps :)
For those not interested in USB debugging or using adb there is an easier solution. In Android 6 (Not sure about prior version) there is an option under developer tools: Take Bug Report
Clicking this option will prepare a bug report and prompt you to save it to drive or have it sent in email.
I found this to be the easiest way to get logs. I don't like to turn on USB debugging.
EDIT:
The internal log is a circular buffer in memory. There are actually a few such circular buffers for each of: radio, events, main. The default is main.
To obtain a copy of a buffer, one technique involves executing a command on the device and obtaining the output as a string variable.
SendLog is an open source App which does just this: http://www.l6n.org/android/sendlog.shtml
The key is to run logcat on the device in the embedded OS. It's not as hard as it sounds, just check out the open source app in the link.
Often I get the error "logcat read: Invalid argument". I had to clear the log, before reading from the log.
I do like this:
prompt> cd ~/Desktop
prompt> adb logcat -c
prompt> adb logcat | tee log.txt
I know it's an old question, but I believe still valid even in 2018.
There is an option to Take a bug report hidden in Developer options in every android device.
NOTE: This would dump whole system log
How to enable developer options? see: https://developer.android.com/studio/debug/dev-options
What works for me:
Restart your device (in order to create minimum garbage logs for developer to analyze)
Reproduce your bug
Go to Settings -> Developer options -> Take a bug report
Wait for Android system to collect the logs (watch the progressbar in notification)
Once it completes, tap the notification to share it (you can use gmail or whetever else)
how to read this?
open bugreport-1960-01-01-hh-mm-ss.txt
you probably want to look for something like this:
------ SYSTEM LOG (logcat -v threadtime -v printable -d *:v) ------
--------- beginning of crash
06-13 14:37:36.542 19294 19294 E AndroidRuntime: FATAL EXCEPTION: main
or:
------ SYSTEM LOG (logcat -v threadtime -v printable -d *:v) ------
--------- beginning of main
A simple way is to make your own log collector methods or even just an existing log collector app from the market.
For my apps I made a report functionality which sends the logs to my email (or even to another place - once you get the log you can do whether you want with it).
Here is a simple example about how to get the log file from a device:
http://code.google.com/p/android-log-collector/
Simple just run the following command to get the output to your terminal:
adb shell logcat
Two steps:
Generate the log
Load Gmail to send the log
.
Generate the log
File generateLog() {
File logFolder = new File(Environment.getExternalStorageDirectory(), "MyFolder");
if (!logFolder.exists()) {
logFolder.mkdir();
}
String filename = "myapp_log_" + new Date().getTime() + ".log";
File logFile = new File(logFolder, filename);
try {
String[] cmd = new String[] { "logcat", "-f", logFile.getAbsolutePath(), "-v", "time", "ActivityManager:W", "myapp:D" };
Runtime.getRuntime().exec(cmd);
Toaster.shortDebug("Log generated to: " + filename);
return logFile;
}
catch (IOException ioEx) {
ioEx.printStackTrace();
}
return null;
}
Load Gmail to send the log
File logFile = generateLog();
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(logFile));
intent.setType("multipart/");
startActivity(intent);
References for #1
https://stackoverflow.com/a/34883741/2162226
https://stackoverflow.com/a/3359857/2162226
~~
For #2 - there are many different answers out there for how to load the log file to view and send. Finally, the solution here actually worked to both:
load Gmail as an option
attaches the file successfully
Big thanks to https://stackoverflow.com/a/22367055/2162226 for the correctly working answer
Thanks to user1354692 I could made it more easy, with only one line! the one he has commented:
try {
File file = new File(Environment.getExternalStorageDirectory(), String.valueOf(System.currentTimeMillis()));
Runtime.getRuntime().exec("logcat -d -v time -f " + file.getAbsolutePath());}catch (IOException e){}
I have created a small library (.aar) to retrieve the logs by email. You can use it with Gmail accounts. It is pretty simple but works. You can get a copy from here
The site is in Spanish, but there is a PDF with an english version of the product description.
I hope it can help.
First make sure adb command is executable by setting PATH to android sdk platform-tools:
export PATH=/Users/espireinfolabs/Desktop/soft/android-sdk-mac_x86/platform-tools:$PATH
then run:
adb shell logcat > log.txt
OR first move to adb platform-tools:
cd /Users/user/Android/Tools/android-sdk-macosx/platform-tools
then run
./adb shell logcat > log.txt
I would use something like:
$ adb logcat --pid=$(adb shell pidof com.example.yourpackage)
which you can then redirect to a file
$ adb logcat --pid=$(adb shell pidof com.example.yourpackage) > log.txt
or if you also want to see it at stdout as well:
$ adb logcat --pid=$(adb shell pidof com.example.yourpackage) | tee log.txt

Categories

Resources