プログラムでクリーンにデバイスをシャットダウンする方法を見つけようとしています。私のアプリケーションにはルート/システム権限があるので、他の回答で提案されている方法を使用してこれを行うのではなく、システムが行うように「適切に」実行したいと思います...
リフレクションを使用して、クラスcom.android.internal.app.ShutdownThreadとその中のshutdownメソッドにアクセスしようとしています。
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();
}
「コンパイルされたクラスファイルが実際にクラスパス上にあることを確認する」必要があるという他の回答を見てきました-(例外にもかかわらず!)そうだと思いますが、おそらく「クラスパス」の意味を誤解しています。
'Thread'を拡張するクラスも問題であるかどうかもわかりませんか?
次のコードを使用して、再起動するか、リカバリ/ブートローダーを再起動できます。
((PowerManager) ctx.getSystemService(Context.POWER_SERVICE)).reboot(action);
私が使用するアクション文字列は、null、ブートローダー、またはリカバリのいずれかです。うまくいけば「シャットダウン」を試みましたが、うまくいきませんでした。これらは明らかにカーネルに送信されたメッセージですが、どこでも使用できるメッセージへの参照が見つかりません...
注:「プログラムでこれを行うべきではない」と投稿する前に、ユーザーはそれを要求し、アプリケーションが持つシステムとルートのアクセス許可を完全に認識しています。それが彼らがそれをインストールする理由です!
私がやっていることは不可能なのか、リフレクションを使った最初の試みでどこが間違っているのかを誰かが指摘してくれたら、ありがたいです。
アップデート
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)
これはサービスから実行しているためだと思いますが、フォアグラウンドアクティビティから実行する必要があるかもしれません。誰かが何か手がかりを持っているなら、私は知りたいです...