Выключите устройство Android с помощью приложения, подписанного системой
Я занимаюсь разработкой приложения для Android, и нам необходимо отключить устройство при определенных обстоятельствах.
Во многих местах я читал, что для этого нужен рутованный телефон. Затем вы можете выполнить команду "перезагрузка" с помощью API Java:
try {
Process proc = Runtime.getRuntime()
.exec(new String[]{ "su", "-c", "reboot -p" });
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
Я действительно попробовал это на устройстве CyanogenMod 10 (Samsung Galaxy S3), и он работает. Однако нам не нужно рутованное устройство для его отключения, поскольку конечный пользователь сможет делать непреднамеренные действия, которые не разрешены нашей компанией.
С другой стороны, наша заявка подписана сертификатом производителя, в данном случае Cyanogen. Я прочитал, что, подписав ваше приложение сертификатом производителя, вы сможете выполнять привилегированные команды (как root). Однако даже если я устанавливаю свое приложение как системное приложение, подписанное сертификатом производителя, приведенный выше код не работает:
Если я оставлю часть команды su, появится экран "Запрос суперпользователя", но мы стараемся избегать этого.
Если я удаляю часть "su" (просто оставляя "reboot -p"), команда игнорируется.
В результате мы не можем выключить наше устройство с помощью нашего системного приложения, которое подписано сертификатом манифестатора. Итак, мой вопрос, как я должен это сделать?
РЕДАКТИРОВАНИЕ
И, кстати, на всякий случай, если кто-то не уверен в этом: приложение правильно подписано и установлено как системное приложение, потому что мы на самом деле можем получить доступ к некоторым ограниченным API, таким как PowerManager.goToSleep()
5 ответов
Если вы хотите, чтобы устройство перезагрузилось (выключите и снова включите), попробуйте PowerManager.reboot()
PowerManager powerManager = (PowerManager)getSystemService(Context.POWER_SERVICE);
powerManager.reboot(null);
/**
* 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) {
}
}
ОБНОВИТЬ
Если вы хотите, чтобы устройство полностью выключилось, используйте 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);
}
}
Это работало нормально для меня:
startActivity(new Intent("android.intent.action.ACTION_REQUEST_SHUTDOWN"));
вам нужно это разрешение (зависит от того, является ли системное приложение):
<uses-permission android:name="android.permission.SHUTDOWN"/>
источник: https://github.com/sas101/shutdown-android-app/wiki
это для котлина
(requireContext().getSystemService(Context.POWER_SERVICE) as PowerManager)
.reboot("reason")
ОК, моя ошибка
Выполнив несколько тестов, я не понял, что удалил "android:sharedUserId="android.uid.system"из манифеста.
После того, как sharedUserId включен, следующий код работает без запроса пользователя на подтверждение корневого доступа:
try {
Process proc = Runtime.getRuntime()
.exec(new String[]{ "su", "-c", "reboot -p" });
proc.waitFor();
} catch (Exception ex) {
ex.printStackTrace();
}
Я попытался удалить "su" (потому что система может не предоставить такую команду), но в этом случае она не работает. Удивительно, но файловая система перемонтируется в режиме только для чтения, поэтому я должен снова перемонтировать ее с разрешениями на запись.
Это старая тема, но она все еще актуальна. Я тестировал это на Android R.
Для приложения, подписанного платформой, вы можете использовать частный SDK посредством отражения.
Во-первых, ваши явные потребности
<uses-permission android:name="android.permission.REBOOT" tools:ignore="ProtectedPermissions" />
Затем вы можете завершить работу, используя
private void shutdown() {
final PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
try {
Method shutdownMethod = PowerManager.class.getMethod("shutdown", boolean.class, String.class, boolean.class);
boolean confirm = false; // If true, shows a shutdown confirmation dialog.
String reason = "shutdown";
boolean wait = true; // If true, this call waits for the shutdown to complete and does not return.
shutdownMethod.invoke(powerManager, confirm, reason, wait);
} catch (Exception e) {
Log.e(TAG, "Cannot shutdown", e);
}
}