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();
}
}
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'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());
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
}
I'm writing a file explorer which will be capable of modifying system files with root access, but I came across some problems.
What I'm doing now is to grant my app root access, but executing "su" doesn't work.
If I set permissions to the folder in adb shell, the app works fine but I think root browsing doesn't rely on chmods.
Can anyone tell me is there a proper way to make my app work as if it were with root privileges?
Running an android application process (its dalvik VM and native libraries) as root is extremely difficult to achieve, and inadvisable for a number of reasons including not just security but memory waste resulting from having to load private copies of system libraries instead of using the shared read-only copies available when you inherit an unprivileged process from zygote as in a normal application launch.
What the unofficial "su" hack on some rooted phones does is lets you launch a helper process which runs as root while your application process remains unprivileged. It does not change the userid of the application calling it - indeed, there really isn't by design any mechanism for doing that on unix-like operating systems.
Once you have a privileged helper process, you would then need to communicate with it via some means of interprocess communication such as its stdin/stdout or unix domain sockets to have it do file operations on your behalf. The shell present on the phone could probably even be used as the helper application - most of what a file manager needs to do can be implemented with the 'cat' command. Officially, none of this is a stable API, but then an application-accesable "su" hack isn't in official android anyway, so the whole project is deep in "unsupported" territory to begin with.
Root access creates a new Process, so, your app does not have root privileges.
The unique thing you can do with root privileges is execute commands, so, you have to know the commands of android, many of commands is based on Linux, like cp, ls and more.
Use this code for execute commands and get output:
/**
* Execute command and get entire output
* #return Command output
*/
private String executeCommand(String cmd) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec("su");
InputStream in = process.getInputStream();
OutputStream out = process.getOutputStream();
out.write(cmd.getBytes());
out.flush();
out.close();
byte[] buffer = new byte[1024];
int length = buffer.read(buffer);
String result = new String(buffer, 0, length);
process.waitFor();
return result;
}
/**
* Execute command and an array separates each line
* #return Command output separated by lines in a String array
*/
private String[] executeCmdByLines(String cmd) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec("su");
InputStream in = process.getInputStream();
OutputStream out = process.getOutputStream();
out.write(cmd.getBytes());
out.flush();
out.close();
byte[] buffer = new byte[1024];
int length = buffer.read(buffer);
String output = new String(buffer, 0, length);
String[] result = output.split("\n");
process.waitFor();
return result;
}
Usages for a file explorer:
Get list of files:
for (String value : executeCmdByLines("ls /data/data")) {
//Do your stuff here
}
Read text file:
String content = executeCommand("cat /data/someFile.txt");
//Do your stuff here with "content" string
Copy file (cp command not working on some devices):
executeCommand("cp /source/of/file /destination/file");
Delete file (rm command not working on some devices):
executeCommand("rm /path/to/file");