android 系统受保护广播

简介: android 系统受保护广播

平台:


rk3288 + android 7.1


Android 对广播有明显的限定权限:


系统应用仅发送指定受保护广播.


E/ActivityManager: Sending non-protected broadcast android.intent.action.NEW_BROADCAST from system 1437:com.android.shell/2000 pkg com.android.shell
     java.lang.Throwable
         at com.android.server.am.ActivityManagerService.checkBroadcastFromSystem(ActivityManagerService.java:18169)
         at com.android.server.am.ActivityManagerService.broadcastIntentLocked(ActivityManagerService.java:18651)
         at com.android.server.am.ActivityManagerService.broadcastIntent(ActivityManagerService.java:18833)
         at android.app.ActivityManagerNative.onTransact(ActivityManagerNative.java:499)
         at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2911)
         at android.os.Binder.execTransact(Binder.java:565)


相关源码:


|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
    private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
            String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
        final String action = intent.getAction();
        if (isProtectedBroadcast
                || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
                || Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action)
                || Intent.ACTION_MEDIA_BUTTON.equals(action)
                || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
                || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
                || Intent.ACTION_MASTER_CLEAR.equals(action)
                || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
                || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)
                || TelephonyIntents.ACTION_REQUEST_OMADM_CONFIGURATION_UPDATE.equals(action)
                || SuggestionSpan.ACTION_SUGGESTION_PICKED.equals(action)) {
            // Broadcast is either protected, or it's a public action that
            // we've relaxed, so it's fine for system internals to send.
            return;
        }
        // This broadcast may be a problem...  but there are often system components that
        // want to send an internal broadcast to themselves, which is annoying to have to
        // explicitly list each action as a protected broadcast, so we will check for that
        // one safe case and allow it: an explicit broadcast, only being received by something
        // that has protected itself.
        if (receivers != null && receivers.size() > 0
                && (intent.getPackage() != null || intent.getComponent() != null)) {
            boolean allProtected = true;
            for (int i = receivers.size()-1; i >= 0; i--) {
                Object target = receivers.get(i);
                if (target instanceof ResolveInfo) {
                    ResolveInfo ri = (ResolveInfo)target;
                    if (ri.activityInfo.exported && ri.activityInfo.permission == null) {
                        allProtected = false;
                        break;
                    }
                } else {
                    BroadcastFilter bf = (BroadcastFilter)target;
                    if (bf.requiredPermission == null) {
                        allProtected = false;
                        break;
                    }
                }
            }
            if (allProtected) {
                // All safe!
                return;
            }
        }
        // The vast majority of broadcasts sent from system internals
        // should be protected to avoid security holes, so yell loudly
        // to ensure we examine these cases.
        if (callerApp != null) {
            Log.wtf(TAG, "Sending non-protected broadcast " + action
                            + " from system " + callerApp.toShortString() + " pkg " + callerPackage,
                    new Throwable());
        } else {
            Log.wtf(TAG, "Sending non-protected broadcast " + action
                            + " from system uid " + UserHandle.formatUid(callingUid)
                            + " pkg " + callerPackage,
                    new Throwable());
        }
    }


广播还是可以发出去的, 只是会有LOG提示, 不影响实际功能.


不允许第三方应用发送受保护广播


非系统APK 发送了系统广播:


Process: com.androidtest, PID: 1640
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.androidtest/com.androidtest.MainActivity}: java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.NEW_BROADCAST from pid=1640, uid=10056
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2671)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732)
    at android.app.ActivityThread.-wrap12(ActivityThread.java)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1483)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:154)
    at android.app.ActivityThread.main(ActivityThread.java:6141)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)
 Caused by: java.lang.SecurityException: Permission Denial: not allowed to send broadcast android.intent.action.NEW_BROADCAST from pid=1640, uid=10056
    at android.os.Parcel.readException(Parcel.java:1684)
    at android.os.Parcel.readException(Parcel.java:1637)
    at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:3565)
    at android.app.ContextImpl.sendBroadcast(ContextImpl.java:881)
    at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:421)
    at com.androidtest.MainActivity.testBroadcast(MainActivity.java:131)
    at com.androidtest.MainActivity.onCreate(MainActivity.java:41)
    at android.app.Activity.performCreate(Activity.java:6709)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1118)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2624)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2732) 
    at android.app.ActivityThread.-wrap12(ActivityThread.java) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1483) 
    at android.os.Handler.dispatchMessage(Handler.java:102) 
    at android.os.Looper.loop(Looper.java:154) 
    at android.app.ActivityThread.main(ActivityThread.java:6141) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:802)


异常代码:


|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
    final int broadcastIntentLocked(ProcessRecord callerApp,
            String callerPackage, Intent intent, String resolvedType,
            IIntentReceiver resultTo, int resultCode, String resultData,
            Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
            boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
        intent = new Intent(intent);
        // By default broadcasts do not go to stopped apps.
        intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
        // If we have not finished booting, don't allow this to launch new processes.
        if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
        }
        if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
                + " ordered=" + ordered + " userid=" + userId);
        if ((resultTo != null) && !ordered) {
            Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
        }
        userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, true,
                ALLOW_NON_FULL, "broadcast", callerPackage);
        // Make sure that the user who is receiving this broadcast is running.
        // If not, we will just skip it. Make an exception for shutdown broadcasts
        // and upgrade steps.
        if (userId != UserHandle.USER_ALL && !mUserController.isUserRunningLocked(userId, 0)) {
            if ((callingUid != Process.SYSTEM_UID
                    || (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
                    && !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
                Slog.w(TAG, "Skipping broadcast of " + intent
                        + ": user " + userId + " is stopped");
                return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
            }
        }
        BroadcastOptions brOptions = null;
        if (bOptions != null) {
            brOptions = new BroadcastOptions(bOptions);
            if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
                // See if the caller is allowed to do this.  Note we are checking against
                // the actual real caller (not whoever provided the operation as say a
                // PendingIntent), because that who is actually supplied the arguments.
                if (checkComponentPermission(
                        android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
                        Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
                        != PackageManager.PERMISSION_GRANTED) {
                    String msg = "Permission Denial: " + intent.getAction()
                            + " broadcast from " + callerPackage + " (pid=" + callingPid
                            + ", uid=" + callingUid + ")"
                            + " requires "
                            + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                }
            }
        }
        // Verify that protected broadcasts are only being sent by system code,
        // and that system code is only sending protected broadcasts.
        final String action = intent.getAction();
        final boolean isProtectedBroadcast;
        try {
            isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception", e);
            return ActivityManager.BROADCAST_SUCCESS;
        }
        final boolean isCallerSystem;
        switch (UserHandle.getAppId(callingUid)) {
            case Process.ROOT_UID:
            case Process.SYSTEM_UID:
    case Process.SHELL_UID://AnsonCode make shell send system broadcast
            case Process.PHONE_UID:
            case Process.BLUETOOTH_UID:
            case Process.NFC_UID:
                isCallerSystem = true;
                break;
            default:
                isCallerSystem = (callerApp != null) && callerApp.persistent;
                break;
        }
        // First line security check before anything else: stop non-system apps from
        // sending protected broadcasts.
        if (!isCallerSystem) {
            if (isProtectedBroadcast) {//限制受保护广播, 并且抛出异常给APP.
                String msg = "Permission Denial: not allowed to send broadcast "
                        + action + " from pid="
                        + callingPid + ", uid=" + callingUid;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
            } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                    || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
                // Special case for compatibility: we don't want apps to send this,
                // but historically it has not been protected and apps may be using it
                // to poke their own app widget.  So, instead of making it protected,
                // just limit it to the caller.
                if (callerPackage == null) {
                    String msg = "Permission Denial: not allowed to send broadcast "
                            + action + " from unknown caller.";
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                } else if (intent.getComponent() != null) {
                    // They are good enough to send to an explicit component...  verify
                    // it is being sent to the calling app.
                    if (!intent.getComponent().getPackageName().equals(
                            callerPackage)) {
                        String msg = "Permission Denial: not allowed to send broadcast "
                                + action + " to "
                                + intent.getComponent().getPackageName() + " from "
                                + callerPackage;
                        Slog.w(TAG, msg);
                        throw new SecurityException(msg);
                    }
                } else {
                    // Limit broadcast to their own package.
                    intent.setPackage(callerPackage);
                }
            }
        }
  ...


使SHELL可以发送系统广播:


|-- frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -18251,6 +18251,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         switch (UserHandle.getAppId(callingUid)) {
             case Process.ROOT_UID:
             case Process.SYSTEM_UID:
+            case Process.SHELL_UID://make shell send system broadcast
             case Process.PHONE_UID:
             case Process.BLUETOOTH_UID:
             case Process.NFC_UID:


添加广播以支持系统应用发送:


|-- frameworks/base/core/res/AndroidManifest.xml
@@ -143,6 +143,7 @@
     <protected-broadcast android:name="android.bluetooth.device.action.SDP_RECORD" />
     <protected-broadcast android:name="android.bluetooth.devicepicker.action.LAUNCH" />
     <protected-broadcast android:name="android.bluetooth.devicepicker.action.DEVICE_SELECTED" />
+    <protected-broadcast android:name="android.intent.action.NEW_BROADCAST"/>


相关文章
|
30天前
|
搜索推荐 Android开发 iOS开发
安卓与iOS系统的用户界面设计对比分析
本文通过对安卓和iOS两大操作系统的用户界面设计进行对比分析,探讨它们在设计理念、交互方式、视觉风格等方面的差异及各自特点,旨在帮助读者更好地理解和评估不同系统的用户体验。
20 1
|
2月前
|
搜索推荐 Android开发 iOS开发
探析安卓与iOS系统的优劣
【2月更文挑战第7天】安卓与iOS是当今手机市场上最主流的两款操作系统,各有优劣。本文将从用户体验、开放程度、生态系统等方面对两者进行深入探析,以期帮助读者更好地了解它们的特点。
|
2天前
|
Android开发
Android构建系统:Android.mk(2)函数详解
Android构建系统:Android.mk(2)函数详解
10 1
|
2天前
|
存储 Java API
Android系统 文件访问权限笔记
Android系统 文件访问权限笔记
28 1
|
2天前
|
移动开发 Java Unix
Android系统 自动加载自定义JAR文件
Android系统 自动加载自定义JAR文件
16 1
|
2天前
|
Shell Android开发 开发者
Android系统 自定义动态修改init.custom.rc
Android系统 自定义动态修改init.custom.rc
18 0
|
2天前
|
测试技术 Android开发 开发者
RK3568 Android系统客制化动态替换ro任意属性
RK3568 Android系统客制化动态替换ro任意属性
13 1
|
2天前
|
存储 Linux Android开发
RK3568 Android/Linux 系统动态更换 U-Boot/Kernel Logo
RK3568 Android/Linux 系统动态更换 U-Boot/Kernel Logo
15 0
|
2天前
|
存储 缓存 安全
Android系统 应用存储路径与权限
Android系统 应用存储路径与权限
6 0
Android系统 应用存储路径与权限
|
2天前
|
存储 开发工具 Android开发
Android系统 权限组管理和兼容性
Android系统 权限组管理和兼容性
11 0