11

I am developing an Android application and we need to power off the device under certain circumstances.

I have read in many places that you need a rooted phone in order to do so. Then, you can issue the "reboot" command by using Java's API:

try {
    Process proc = Runtime.getRuntime()
                .exec(new String[]{ "su", "-c", "reboot -p" });
    proc.waitFor();
} catch (Exception ex) {
    ex.printStackTrace();
}

I have actually tried this in a Cyanogenmod 10 device (Samsung Galaxy S3), and it works. However, we do not want a rooted device in order to power it off, since the end user will then be able to do unintended things which are not allowed by our company.

On the other hand, our application is signed by the manufacturer's certificate, in this case Cyanogen's. I have read that by signing your application with the manufacturer's certificate, you should be able to issue privileged commands (as if root). However, even if I install my app as a system app signed with the manufacturer's certificate, the above code does not work:

  • If I leave the "su" part of the command, the "Superuser Request" screen is displayed, but that's something we are trying to avoid.

  • If I remove the "su" part (just leaving "reboot -p"), the command is silently ignored.

As a result, we are not being able to poweroff our device with our system app, which is signed with the manifacturer's certificate. So my question is, how am I supposed to do that?

EDITED

And, by the way, just in case someone is not sure about it: the application is properly signed and installed as a system application, because we can actually access some restricted APIs, such as PowerManager.goToSleep()

Knuckles the Echidna
  • 1,716
  • 3
  • 17
  • 22

4 Answers4

9

If you want the device to reboot (power off and on), then try PowerManager.reboot()

PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
powerManager.reboot(null);

android.os.PowerManager:

/**
 * Reboot the device.  Will not return if the reboot is successful.
 * <p>
 * Requires the {@link android.Manifest.permission#REBOOT} permission.
 * </p>
 *
 * @param reason code to pass to the kernel (e.g., "recovery") to
 *               request special boot modes, or null.
 */
public void reboot(String reason) {
    try {
        mService.reboot(false, reason, true);
    } catch (RemoteException e) {
    }
}

UPDATE

If you want the device to completely turn off, use PowerManagerService.shutdown():

IPowerManager powerManager = IPowerManager.Stub.asInterface(
        ServiceManager.getService(Context.POWER_SERVICE));
try {
    powerManager.shutdown(false, false);
} catch (RemoteException e) {
}

com.android.server.power.PowerManagerService:

/**
 * Shuts down the device.
 *
 * @param confirm If true, shows a shutdown confirmation dialog.
 * @param wait If true, this call waits for the shutdown to complete and does not return.
 */
@Override // Binder call
public void shutdown(boolean confirm, boolean wait) {
    mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);

    final long ident = Binder.clearCallingIdentity();
    try {
        shutdownOrRebootInternal(true, confirm, null, wait);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}
ozbek
  • 20,955
  • 5
  • 61
  • 84
  • 1
    I specifically said "power off", not reboot. – Knuckles the Echidna Jun 19 '13 at 12:32
  • 1
    Yeah, I noticed that. But since you have been trying to use `su reboot` as shown in the question body, I thought `PowerManager.reboot()` would be helpful enough. Anyway, please see the update with the "power off". – ozbek Jun 19 '13 at 13:22
  • No, not part of SDK. But available for _"the application [that] is properly signed and installed as a system application"_ – ozbek Jun 19 '13 at 14:11
  • OK, fair enough. Even though neither your solution nor mine are "standard", since they both rely on specific internal APIs provided by the device's manufacturer, yours is cleaner and probably will be supported for long. Moreover, when using the IPowerManager, the system shuts down nicely, but when you use the "poweroff" command it just shuts down abruptly, which I guess could be a problem. Thanks a lot! – Knuckles the Echidna Jun 19 '13 at 14:28
  • By the way, I don't think that what you said about it being available "for system apps" is necessarily true. That part of the API is private, so Google may get rid of it in future versions. I mean, that was not even available in previous versions of Android. – Knuckles the Echidna Jun 20 '13 at 05:51
  • Hmm... I am not sure about shutdown() but reboot() was there at least since Eclair. Nevertheless, any version of Android had, has and will have these or other private APIs to turn the device off and reboot. – ozbek Jun 20 '13 at 10:03
  • Well, I do not think that's true at all. Android may have a specific internal API, but it's internal, so it may well change in the future. They are actually pretty clear about "using internal Apis at your own risk". Can you please provide a link where they say that this API to power off the device "will" always be available – Knuckles the Echidna Jun 20 '13 at 10:16
  • I did not say _only_ this will be available. I am saying if these will go away, another will be there as a replacement. There is no link for this claim. I am saying this based on the common sense that the OS will and should provide an option to turn the device off. All the time. – ozbek Jun 20 '13 at 10:19
  • Hi guys, how do I import IPowerManager and other private API parts to my application? Could you share that knowledge please? – SebastianT Aug 27 '14 at 14:56
  • @SebastianT: unless you are building and bundling your app with the platform, you can not use above methods. – ozbek Aug 28 '14 at 04:34
  • @shoerat I though that if I've rooted the device, I could use it. Thanks though. – SebastianT Aug 28 '14 at 13:36
4

This was working fine for me:

startActivity(new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN"));

you need this permission ( depends on being system-app ):

 <uses-permission android:name="android.permission.SHUTDOWN"/>

source: https://github.com/sas101/shutdown-android-app/wiki

ligi
  • 39,001
  • 44
  • 144
  • 244
0

OK, my mistake.

As I performed some tests, I did not realize that I had removed "android:sharedUserId="android.uid.system" from the manifest.

Once the sharedUserId is included, the following code works without prompting the user to confirm root access:

try {
    Process proc = Runtime.getRuntime()
            .exec(new String[]{ "su", "-c", "reboot -p" });
    proc.waitFor();
} catch (Exception ex) {
    ex.printStackTrace();
}

I tried to remove "su" (because the system may not provide such a command), but in that case it does not work. Surprisingly, the file system is remounted in read-only mode, so I must remount it again with write permissions.

Knuckles the Echidna
  • 1,716
  • 3
  • 17
  • 22
0

this is for kotlin

(requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager)
                        .reboot("reason")
Terry Hope
  • 11
  • 3