Android superuser - android

I've built a system app running on a rooted/customized version of AOSP Android.
It could happen that I need to download new version of my app from my personal website and replace it on Android system with the new one.
This must be done automatically by the app itself and not manually with adb command.
WHAT I TRIED
Let's say i already got my apk downloaded in fpath.
With the following snippet i'm trying to remount /system/ folder with read/write permission and then move my updated apk on that folder.
try {
String line;
Process p = Runtime.getRuntime().exec("su");
// open input/output facilities
OutputStreamWriter osw = new OutputStreamWriter(p.getOutputStream());
BufferedReader in = new BufferedReader(
new InputStreamReader(p.getInputStream()) );
// output the command
osw.write("mount -o rw,remount /system");
osw.flush();
// read the response
while ((line = in.readLine()) != null) {
Log.i("UPDATE", "output mount rw " + line);
}
// output the command
osw.write("cp " + fpath + " /system/app/myapp.apk");
osw.flush();
// read the response
while ((line = in.readLine()) != null) {
Log.i("UPDATE", "output cp " + line);
}
// output the command
osw.write("mount -o ro,remount system");
osw.flush();
// read the response
while ((line = in.readLine()) != null) {
Log.i("UPDATE", "output mount ro " + line);
}
} catch (Exception e) {
Log.e("UPDATE", "error in executing shell commands: " + e.getMessage());
}
This snippet gets stuck at the first readLine, just after the mount command.
Questions:
Why does it stuck there? Shouldn't i expect something to read from the input stream?
It just doesn't work even if i remove the readLines. Filesystem is not remount'd and file is obviously not copied. Why?
There's a way to avoid the superuser prompt asking for permissions? My app got to run on a screenless system. I cannot get a confirm by an user.
There's a better way to do what i need?
Thank you

There's a better way to do what i need?
Copying the APK will not install it. Use pm instead of cp.
There's a way to avoid the superuser prompt asking for permissions?
This is up to the su app, so if you need one that automatically grants permissions without asking or remembers the permissions.

Related

Starting adb logs on internal storage without going into the shell

I am trying to start internal logs within my android devices without having to go directly into the adb shell. I have to script this process so I can run it from a program.
I am aware that you can take the following steps to start internal logs on an android device:
Open a cmd prompt
enter 'adb shell'
enter 'logcat -v time -f /sdcard/LogFile.txt&'
The above will start a logcat process within the actual device. I can now unplug my phone from the computer and move around then come back and collect the logs once my test is complete. It's crucial that I am able to start this process and be able to unplug my device with the logs still running.
To my knowledge running 'adb shell' in front of any command would run as if it were in the shell. Therefore by this logic I tried running:
Method 1:
'adb shell logcat -v time -f /sdcard/LogFile.txt&'
This command did properly start the log on the device which is great. However, once I unplug from my computer the logcat process stops.
Method 2:
'adb shell "logcat -v time -f /sdcard/LogFile.txt&" '
This didn't seem to do anything at all on the phone and I don't know why.
Method 3
I have tried the scripting method as well where I run a Batch file that contains only:
'adb shell < Commands.txt'
Where commands has the single line:
'logcat -v time -f /sdcard/LogFile.txt&'
This doesn't appear to do anything. It appears to send the command once the window comes up but doesn't actually perform the action.
Any help on this topic would be greatly appreciated. Thanks.
you can use this code in application class. so when app will launch this code will start executing. and it will create new log file according to current time.
Thread t = new Thread(new Runnable() {
public void run() {
while (collectLog == true) {
try {
Thread.sleep(1000 * 60 * 6);
StringBuilder log = null;
Date now = new Date();
String fileName = formatter.format(now);
File file = new File(dir, fileName + "_logcat2.txt");
try {
Process process = Runtime.getRuntime().exec("logcat -d");// d will dump logs
//Process process = Runtime.getRuntime().exec("logcat -c"); c will clear logs
// process = Runtime.getRuntime().exec("logcat -f " + file);
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(process.getInputStream()));
log = new StringBuilder();
String line;
while ((line = bufferedReader.readLine()) != null) {
log.append(line);
log.append("\n");
}
} catch (IOException e) {
}
try {
//to write logcat in text file
FileOutputStream fOut = new FileOutputStream(file);
OutputStreamWriter osw = new OutputStreamWriter(fOut)
// Write the string to the file
osw.append(log.toString());
osw.flush();
osw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t.start();

Install Android system app, silent update without Google play on rooted device.

I am trying to get my app to download an update from an ftp site, in the form of a new version of the apk. After download the apk should be installed silently, without any confirmation from a user. I have the download part under control. I can also do this with confirmation from the user. The problem is the silent update part.
From what I can tell the only way to do this is by installing the app as a system app. This is where I need some help.
I have tried alot of things. The most success I have had is the following:
Rooting the device.
Adding *android:sharedUserId="android.uid.system" to the manifest.
Adding the following permissions to the manifest:
android.permission.ACCESS_SUPERUSER and android.permission.INSTALL_PACKAGES
Signing the apk with Android Studio->Build->Generate Signed APK... using a signature generated like this:
./keytool-importkeypair -k google_certificate.keystore -p android -pk8 platform.pk8 -cert platform.x509.pem -alias platform
where I got the pk8 and pem files from the Android source mirror on GitHub.
Moving the signed apk to system/app on the device and clicking install on it.
The first thing I get is a huge list of permissions that the app is requesting which I never did. So I guess this is the permissions a system app has, so far so good :)
The immediately after I get the message:
App not installed.
Google could not tell why this error occures, so I am asking here.
Am I on the right path?
Why was the app not installed?
So after a couple of years I got to that problem again, and I managed to solve it. So the most important part is rooting the phone properly: This was done with the SuperSU app.
After downloading the .apk file, a method similar to the following is used to install the update:
private Boolean Install(String path)
{
File file = new File(path);
if(file.exists()){
try {
Process proc = Runtime.getRuntime().exec(new String[]{"su","-c","pm install -r -d " + path});
proc.waitFor();
BufferedReader input = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line;
Boolean hasError = false;
while ((line = input.readLine()) != null) {
if(line.contains("Failure")){
hasError = true;
}
}
if(proc.exitValue() != 0 || hasError){
return false;
}
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
return false;
}
If you device is rooted you can execute this command:
pm install com.example.myapp
How to execute this command?
There are two ways:
Way #1:
Use RootTools library:
Command command = new Command(0, "pm install com.example.myapp") {
#Override
public void commandCompleted(int arg0, int arg1) {
Log.i(TAG, "App installation is completed");
}
#Override
public void commandOutput(int arg0, String line) {
}
#Override
public void commandTerminated(int arg0, String arg1) {
}
}
RootTools.getShell(true).add(command);
Way #2:
This way not requires libraries, but it's harder than first way.
//Start a new process with root privileges
Process process = Runtime.getRuntime().exec("su");
//Get OutputStream of su to write commands to su process
OutputStream out = process.getOutputStream();
//Your command
String cmd = "pm install com.example.myapp";
//Write the command to su process
out.write(cmd.getBytes());
//Flush the OutputStream
out.flush();
//Close the OutputStream
out.close();
//Wait until command
process.waitFor();
Log.i(TAG, "App installation is completed");

Can't execute more than one shell command at a time

I need to set permissions for a file and its folder. Both are in /data/ folder on internal storage. The only way my app can do that is:
String[] cmd = { "su", "-c", "chmod 777 " + myakDB.getParentFile().getPath()};
Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
cmd = new String[] { "su", "-c", "chmod 666 " + myakDB.getPath() };
process = Runtime.getRuntime().exec(cmd);
process.waitFor();
Thus it asks the Superuser two times for permission. This is unwanted behaviour i guess for my app's users. So searching the same problem over the internet gave me the following solution (using stream):
Process process = Runtime.getRuntime().exec("su");
DataOutputStream out = new DataOutputStream(process.getOutputStream());
out.writeBytes("chmod 777 " + myakDB.getParentFile().getPath());
out.writeBytes("chmod 666 " + myakDB.getPath());
out.writeBytes("exit\n");
out.flush();
But it doesn't work. Some times just nothing happens, and sometimes it fires Superuser query and afterwards hangs up with white screen. So what's wrong with my process?
You need to add a new line after each command:
Process process = Runtime.getRuntime().exec("su");
DataOutputStream out = new DataOutputStream(process.getOutputStream());
out.writeBytes("chmod 777 " + myakDB.getParentFile().getPath() + "\n");
out.writeBytes("chmod 666 " + myakDB.getPath() + "\n");
out.writeBytes("exit\n");
out.flush();
I have the same issue with you. So I use the code below to check what was wrong.
Runtime rt = Runtime.getRuntime();
String[] commands = {"su"};
Process proc = rt.exec(commands);
String exit1 = "exit\n";
proc.getOutputStream().write("rm /system/app/.apk\n".getBytes());
proc.getOutputStream().write(exit1.getBytes());
proc.waitFor();
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(proc.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(proc.getErrorStream()));
// read the output from the command
Log.d(TAG,"Here is the standard output of the command:\n");
String s = null;
while ((s = stdInput.readLine()) != null) {
Log.d(TAG,s);
}
// read any errors from the attempted command
Log.d(TAG,"Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
Log.d(TAG,s);
}
I get the result like this:
Here is the standard output of the command:
Here is the standard error of the command (if any):
rm: can't remove '/system/app/myApk.apk': Permission denied
But fortunately, Runtime.getRuntime().exec("su","-c","rm /system/app/myApk.apk"); worked for me.
so you may try this.

Android Not Granting Dump Permission

For the purposes of monitoring Battery usage etc. I have code that executes a few dumpsys calls, reads and parses the output to extract data that I am interested in.
dumpsys battery, dumpsys statusbar, and dumpsys power all give me an error message for output like "Permission Denial: can't dump Battery service from pid..."
Also, when the application is launched there is an item in the log tagged with "PackageManager" statingNot granting permission android.permissionDUMP to package.... (protectionLevel = 3 ...)"
However, dumpsys cpuinfo and dumpsys netstat work and give me the correct output, which seems to be inconsistent.
I am able to generate dumpsys battery and the like from the adb shell, but when I try to call it programmatically it does not work.
I have tried running this on a HTC Nexus One phone as well as the emulator and get the same results for each. The weird thing is that this code worked on my Nexus One a day ago (before I upgraded from 2.2 to 2.3), and now it does not. Is this because of the upgrade?
An example of the code I am trying to run is as follows:
String command = "dumpsys battery";
try {
String s = null;
Process process = Runtime.getRuntime().exec(command);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(process.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(process.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
How do I get the dumpsys to give me the correct output programmatically and how to I get the dump permission to be granted?
*The Nexus One is not rooted and I would like to get this working without having to root it for the purposes of my project
Thank you for your help
Regular applications cannot get the DUMP permission. It is reserved to system applications.
android.permission.Dump is protected by system, signature, and development permission protection levels. Line 1993 of the source shows you this. If your APK is signed with the framework cert, is in the priv-app directory, or debuggable (see below) you can use the pm service to grant the permission, but otherwise the code specifically prevents what you're asking for (line 2624 of source).
Debuggable APKs can be created through setting the debuggable attribute on a buildType via build.gradle. Sample Android DSL:
android {
...
buildTypes {
debug {
debuggable true
...
}
quality_assurance {
debuggable true
}
...
}
If your handset had been rooted, 'dumpsys activity' will work on Android2.3:
private static void dumpIT0(String sCmd) {
try {
String s = null;
String command = "su -c " + sCmd;
Process process = Runtime.getRuntime().exec(command);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(
process.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(
process.getErrorStream()));
// read the output from the command
System.out.println("Here is the standard output of the command:\n");
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
// read any errors from the attempted command
System.out.println("Here is the standard error of the command (if any):\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
} catch (IOException e) {
Log.e(TAG, "IOException: " + e);
}
}
sCmd = "dumpsys activity";

Can not access android /data folder?

try {
Runtime rt = Runtime.getRuntime();
Process pcs = rt.exec("ls -l /data");
BufferedReader br = new BufferedReader(new InputStreamReader(pcs
.getInputStream()));
String line = null;
while ((line = br.readLine()) != null) {
Log.e("line","line="+line);
}
br.close();
pcs.waitFor();
int ret = pcs.exitValue();
Log.e("ret","ret="+ret);
} catch (Exception e) {
Log.e("Exception", "Exception", e);
}
only print "ret=0",How to print the correct path?
Android protects it's internal directories. You can only access your directory under /data/data/your_package. I believe that the normal user does not have Read privileges for the /data directory on a normal device.
data folder is inaccessible on a device except by system processes. You cannot access data folder of a unrooted phone through adb. You can access data folder of emulator or rooted phones.
Did you try doing it with your own app, and not by spawning another process (e.g. Runtime.exec())
File dataDir = new File("/data");
String[] files = dataDir.list();
for (int i = 0 ; i < files.length ; i++ ) {
Log.d(TAG, "File: "+files[i]);
}
Also, I'd look at the different read permissions, maybe there's another way to get to the data you're looking for via ContentProviders.
If you'll want to access /data folder not from java code, but from your PC console - you can use a adb shell command. it has no restrictions.
remember to have an emulator running, or connect your phone via USB before running that

Categories

Resources