Run a service with Root privileges or adding permissions with root
Force, I must tell you that an Android Service do not require root access instead some actions(i.e. Access, Read, Write system resources) requires Root Permissions. Every Android Service provided in Android SDK can be run without ROOT ACCESS.
You can make the actions to execute with root permissions with the help of shell commands.
I have created an abstract class to help you with that
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import android.util.Log;
public abstract class RootAccess {
private static final String TAG = "RootAccess";
protected abstract ArrayList<String> runCommandsWithRootAccess();
//Check for Root Access
public static boolean hasRootAccess() {
boolean rootBoolean = false;
Process suProcess;
try {
suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
DataInputStream is = new DataInputStream(suProcess.getInputStream());
if (os != null && is != null) {
// Getting current user's UID to check for Root Access
os.writeBytes("id\n");
os.flush();
String outputSTR = is.readLine();
boolean exitSu = false;
if (outputSTR == null) {
rootBoolean = false;
exitSu = false;
Log.d(TAG, "Can't get Root Access or Root Access deneid by user");
} else if (outputSTR.contains("uid=0")) {
//If is contains uid=0, It means Root Access is granted
rootBoolean = true;
exitSu = true;
Log.d(TAG, "Root Access Granted");
} else {
rootBoolean = false;
exitSu = true;
Log.d(TAG, "Root Access Rejected: " + is.readLine());
}
if (exitSu) {
os.writeBytes("exit\n");
os.flush();
}
}
} catch (Exception e) {
rootBoolean = false;
Log.d(TAG, "Root access rejected [" + e.getClass().getName() + "] : " + e.getMessage());
}
return rootBoolean;
}
//Execute commands with ROOT Permission
public final boolean execute() {
boolean rootBoolean = false;
try {
ArrayList<String> commands = runCommandsWithRootAccess();
if ( commands != null && commands.size() > 0) {
Process suProcess = Runtime.getRuntime().exec("su");
DataOutputStream os = new DataOutputStream(suProcess.getOutputStream());
// Execute commands with ROOT Permission
for (String currentCommand : commands) {
os.writeBytes(currentCommand + "\n");
os.flush();
}
os.writeBytes("exit\n");
os.flush();
try {
int suProcessRetval = suProcess.waitFor();
if ( suProcessRetval != 255) {
// Root Access granted
rootBoolean = true;
} else {
// Root Access denied
rootBoolean = false;
}
} catch (Exception ex) {
Log.e(TAG, "Error executing Root Action", ex);
}
}
} catch (IOException ex) {
Log.w(TAG, "Can't get Root Access", ex);
} catch (SecurityException ex) {
Log.w(TAG, "Can't get Root Access", ex);
} catch (Exception ex) {
Log.w(TAG, "Error executing operation", ex);
}
return rootBoolean;
}
}
Extend your class with RootAccess or create an instance of RootAccess class and Override runCommandsWithRootAccess() method.
This is far from trivial but should work when the apps you want to monitor use sqlite databases or, more generically, write messages to a file when they arrive.
You will indeed need to have root access to the device as this violates the android security system:
Write a native process which runs as a daemon using the NDK and spawn it once after boot as root. You have now 3 major problems to solve:
How to find out if something changed?
This is the easy part. You would need to utilize the Linux inotify interface which should be accessible on every Android phone as the SDK has a FileObserver since API 1, so you are on the safe side here.
Another interesting approach may be to catch the C2DM messages. I have found a NDK class called BroadcastReceiver, so the NDK may be able to catch them. But I personally wouldn't do that as it feels wrong to steal intents. Also you would have to redistribute them or let them travel to real recipient, so I will not describe this in detail here. It may work, but it may be harder and should only be a fallback.
So, when you have solved this, the next problem arises:
How to read the changes in a safe way?
You have a problem, a big one, here. The file doesn't belong to the client, and the client doesn't even have the permission to know where it is (normally). So the monitored app is not aware of the client and will act like the file is exclusively owned only by itself. If they use some plain old textfile to write messages to you have to find out a way to read from it safely as it may be overwritten or extended at any time. But you may be lucky when they use sqlite, according to this it's totally valid to have more than one simultaneous reader, just only one writer. We are in the specs, everything fine again. When you have now read out the new data, more problems to solve:
How to get the new data back into the main app?
You should do only the bare minimum in this C/C++ program because it runs as root. You should also protect your app users from security breaches, so please write the program with this in mind. I have no real idea for this could work really good, but here are some thoughts:
- Write the collected data into your own sqlite database (easy in C/C++ and Java),
- Write the collected data into a plain file (not recommended at all, pain in the rear),
- Send an Intent which contains the new data (maybe not that easy in C/C++, but easy in Java)
- Use sockets/pipes/..., just every RPC mechanism you could imagine which is brought to you by Linux (same as the file, don't do it)
As stated in the text above, please be careful when you write this daemon as it is a potential security hazard. It may be hard to do this when you have no knowledge about C/C++ at all, even if you have written simple programs this should be a non trivial task.
On my search through the web I have found the NDK C++ classes I mentioned above. It can be found at Google code. I have neither experience with the NDK nor the C++ wrapper but it may be worth a look when you plan to write this.
running something as root is not the right way of solving this.
instead, consider an accessibility service that can watch for new notifications:
AccessibilityEvent