0

I'm trying to find a way to shutdown the device programmatically and cleanly. My application has root/system permissions, so rather than using methods suggested in other answers to do this, I want to do it 'properly', as the System would...

Using reflection, I'm trying to access the Class com.android.internal.app.ShutdownThread and the shutdown method within it.

private static final String SHUTDOWN_CLASS = "com.android.internal.app.ShutdownThread";
private static final String SHUTDOWN_METHOD = "shutdown";

Class<?> sdClass;
Method shutdown;
boolean sd;
boolean success = false;

try {
    sdClass = Class.forName(SHUTDOWN_CLASS);
    Object obj = sdClass.newInstance();

    shutdown = sdClass.getDeclaredMethod(SHUTDOWN_METHOD);

    shutdown.setAccessible(true);
    sd = (Boolean) shutdown.invoke(obj, ctx, false);

    success = sd;

} catch (ClassNotFoundException e) {
    e.printStackTrace();
} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (IllegalArgumentException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
} catch (InstantiationException e) {
    e.printStackTrace();
}

I've looked at other answers that state I need to "Make sure the compiled class file is actually on the classpath" - I assume it is (despite the Exception!), but perhaps I misunderstand the meaning of 'classpath'.

I'm also not certain if the Class extending 'Thread'is also a problem?

I'm able to reboot or reboot to recovery/bootloader with the following code:

((PowerManager) ctx.getSystemService(Context.POWER_SERVICE)).reboot(action);

The action String I use is either null, bootloader or recovery. I tried rather hopefully "shutdown" but it didn't work. These are apparently messages sent to the Kernel, but I can't find reference to which ones are usable anywhere...

Note: Before you post 'you shouldn't be doing this programmatically', my users have requested it and are fully aware of the System and root permissions my application has. That's why they install it!

If someone could point out if what I'm doing is not possible or where I'm going wrong with my first attempt at using reflection, I'd appreciated it.


UPDATE

CommonsWare's comment was of course absolutely correct, the Class path no longer exists. In the Jelly Bean source code it's now com.android.server.power.ShutdownThread

I got as far as I could, but have been unable to get past the problem of a bad window token using the following code.

boolean sd = false;
boolean success = false;

        try {
            Class<?> sdClass = Class.forName("com.android.server.power.ShutdownThread");

            for (Constructor<?> ctor : sdClass.getDeclaredConstructors()) {
                // Log output
            }

            Constructor<?> con = sdClass.getDeclaredConstructors()[0];
            con.setAccessible(true);

            for (Method m : sdClass.getDeclaredMethods()) {

                if (m.getName().matches("shutdown")) {
                    m.setAccessible(true);
                    sd = (Boolean) m.invoke(ctx, ctx, false);
                }
            }

            success = sd;

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
             e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
             e.printStackTrace();
        }

        return success;

The error I get now is:

W/System.err(17002): Caused by: android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@41ae4a10 -- permission denied for this window type

W/System.err(17002): at com.android.server.power.ShutdownThread.beginShutdownSequence(ShutdownThread.java:222)

I assume it is because I'm executing this from a service, whereas it may need to be executed from a Foreground Activity? If anybody has any clues, I'd love to know...

Community
  • 1
  • 1
brandall
  • 6,094
  • 4
  • 49
  • 103

0 Answers0