Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Running shell commands on Android using Runtime.getRuntime

I am working on a device admin app (has been signed by the manufacturer). I am using it to install other apps using the below adb shell command for android 9 :-

cat /sdcard/Download/myfolder/newapp.apk | pm install -S 1528293

and I am just passing it like this:-

String command = "cat /sdcard/Download/myfolder/newapp.apk | pm install -S 1528293"
Runtime.getRuntime().exec(command);

But I get the error "cat unknown option S ".

The same command works perfectly fine when I run it from adb shell. Don't know what I am doing wrong and could use some help.

EDIT 1:- I tried running the command like below:-

String[] commandInstall = {
                "/system/bin/sh",
                "-c",
                "cat /sdcard/Download/myfolder/newapp.apk | pm install -S 1528293"
        };
Process process = Runtime.getRuntime().exec(commandInstall);

But now I get the error:-

ava.lang.SecurityException: Reverse mode only supported from shell
    at com.android.server.pm.PackageInstallerSession.doWriteInternal(PackageInstallerSession.java:679)
    at com.android.server.pm.PackageInstallerSession.write(PackageInstallerSession.java:612)
    at android.content.pm.PackageInstaller$Session.write(PackageInstaller.java:852)
    at com.android.server.pm.PackageManagerShellCommand.doWriteSplit(PackageManagerShellCommand.java:2447)
    at com.android.server.pm.PackageManagerShellCommand.runInstall(PackageManagerShellCommand.java:915)
    at com.android.server.pm.PackageManagerShellCommand.onCommand(PackageManagerShellCommand.java:158)
    at android.os.ShellCommand.exec(ShellCommand.java:103)
    at com.android.server.pm.PackageManagerService.onShellCommand(PackageManagerService.java:21330)
    at android.os.Binder.shellCommand(Binder.java:634)
    at android.os.Binder.onTransact(Binder.java:532)
    at android.content.pm.IPackageManager$Stub.onTransact(IPackageManager.java:2821)
    at com.android.server.pm.PackageManagerService.onTransact(PackageManagerService.java:3856)
    at android.os.Binder.execTransact(Binder.java:731)

Edit 2:- Prior to android 9, I could just do the below for installing apps:-

Runtime.getRuntime().exec("pm install -r app.apk");
like image 983
noname Avatar asked Nov 28 '19 13:11

noname


People also ask

How do I run a shell script on an Android app?

To execute a shell command from your android app you can grab the standard input of the su process just launched by Runtime.getRuntime().exec(“su”) and write down the command there, otherwise you are running the commands with the current UID.

What is the use of runtime getruntime() method?

Runtime.getRuntime().exec("sh -c grep -i 'exception' /home/java_w3schools/java/server.log); This class is used to create operating system processes. command () method to add the commands to the process builder and need to invoke the start () method to start a new process on the underlying operating system.

How to execute a shell command from within Java code?

Executing a shell command from within Java code using Runtime.getRuntime ().exec () method and ProcessBuilder api. Examples on chmod, mkdir, grep or any unix commands. In this tutorial, We are going to learn how to run shell commands from java such as chmod, mkdir, grep files.


2 Answers

Looking at the source code of PackageInstallerSession I found that it was changed to :-

switch (Binder.getCallingUid()) {
    case android.os.Process.SHELL_UID:
    case android.os.Process.ROOT_UID:
        break;
    default:
        throw new SecurityException("Reverse mode only supported from shell");
    }

Source So even if it is a system app, the shell command for install might not work. From the commit messages it seems, this was done to let PackageInstaller do this job.

However it seems this again got changed to at some point, but probably is not included in android 9:-

    switch (Binder.getCallingUid()) {
                case android.os.Process.SHELL_UID:
                case android.os.Process.ROOT_UID:
                case android.os.Process.SYSTEM_UID:
                    break;
                default:
                    throw new SecurityException(
                            "Reverse mode only supported from shell or system");
            }

Source

So if the app is a system app , then the best way would be to use PackageInstaller.

like image 194
noname Avatar answered Sep 23 '22 05:09

noname


from PackageInstallerSession.java:

switch (Binder.getCallingUid()) {
                    case android.os.Process.SHELL_UID:
                    case android.os.Process.ROOT_UID:
                    case android.os.Process.SYSTEM_UID:
                        break;
                    default:
                        throw new SecurityException(
                                "Reverse mode only supported from shell or system");
                }

If your app is under system/app maybe you have to put it in system/priv-app. Hope the origin of the exception helps you somehow.

like image 44
Sina Avatar answered Sep 24 '22 05:09

Sina