Some time ago I created an application with private Shared Preferences. Now I'm creating a related application that needs to check some of the previous application preferences. The problem I'm facing is that the previous application source code is in a computer I can't access until next month. Since I don't want to wait that long I thought that, since my device is rooted, I might be able to modify the preferences file permissions to be able to access it so I can publish both applications as soon as I get the previous application code back.
The preferences file is located in /data/data/my.package/shared_prefs. If I access it with adb shell and use chmod 777 the file permissions are modified and I can access the preferences, but eventually the permissions will go back to 660. I tried to change them from code using:
Runtime.getRuntime().exec("su");
Runtime.getRuntime().exec("chmod 777 /data/data/my.package/shared_prefs/my_preferences.xml");
The permissions aren't modified. Why is that?
Thanks!
My guess is each command run from exec() is executed in a separate native process. Therefore your su command doesn't affect the second call to exec().
Try this instead:
Runtime.getRuntime().exec("su; chmod 777 /data/data/my.package/shared_prefs/my_preferences.xml");
try {
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream suOutputStream = new DataOutputStream(suProcess.getOutputStream());
suOutputStream
.writeBytes("chmod 777 /data/data/my.package/shared_prefs/my_preferences.xml\n");
suOutputStream.flush();
suOutputStream.writeBytes("exit\n");
suOutputStream.flush();
suProcess.waitFor();
} catch (IOException e) {
// TODO Auto-generated catch block
} catch (InterruptedException e) {
// TODO Auto-generated catch block
}
Related
Having a problem writing out to a file, this code is taken directly from the android developer page and then tweaked a bit by me. Is there something i am missing? Quite new to Android development so sorry if it's something blatantly obvious.
send.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FileOutputStream outputStream;
String data = "hello";
File fileDir = new File("data.txt");
if (!fileDir.exists())
fileDir.mkdirs();
try {
outputStream = openFileOutput("data.txt",Context.MODE_PRIVATE);
outputStream.write(data.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
Basically, your problem is that you are trying to do it twice, once in a way that won't work, and once in a way that will, but hides the result.
File fileDir = new File("data.txt");
if (!fileDir.exists())
fileDir.mkdirs();
This would create a Java File object connected to a hypothetical file called "data.txt" located in the current working directory, which for an Android app is the root directory of the device - a place you most definitely are not allowed to write to. However, this may not obviously cause any errors, as the root directory exists so mkdirs() will do nothing, and you only create a File object, you don't actually try to create a file on "disk". Effectively this code does nothing for you - get rid of it.
Next you try something basically workable:
try {
outputStream = openFileOutput("data.txt",Context.MODE_PRIVATE);
outputStream.write(data.getBytes());
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
openFileOutput() is a method of a Context (Activity or Service) which creates an output stream to write to an actual file located in the private internal storage area of your app. This is all fine and good, and normally a good choice for storing typical data. However, it is not a place that you will be able to examine when running a release app on a secured device, as neither ADB based tools nor Mass Storage or MTP access over USB have rights to it. So it's entirely possible that this code worked, but you had no way to discover that fact. If you are on an emulator, you can access this location with ADB or the DDMS browser, and if your apk is a debug one, you can use the run-as command line tool in the shell.
If you want to share the data, you might consider putting it on the External Storage instead.
I want to get the Skype db file, which is called main.db and is not encrypted like WhatsApp etc. and copy that file to my custom folder.
What I am trying to do is the following: (my device is rooted and I am giving my app SuperUser access)
public void getSkypeDB() throws InterruptedException
{
Process sh;
try
{
sh = Runtime.getRuntime().exec("su", null, null);
File skypeDir= new File("/data/app", "/com.skype.raider");
Toast.makeText(getApplicationContext(), skypeDir.toString(), 0).show();
sh.waitFor();
}
catch (IOException e)
{
e.printStackTrace();
}
}
After doing this, my app crashed!
How can I get access to its database or access to the location of the database in the /data/app folder?
The database for an app won't be in /data/app/<app_package_name>, that's where the downloaded or pre-bundled APKs are located. The runtime data directory for an app is at /data/data/<app_package_name>. Also, be sure to include the stack trace from your exception catch or from the crash itself, otherwise it is a lot harder for people to help.
I need to access a file contained in the private folder of another app. I have granted my app the root privilege and changed the permissions - although I think it's not necessary - but when I try to read from the file, I get "permission denied".
This is the code:
File file = new File("/data/data/other.app/shared_prefs/file.xml");
if(file.exists()) {
try {
Runtime.getRuntime().exec("su");
Runtime.getRuntime().exec("chmod 777 " + file.getAbsolutePath());
InputStream in = new FileInputStream(file);
....
} catch (IOException e) {
e.printStackTrace();
}
}
Probably you wont be able to do this, because each app on android has a user with unique permissions.
See this: http://developer.android.com/guide/topics/security/permissions.html#userid
Any data stored by an application will be assigned that application's user ID, and not normally accessible to other packages. When creating a new file with getSharedPreferences(String, int), openFileOutput(String, int), or openOrCreateDatabase(String, int, SQLiteDatabase.CursorFactory), you can use the MODE_WORLD_READABLE and/or MODE_WORLD_WRITEABLE flags to allow any other package to read/write the file. When setting these flags, the file is still owned by your application, but its global read and/or write permissions have been set appropriately so any other application can see it.
You cannot break up the su and the chmod operations like that.
This code:
Runtime.getRuntime().exec("su");
Runtime.getRuntime().exec("chmod 777 " + file.getAbsolutePath());
Does not result in the chmod being executed in a root shell. Each call to exec kicks off a NEW process.
You need to run the commands you need all within a single process. The easiest way to do that is to write a shell script to your /data/data directory that does these operations for you and then run that through the sh shell processor.
Please note that good security practice would be to chmod the file back to not world readable after you are done with it in your app so that you are not leaving the other app exposed forever.
This answer looks to have what you need: Run binary from with root Android Application
SOLVED
Solved using this code to run the commands:
public static void runAsRoot(String[] cmds){
try {
Process p = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(p.getOutputStream());
for (String tmpCmd : cmds) {
os.writeBytes(tmpCmd+"\n");
}
os.writeBytes("exit\nexit\n");
os.flush();
p.waitFor();
} catch(IOException e) {
e.printStackTrace();
} catch(InterruptedException e) {
e.printStackTrace();
}
}
I'm trying to develop an android application that could erase default browser's search history without rooting, but I'm stuck. Here is my source code
File file = new File("data/data/com.android.browser/databases/browser.db");
try {
String content = "";
if(!file.exists()) {
file.createNewFile();
}
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(content);
bw.close();
Toast.makeText(MainActivity.this, "History Deleted From Default Browser", Toast.LENGTH_LONG).show();
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
}
As i know browser's history will be stored in "browser.db" file, i can able to clear history only if I change the permission of browser.db file in command prompt through adb shell like "chmod 777 data/data/com.android.browser/databases/browser.db"
But i need to do it every time, i want to do this inside my application source code, I also tried Runtime.exec() methods to execute adb shell, actually History Eraser app can erase the history of default browser without root permission, Can any one please help me out in solving this mystery. Thanks in Advance.
Add the following permissions to AndroidManifest.xml:
<uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"/>
<uses-permission android:name="com.android.browser.permission.READ_HISTORY_BOOKMARKS"/>
Then when you want to clear the history use:
Browser.clearHistory(getContentResolver());
How can I, within my application, edit a file in the /system/ directory?
Do I have to make the system R/W accessible?
I ve tried:
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes("mount -o remount,rw /system\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
and many other ways, without success.
If anybody can help me, I'd greatly appreciated it! :)
Also, if i finally made it, will it worked with all rooted phones? Or is it different with some phones?
I use:
os.writeBytes("mount -o remount rw /system/\n");
//instead of a comma, I have a space.
//When I tried it with a comma, mine didn't work either.
And that allows me to successfully mount.
If you exit right after that, of course it will not work. You have to stay within the same process and use the linux commands to edit the file.
I have no idea how to edit the files, but I suggest googling how to do things in linux terminal, and then putting the proper code in os.writeBytes("CODE_HERE");
Though, as far as the mounting process is concerned, I don't know if that command will work universally. It may just fortunately work on my device.
EDIT:
I now use RootTools: http://code.google.com/p/roottools/downloads/list
And here is the Wiki page:
http://code.google.com/p/roottools/w/list
But I now am using:
RootTools.remount(file, mountType);
//For example:
RootTools.remount("/system/", "rw");
I believe that is universal
Edit: All version of codes below DOES NOT mount system as RW.
*Read comments below to see why.
Solution of this is not a simple command.
Edit1: I went on Super User apk, Settings tab, and "tapped" at the last item, to update the su binary. With that update, everything below isnt working.
Edit2: started a whole conversation with my self here. Fix for the current latest binary is at the bottom of the post
==================================================================================
Found out how to do it! Second day of efforts, and finally found it!!!!!
Tried several things, and answer was to a simple change mode,
what i have done:
First Version Code:(doesnt work)
String[] mountRW = { "su", "-c",
"chmod 777 /system/etc/build.prop"};
String[] mountRO = {"su", "-c",
"chmod 755 /system/etc/build.prop"};
//TODO REMOVE testing purposes
File file2 = new File("/system/build.prop");
//Make file Read-Write
process = Runtime.getRuntime().exec(mountRW);
process.waitFor();
//TODO REMOVE testing purposes
Log.d("MOUNT RW?", "RW WRITABLE? "+ file2.canWrite());
///////////////////////
// process the file
//////////////////////
// After editing finish,
//make Read Only file again
process = Runtime.getRuntime().exec(mountRO);
process.waitFor();
//TODO REMOVE
Log.d("MOUNT RO?", "RO WRITABLE? "+ file2.canWrite());
I didnt paste some try catch cases.
Also i got another problem.. And i solved it in Version 2. THe little problem was, that, i was asking for a specific for a su command, and the user, had to accept SU cmd for RO, SU cmd for RW.. and another time for other stuff in my program.
In 2nd version i m using the generic su command, so user has to accept SU privileges only ONE time, and i m using output stream.
Code Version 2(Recomended) (doesnt work):
String mountRW = "chmod 777 /system/build.prop";
String mountRO = "chmod 755 /system/build.prop";
//TODO REMOVE
File file2 = new File("/system/build.prop");
//Make file Read-Write
process = Runtime.getRuntime().exec("su"); //Generic SU Command
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(mountRW + " \n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
//TODO REMOVE
Log.d("MOUNT RW?", " RW WRITABLE? "+ file2.canWrite());
////////////////////////////
/// mod the file
///////////////////////////
// After editing finish, make Read Only file again
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(mountRO + " \n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
//TODO REMOVE
Log.d("MOUNT RO?", "RO WRITABLE? "+ file2.canWrite());
Both codes require Root on your device.
Both versions doesnt include catch cases. (Eclpise will found them for you)
Check out your logcat(adb logcat), to see that indeed it works!
With latest su binary, this code changes slightly. The change mode command requires 4 digits. 0777 for rw permissions, and 0755 for ro permissions!
This code by its own, it does nothing to your device.
Only it mounts built.prop RW, and then mounts it back to RO.
Although if you change it, you may brick your device! Take care!