I have written an app where i can send commands to a device via GCM (Push Notification). One command is START_LOGGING. When the device receives this command it should start writing log statements to a file on the SDCard. I have another command where i upload the file to my server.
I can use these mechanisms to remotely get bugs from a device. It works fine when i test it on my HTC One X running Android 4.2.2. I have tested it on a HTC Desire C running Android 4.0.3 and it is not logging the statements to the SDCard. It creates the file and i can upload it but the file is empty.
Any Ideas why? Thanks in advance.
public static void logToSdcard(Context context){
String filename = context.getExternalFilesDir(null).getPath() + File.separator + "RR3.txt";
String command = "logcat -f "+ filename + " -v time *:V -v time";
Log.d(TAG, "command: " + command);
try{
Runtime.getRuntime().exec(command);
}
catch(IOException e){
e.printStackTrace();
}
}
Related
I have a problem running my application which plays mp3, on Android 2.3.
These mp3 are downloaded from a remote server to /data/data/com.my.package.name/, and the default file permissions are -rw-------.
Unlike on post HONEYCOMB devices (According to my tests), media player refuses to read mp3 if their file permissions are not -rw-rw-rw-.
I obviously verified that if I set files permissions to 666 with the adb shell, then the media player successfully read it.
So, after some researches on the net, I tried to implement the following code, just after writing the file:
String chmodString = "chmod 666 " + getActivity().getApplicationContext().getFilesDir().getParentFile().getPath() +"/" + fileName;
Process sh = Runtime.getRuntime().exec("su", null, new File("/system/bin/"));
OutputStream osChgPerms = sh.getOutputStream();
try {
osChgPerms.write((chmodString).getBytes("ASCII"));
osChgPerms.flush();
osChgPerms.close();
sh.waitFor();
} catch (InterruptedException e) {
Log.d("2ndGuide", "InterruptedException." + e);
} catch(IOException e) {
Log.d("2ndGuide", "IO Exception." + e);
}
This code is executed in a fragment but I don't think that changes anything.
Unfortunately, if this code works on post HONEYCOMB devices, where it's not useful,
osChgPerms.write((chmodString).getBytes("ASCII"));
Throws an IOException: broken pipe on Android 2.3, where I really need it.
In fact, I don't really know if the problem comes from the chmod or from the way to execute it.
Any solution to get it working or, to get the media player working on pre HONEYCOMB without changing file permissions?
Very good question, I ran in this problem a while back!
Using Java + Android(User must have chmod):
Folders:
Runtime.getRuntime().exec("chmod -R 777 " + FOLDERNAME);
Files:
Runtime.getRuntime().exec("chmod 777 " + FILENAME);
Problem: What if they do not have the "chmod" binary? You must download and include it in your application or assets.
Using Android NDK + JNI(User does not need chmod but needs compiled ndk libs):
/**
* Change file permissions. Eg. chmod 777 FILE.
* #param e Java environment.
* #param c Java class.
* #param file Path to file.
* #param mode Permissions for the file.
*/
static jint executeCommand(JNIEnv *e, jclass __attribute__((__unused__))c, jstring file, jstring mode) {
return (chmod(e->GetStringUTFChars(file, 0), strtol(e->GetStringUTFChars(mode, 0), 0, 8)));
}
Problem: Make sure to compile NDK with APP_ABI := all for all devices
For Java(7+) + Android API 9+(User does not need chmod or libs):
/**
* Change files to "0777"
* #param path Path to file
*/
public static void changeFilePermission(final String path) {
final File file = new File(path);
file.setReadable(true, false);
file.setExecutable(true, false);
file.setWritable(true, false);
}
Problem: Your minSDK must be 9!
Turning your problem around, you are really asking how can I give Media Player access to data my application provides?
You have chosen to pass it as a file, and thus want to know how to make that file publicly readable.
The alternative solution is to pass the data to the Media Player via a ContentProvider, so that it doesn't need direct access to your data. Look at FileProvider for how to wrap a file up in this way.
I give you an interesting and simple solution for changing permissions of a file in Android system. Just put code
Runtime.getRuntime().exec("chmod 777 <path to file>");
in a UiAutomator test case. And run that uiautomator test case at your target machine!
Reference: http://android-lihao.blogspot.com/2015/08/modify-permissions-of-files-in-android.html
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
Last night i had this code working at home and Whatzit was a good help. I got everything working(commented out the dbFile exists check and just copied any changes to the database that i wanted to make using the sqlite browser).
This morning i bring in my tablet to a windows 7 machine, uninstalled the application and tried to run the same code from eclipse. I keep getting an error:
03-12 11:51:39.320: E/AndroidRuntime(20365): Caused by:
java.io.IOException: trying to copy the database - ERROR:
/data/data/mypackage/databases/restaurant.db: open failed:
ENOTDIR (Not a directory)
i had zipped up my project on my mac and unzipped it to the same project directory in eclipse on the windows machine and in eclipse just performed a refresh.
Would like any input on what i might try? I tried uninstalling the app, copying the .apk back over and installing it again but nothing seems to work. thanks.
*I am actually running this on an actual device - Motorola Xoom 4.0.3
private void copyDataBase(File dbFile) throws IOException {
try{
InputStream dbStream = myDbContext.getAssets().open(dbName);
Log.e("In copyDataBase", "Environment Directory: " + Environment.getDataDirectory().canRead());
Log.e("In copyDataBase", "Environment Directory: " + Environment.getDataDirectory().canWrite());
Log.e("In copyDataBase", "Environment Directory: " + Environment.getExternalStorageDirectory());
Log.e("In copyDataBase", "opened up file " + dbName + " successfully. - trying " + path.toString());
OutputStream newDbFile = new FileOutputStream(DB_PATH + dbName);
byte[] buffer = new byte[1024];
int length;
while((length = dbStream.read(buffer)) > 0){
newDbFile.write(buffer);
}
newDbFile.flush();
newDbFile.close();
dbStream.close();
}
catch(IOException e){
throw new IOException("trying to copy the database - ERROR: " + e.getMessage());
}
}
the results of canWrite and canRead both come back as false. As sure as i am typing here this was working flawlessly. I dont know why hooking up the tablet to a windows machine running the same version as eclipse would make any difference.
The error you're getting is saying that the directory specified doesn't exist. You're clearly running this on a new virtual device correct? Is the version of android the same as what you initially developed on?
while programming android with eclipse, no matter if you're using the emulator or a device connected in debug mode you can easily check the Log for looking at the custom messages that you wrote.
e.g.: Log.i("foo: " + foo);
With the method:
Titanium.API.info("foo: " + foo);
if i'm using the emulator it all works fine, but if i'm deploying on the device is there a way of looking at the INFO?? with TiStudio or even TiDev
Thanks
You can use adb from the android SDK tools directory to see your Titanium Titanium.API.info calls:
tools/adb logcat | grep "TiAPI"
This will filter the adb log, giving you a cleaner view of only your log messages.
You can see logcat from the current device. Enable debug mode on the device, and connect it to the computer.
Then, if using eclipse, on the DDMS view on Devices select the device you want and the LogCat will show logs from it.
You can also see with this app the logs:
https://market.android.com/details?id=org.jtb.alogcat
Or save them to file:
try {
File filename = new File(Environment.getExternalStorageDirectory()
+ "/logfile.txt");
filename.createNewFile();
String[] cmd = new String[] { "logcat", "-v", "time", "-c", "-f",
filename.getAbsolutePath() };
Runtime.getRuntime().exec(cmd);
} catch (IOException e) {
Log.d("mCare", "Unable to log...", e);
e.printStackTrace();
}
You can read more here: How to redirect my log output from logcat to the SD-Card on an android device?
Have you tried Ti.API.log?
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