Song Bee
Song Bee

Reputation: 794

Permission Denial of android.intent.action.REBOOT for APP in /system/priv-app

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

Answers (2)

Song Bee
Song Bee

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

Federico Picci
Federico Picci

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

Related Questions