3

This answer suggests that an Android app can run dpm like this:

Runtime.getRuntime().exec("dpm set-device-owner com.test.my_device_owner_app");

This fails silently on my Nexus 4 running 5.1.1. The shell returns an error code of 0 (success) and there is no console output. Despite the apparent success, my app does not become the device owner. The device is fresh from a factory reset, with no user account configured.

As a control, I tried running a garbage command instead of dpm. It fails as expected.

Did this ever work? Was it intentionally nerfed?

Community
  • 1
  • 1
Kevin Krumwiede
  • 9,868
  • 4
  • 34
  • 82
  • In your linked answer - there are conditions listed in the comments - do they apply to your setup? – Morrison Chang Jun 05 '15 at 20:17
  • @MorrisonChang I've done all those things, else I could not have installed the app that's trying to run this command. – Kevin Krumwiede Jun 05 '15 at 20:22
  • I have the same problem, though from the commandline using "adb shell ..." it works fine, but for some reason using Runtime.getRuntime().exec() doesn't work – user3294126 Dec 10 '15 at 20:44
  • this was my problem: http://stackoverflow.com/questions/26696440/android-lollipop-becoming-device-admininistrator-doesnt-work – user3294126 Dec 10 '15 at 21:56

2 Answers2

1

dpm incorrectly exits with a status code of 0 when you get the command syntax wrong. The correct syntax is dpm set-device-owner package/.ComponentName. When you get the syntax right, exec(...) throws a SecurityException:

java.lang.SecurityException: Neither user 10086 nor current process has android.permission.MANAGE_DEVICE_ADMINS.
  at android.os.Parcel.readException(Parcel.java:1546)
  at android.os.Parcel.readException(Parcel.java:1499)
  at android.app.admin.IDevicePolicyManager$Stub$Proxy.setActiveAdmin(IDevicePolicyManager.java:2993)
  at com.android.commands.dpm.Dpm.runSetDeviceOwner(Dpm.java:110)
  at com.android.commands.dpm.Dpm.onRun(Dpm.java:82)
  at com.android.internal.os.BaseCommand.run(BaseCommand.java:47)
  at com.android.commands.dpm.Dpm.main(Dpm.java:38)
  at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
  at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:249)

Adding this permission to the manifest does not help, so maybe it's a system-only permission.

It's already a pain in the butt to deploy a kiosk mode app on a device without NFC, since you have to enable developer mode and install the app via adb. I guess the provisioner will just have to run dpm manually.

Kevin Krumwiede
  • 9,868
  • 4
  • 34
  • 82
  • 1
    When I call from the commandline "adb shell dpm set-device-owner BLAH" things work fine (my app becomes device owner - I don't get a security exception because my app is a system app), but when I call from my program "Runtime.getRuntime().exec("dpm set-device-owner BLAH");" I get a silent failure (not a SecurityException, though I wish I got some feedback). Any idea why? – user3294126 Dec 10 '15 at 20:37
  • @user3294126 I'd guess that Google considers it a security risk. – Kevin Krumwiede Dec 10 '15 at 21:34
  • this was the answer: http://stackoverflow.com/questions/26696440/android-lollipop-becoming-device-admininistrator-doesnt-work – user3294126 Dec 10 '15 at 21:55
0

As some extra info, I was able to capture and log the output (stdout and stderr) to logcat

DevicePolicyManager dpm = (DevicePolicyManager)getSystemService(Context.DEVICE_POLICY_SERVICE);
Runtime rt = Runtime.getRuntime();
Process proc = null;
try {
    proc = rt.exec("dpm set-device-owner com.myapp/.DeviceOwnerReceiver");
    BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));

    BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));

    // Read the output from the command
    System.out.println("Here is the standard output of the command:\n");
    String s = null;
    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) {
    e.printStackTrace();
}