0

我正在尝试找到一种以编程方式和干净地关闭设备的方法。我的应用程序具有根/系统权限,因此我不想使用其他答案中建议的方法来执行此操作,而是希望“正确”地执行此操作,因为系统会...

使用反射,我试图访问类com.android.internal.app.ShutdownThread和其中的关闭方法。

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();
}

我查看了其他答案,指出我需要“确保编译的类文件实际上在类路径上” - 我认为它是(尽管有异常!),但也许我误解了“类路径”的含义。

我也不确定扩展“线程”的类是否也是一个问题?

我可以使用以下代码重新启动或重新启动到恢复/引导加载程序:

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

我使用的操作字符串是 null、bootloader 或 recovery。我很有希望地尝试“关闭”,但它没有用。这些显然是发送到内核的消息,但我找不到在任何地方都可以使用的参考......

注意:在您发布“您不应该以编程方式执行此操作”之前,我的用户已经请求它并且完全了解我的应用程序具有的系统和 root 权限。这就是他们安装它的原因!

如果有人能指出我在做什么是不可能的,或者我第一次尝试使用反射时哪里出错了,我会很感激的。


更新

CommonsWare 的评论当然是绝对正确的,类路径不再存在。在 Jelly Bean 源代码中,它现在是com.android.server.power.ShutdownThread

我尽我所能,但无法使用以下代码解决错误窗口令牌的问题。

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;

我现在得到的错误是:

W/System.err(17002):原因:android.view.WindowManager$BadTokenException:无法添加窗口 android.view.ViewRootImpl$W@41ae4a10 -- 此窗口类型的权限被拒绝

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

我认为这是因为我是从服务中执行的,而它可能需要从前台活动中执行?如果有人有任何线索,我很想知道...

4

0 回答 0