Protect Broadcast 保护广播
一、android:sharedUserId="android.uid.system"
-
系统中所有使用android.uid.system作为共享UID的APK,都会首先在manifest节点中增加 android:sharedUserId="android.uid.system",然后在Android.mk中增加 LOCAL_CERTIFICATE := platform.如ZsDeskclock,:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.journeyui.deskclock"
android:sharedUserId="android.uid.system"
android:versionCode="410"
android:versionName="4.1.0">
...
</manifest>
下面所说的系统应用也是指这些shareUID是system的应用。
2. 在开机PMS初始化的时候,将该name为“android.uid.system”的uid归为1000的system用户ID;
PackageManagerService.java
public PackageManagerService(Context context, Installer installer,
boolean factoryTest, boolean onlyCore) {
...
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
...
}
Process.java
/**
* Defines the UID/GID under which system code runs.
*/
public static final int SYSTEM_UID = 1000;
二、AMS对系统应用发出的广播进行安全检查
当应用或者组件发送广播时,在广播发送的必经之路上,AMS对系统应用发送的广播进行了检查:
1. 判断是否是系统uid,
ActivityServiceManager.java
final int broadcastIntentLocked(){
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case Process.ROOT_UID:
case Process.SYSTEM_UID:
case Process.PHONE_UID:
case Process.BLUETOOTH_UID:
case Process.NFC_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = (callerApp != null) && callerApp.persistent;
break;
}
}
2. 如果是SYSTEM_UID,便对该广播进行安全检查:
if (isCallerSystem) {
checkBroadcastFromSystem(intent, callerApp, callerPackage, callingUid,
isProtectedBroadcast, receivers);
}
3. 在checkBroadcastFromSystem()函数中进行安全检查:
private void checkBroadcastFromSystem(Intent intent, ProcessRecord callerApp,
String callerPackage, int callingUid, boolean isProtectedBroadcast, List receivers) {
final String action = intent.getAction();
if (isProtectedBroadcast //A
|| 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;