平台:
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"/>