Execute linux command and store output in a file android - android

I would like to execute 'top -n 1' command using android and store the output of top command in a file in the internal storage in my device, if possible. Otherwise the file should be stored in sd card. I used the following code to achieve it.
File logFile = new File(getFilesDir().getAbsolutePath()+File.separator+"logtex.txt");
if(!logFile.exists())
{
logFile.createNewFile();
}
logFile.setExecutable(true,false);
logFile.setReadable(true,false);
logFile.setWritable(true,false);
Log.e("executeToplog", "err in");
Runtime.getRuntime().exec("top -n 1 > /data/user/0/com.example.abcdef.memcpuusage/files/logtex.txt ");
But it doesn't seem to work. What changes should be made to the code?

I don't like the idea to fill a file with the output. I would try to following
Process process = Runtime.getRuntime ().exec ("top -1 1");
Reader reader = new InputStreamReader (process.getInputStream ());
// simple approach, omit some checkings, not compiled or tested, so may still fail
FileWriter writer = new FileWriter ("top.log");
for (int chr; (chr = reader.read ()) != –1;) {
writer.append((char) chr);
}
writer.close()
However, it may be that android doesn't support "top", may be you need to apply the full path (on my ubuntu /usr/bin/top)
When you need the output into a file, put the content of reader into that file. ">" is a feature of the shell, not of exec

Related

Config file on Android

New to Android, working on an app for Vuzix M300s. The app needs to access a file that contains the IP address and port of a web server.
I believe I will need to manually place a pre-configured file on the M300s using adb shell, but I cannot figure out where on the device to place it so that the app can find it.
Via Android Studio 3.1.3, I have placed a file in the assets folder which I can open & read, but using adb shell I cannot locate it. (I get permission denied for a lot of actions like ls).
How do I get a file on there? Or is there a better way?
Note that the assets folder in your project only exists on your development machine. The contents of this folder are packaged into the APK file when you build your app. In order to read any of these files, you need to use Context.getAssets() as explained in read file from assets.
Figured it out.
To move/copy a file to the M300s for an application
move the file to the device (in the sdcard folder)
.\adb push C:\temp\file.cfg /sdcard/
move the file from /sdcard/ to the desired location
a) go into the shell
'> .\adb shell
b) change to the application's permissions
$ run-as com.foobar.appname
c) copy the file into the app's 'files' folder
$ cp /sdcard/file.cfg files/
Within my app, I was able to read this with
FileInputStream fin = openFileInput("file.cfg");
InputStreamReader rdr = new InputStreamReader(fin);
char[] inputBuffer = new char[100];
int charsRead = rdr.read(inputBuffer);
String fileContents = new String(inputBuffer);
rdr.close();
Log.i(method, "charsRead: " + charsRead);
Log.i(method, "fileContents: " + fileContents);

Why can't I successfully write to my external SD card in Android?

I am trying to write a log file of my app to my external SD card. To figure out how to do this, I have been trying to follow the example HERE.
There is a section about 3/4 of the way down that page that says:
If none of the pre-defined sub-directory names suit your files, you can instead call getExternalFilesDir() and pass null. This returns the root directory for your app's private directory on the external storage.
My device does not have any of those pre-defined directories, and I would rather just as well save my data to the external SD card. Using the following command:
$ ADB shell
shell#android:/ $ cd /mnt
shell#android:/ $ ls -F
d ext_sdcard
You can see my external SD card. So, I created a directory on the external SD card:
shell#android:/ $ cd ext_sdcard
shell#android:/ $ mkdir MyAwesomeApplication
shell#android:/ $ ls -F
d MyAwesomeApplication
Now is when I [sort of] use the code from the Android developers site:
public File getDocumentStorageDir(String filename){
File file = new File("/mnt/ext_sdcard/MyAwesomeApplication", filename);
if(!file.getParentFile().mkdirs()){
Log.i(MainActivity.class.getName(), "Directory Not Created!");
}
return file;
}
When I run my application, it sort of works; I immediately get this error:
E/myPackage.MainActivity: Directory Not Created!
But then it creates the log file anyway, and successfully writes the data to the file.
My issue is that it is always overwriting the log file with new data, it doesn't append, even though I am using:
public boolean isExternalStorageWritable() {
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
return true;
}
return false;
}
if(isExternalStorageWritable()){
File logfile = getDocumenetStorageDir("mylogfile.log");
PrintWriter logFileWriter = null;
try {
logFileWriter = new PrintWriter(logfile);
logFileWriter.append("stuff ...");
} catch(FileNotFoundException fnfe){
Log.i(MainActivity.class.getName(), fnfe.getMessage());
} finally {
logFileWriter.close();
}
}
Now, when I use this command:
shell#android:/ $ cd MyAwesomeApplication
shell#android:/ $ ls -F
- mylogfile.log
I see my log file where it should be. But when I use this command:
shell#android:/ $ cat mylogfile.log
// only the very latest piece of data is here
What I am I doing incorrectly here?
Thanks
there're two parts on your question and I'll try to address them separately.
Location of files
You should never hardcode file locations like you're doing (even if it's just debug logging). The location File file = new File("/mnt/ext_sdcard/MyAwesomeApplication", filename); might work for this device, but this vary on version of Android and manufacturer. You must use the appropriate getter method available to get the correct directory. On THIS LINK you can find the complete explanation, but from what I understood of your use case you want to use the following code:
public static File getLogFile(Context context) {
File folder = getExternalFilesDir("logs");
if(!folder.exists()) {
folder.mkdirs();
}
return new File(folder, "mylogfile.log");
}
Append to an existing file.
You didn't show how you're creating the PrintWriter, but I've always used the FileWriter class without any issues on appending.
Here in this question you can see about that (How to append to a text file in android?). And here some code
FileWriter f;
try {
f = new FileWriter(getLogFile(context), true); // true is for append
f.write(" ..logs...");
f.flush();
} catch(Exception e) {
.. handle exceptions
} finally {
if(f != null) {
f.close();
} catch(Exception ee){
... exceptions might happen here too
}
}

How to execute linux command in android programmatically?

As in android(through android sdk/tools folder) from command line we can execute linux shell command to access mnt folder/data folder likewise. (e.g cd data ls) now that command i want to execute from programmatically in android so how could it be possible?
I am using following code to execute shell command
Process p = Runtime.getRuntime().exec("cd data");
but it is giving me exception
java.io.IOException: Error running exec(). Command: [cd, data] Working
Directory: null Environment: null
so how should i proceed for it.Thanks in advance.
cd is not a Linux command, it's a command built into the shell; it changes the current working directory in the context of that shell process. In your case, if the command were to be successful, it would be successful for the child process only (which would soon terminate) and would have no effect on your own process.
On Android, your process does not have permissions to read files in other app's /data/data/_other-package-name_, or list its private files in directory /data/data/_other-package-name_/files. But it does have permission to list and read files in the lib directory /data/data/_other-package-name_/lib, and you can look at a specific file in /data/data/_other-package-name_/files, if the other-package opened this file as public.
I.e. if the other-package does something in line with:
FileOutputStream fos = openFileOutput("public_file", Context.MODE_WORLD_READABLE);
fos.write("hello world".getBytes());
fos.close();
then your package can read this file like this:
byte[] bytes = new byte[100];
FileInputStream fis = new FileInputStream(new File("/data/data/*other-package*/files/public_file"));
int cnt = fis.read(bytes);
fis.close();
Log.d("Two_Libs", new String(bytes, 0, cnt));
But you cannot list the public files in that directory to discover them.
try this :
Process p = Runtime.getRuntime().exec("cd /data");
To retrieve the path to your app's private data folder use the following from Java:
File MyData = Ctxt.getDir("Foo");
Where Ctxt is a Context object, like an Activity. It will return you a path like /data/data/com.activity.networkRequestDetector/app_Foo. Note that reading/writing /data/data/com.activity.networkRequestDetector/ is discouraged in Android - it's your application's sandbox's root, not to be played with.
To open files from the data folder, use something like this:
FileInputStream Stm = new FileInputStream(new File(MyData, "Filename.txt"));
In general, anything a shell command does your app can do, too. Shell commands are just programs that use API like everyone else.
Use as following:-
Process process = Runtime.getRuntime().exec("command to be executed");
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()));

How can I run Linux commands on an Android device?

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

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