Knossos Knossos - 3 months ago 108
Android Question

Turn off device programmatically

I am writing an App that is designed to run on one specific device model (an Android set-top device that runs Amlogic based firmware). I have both root capability and my App is signed with the firmware certificate.

My App is the main focus of the device, and it would be helpful to be able to initiate a complete power-off.

I do not have the

shutdown
command. I do have the
reboot
command.

reboot -p
does not help. It simply freezes the device while remaining powered on.

The
PowerManager
is one step better, but it sets the device into sleep mode, instead of a complete shutdown:

PowerManager pm = (PowerManager)getSystemService(Service.POWER_SERVICE);
pm.goToSleep(SystemClock.uptimeMillis());


I am open to all suggestions - hacky or otherwise. The version of Android is expected to remain at
4.2.2
.




Intents

This command will cause the device to reboot.
Intent.ACTION_SHUTDOWN
does not appear to do anything. Is this Intent perhaps only to report a shutdown, and not to initiate one?

Intent i = new Intent(Intent.ACTION_REBOOT);
i.putExtra("nowait", 1);
i.putExtra("interval", 1);
i.putExtra("window", 0);
sendBroadcast(i);


The most luck I had with this was to request a shutdown by Intent:

Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", true);
startActivity(i);





Shutdown Thread

That is a bit closer. Definitely interesting. Can you find an example of using it?

So far I have come up with this:

Class<?> sdClass = Class.forName("com.android.server.power.ShutdownThread");
Constructor<?> con = sdClass.getDeclaredConstructors()[0];
con.setAccessible(true);

for (Method m : sdClass.getDeclaredMethods()) {
if (m.getName().matches("shutdown")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
} else if (m.getName().matches("rebootOrShutdown")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
} else if (m.getName().matches("beginShutdownSequence")) {
m.setAccessible(true);
m.invoke(sdClass, PlayerActivity.this, false);
}
}


shutdown
and
beginShutdownSequence
create
NullPointerException
s (do you see why?) and
rebootOrShutdown
creates an
InvocationTargetException
due to an
UnsatisfiedLinkError
... It cannot find a native method:


java.lang.UnsatisfiedLinkError: Native method not found:
com.android.server.power.PowerManagerService.nativeShutdown:()V at
com.android.server.power.PowerManagerService.nativeShutdown(Native
Method) at
com.android.server.power.PowerManagerService.lowLevelShutdown(PowerManagerService.java:2163)
at
com.android.server.power.ShutdownThread.rebootOrShutdown(ShutdownThread.java:543)
at
com.android.server.power.ShutdownThread.run(ShutdownThread.java:393)


lowLevelShutdown
is the function that all the functions eventually reach, when configured to shutdown (and not reboot). So figuring out how to avoid this link error may be key.

Answer

In my case, I do not think it is possible to shut the device down how I would like to.

The closest that I managed to get to my target was using:

Intent i = new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN");
i.putExtra("android.intent.extra.KEY_CONFIRM", true);
startActivity(i);

That brings up a dialog to turn the device off. This is the perfect solution, but in my case, using it causes the device to crash. It may be that my device is somewhat special, and other devices will not have these restrictions.

In any case, I hope that my testing will help others in their quest.