Reputation: 794
A feature of my app is designed to send a reboot broadcast when a Reboot button is clicked.
getActivity().sendBroadcast(new Intent(Intent.ACTION_REBOOT));
According to Android reference documents, apps whose APKs are in /system/priv-app directory are allowed to use signatureOrSystem permissions without sharing the platform cert. Refer to AOSP Privileged vs System app
The REBOOT permission is one of them (in frameworks/base/core/res/AndroidManifest.xml).
<!-- @SystemApi Required to be able to reboot the device.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.REBOOT"
android:label="@string/permlab_reboot"
android:description="@string/permdesc_reboot"
android:protectionLevel="signature|system" />
So I signed my APK with my own cert then pushed my APK to /system/priv-app and made sure the APK file has same read-write access permission as other APKs in the directory.
However, it failed to send a reboot broadcast with an error as followed,
ActivityManager: Permission Denial: not allowed to send broadcast android.intent.action.REBOOT from pid=2801, uid=10016
I checked system statuses with dumpsys and found that the REBOOT permission was granted for the user-id of 10016.
SharedUser [com.example] (10b8d16d):
userId=10016 gids=[1028, 1015, 1007, 3003]
grantedPermissions:
android.permission.REBOOT
BTW, I'm using a pad of Android5.1.1 for the testing.
Upvotes: 1
Views: 2765
Reputation: 794
I got the answer in ActivityManagerService.java from Android source code.
int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
|| callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
|| callingAppId == Process.NFC_UID || callingUid == 0) {
// Always okay.
} else if (callerApp == null || !callerApp.persistent) {
try {
if (AppGlobals.getPackageManager().isProtectedBroadcast(
intent.getAction())) {
String msg = "Permission Denial: not allowed to send broadcast "
+ intent.getAction() + " from pid="
+ callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
...
}
...
}
}
So, android:persistent NEED be set to true.
<application android:name="MyApp"
android:persistent="true">
Upvotes: 2
Reputation: 1113
According to docs, you can't use it.
Broadcast Action: Have the device reboot. This is only for use by system code. This is a protected intent that can only be sent by the system.
https://developer.android.com/reference/android/content/Intent.html#ACTION_REBOOT
Upvotes: -2