Merge "Make AppWidgets encryption-aware."

This commit is contained in:
Jeff Sharkey
2015-12-17 21:28:06 +00:00
committed by Android (Google) Code Review
4 changed files with 66 additions and 38 deletions

View File

@@ -16,6 +16,7 @@
package com.android.server.appwidget;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppGlobals;
import android.app.AppOpsManager;
@@ -76,6 +77,7 @@ import android.view.Display;
import android.view.WindowManager;
import android.widget.RemoteViews;
import com.android.internal.R;
import com.android.internal.appwidget.IAppWidgetHost;
import com.android.internal.appwidget.IAppWidgetService;
import com.android.internal.os.BackgroundThread;
@@ -83,7 +85,6 @@ import com.android.internal.os.SomeArgs;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.widget.IRemoteViewsAdapterConnection;
import com.android.internal.widget.IRemoteViewsFactory;
import com.android.internal.R;
import com.android.server.LocalServices;
import com.android.server.WidgetBackupProvider;
@@ -139,8 +140,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
private static final int CURRENT_VERSION = 1;
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
final String action = intent.getAction();
final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
if (DEBUG) {
Slog.i(TAG, "Received broadcast: " + action);
@@ -148,23 +151,16 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
onConfigurationChanged();
} else if (Intent.ACTION_USER_STARTED.equals(action)) {
onUserStarted(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL));
} else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
onUserUnlocked(userId);
} else if (Intent.ACTION_USER_STOPPED.equals(action)) {
onUserStopped(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL));
onUserStopped(userId);
} else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
refreshProfileWidgetsMaskedState(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
UserHandle.USER_NULL));
refreshProfileWidgetsMaskedState(userId);
} else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
UserHandle profile = (UserHandle)intent.getParcelableExtra(Intent.EXTRA_USER);
if (profile != null) {
refreshWidgetMaskedState(profile.getIdentifier());
}
refreshWidgetMaskedState(userId);
} else {
onPackageBroadcastReceived(intent, intent.getIntExtra(
Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL));
onPackageBroadcastReceived(intent, userId);
}
}
};
@@ -263,7 +259,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
sdFilter, null, null);
IntentFilter userFilter = new IntentFilter();
userFilter.addAction(Intent.ACTION_USER_STARTED);
userFilter.addAction(Intent.ACTION_USER_UNLOCKED);
userFilter.addAction(Intent.ACTION_USER_STOPPED);
userFilter.addAction(Intent.ACTION_USER_SWITCHED);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
@@ -340,6 +336,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
private void onPackageBroadcastReceived(Intent intent, int userId) {
if (!isUserRunningAndUnlocked(userId)) return;
final String action = intent.getAction();
boolean added = false;
boolean changed = false;
@@ -419,9 +417,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
* Refresh the masked state for all profiles under the given user.
*/
private void refreshProfileWidgetsMaskedState(int userId) {
if (userId == UserHandle.USER_NULL) {
return;
}
if (!isUserRunningAndUnlocked(userId)) return;
List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
if (profiles != null) {
for (int i = 0; i < profiles.size(); i++) {
@@ -435,6 +431,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
* Mask/unmask widgets in the given profile, depending on the quiet state of the profile.
*/
private void refreshWidgetMaskedState(int profileId) {
if (!isUserRunningAndUnlocked(profileId)) return;
final long identity = Binder.clearCallingIdentity();
try {
UserInfo user = mUserManager.getUserInfo(profileId);
@@ -484,6 +481,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
private void ensureGroupStateLoadedLocked(int userId) {
if (!isUserRunningAndUnlocked(userId)) {
throw new IllegalStateException(
"User " + userId + " must be unlocked for widgets to be available");
}
final int[] profileIds = mSecurityPolicy.getEnabledGroupProfileIds(userId);
// Careful lad, we may have already loaded the state for some
@@ -2321,7 +2323,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
}
}
private void onUserStarted(int userId) {
private void onUserUnlocked(int userId) {
synchronized (mLock) {
ensureGroupStateLoadedLocked(userId);
@@ -2510,6 +2512,15 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
mWidgetPackages.clear();
}
private boolean isUserRunningAndUnlocked(int userId) {
if (userId == UserHandle.USER_NULL) {
return false;
} else {
return mContext.getSystemService(ActivityManager.class)
.isUserRunningAndUnlocked(userId);
}
}
@Override
public boolean isBoundWidgetPackage(String packageName, int userId) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {

View File

@@ -17061,6 +17061,8 @@ public final class ActivityManagerService extends ActivityManagerNative
}
}
// 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 {
@@ -17070,35 +17072,47 @@ public final class ActivityManagerService extends ActivityManagerNative
return ActivityManager.BROADCAST_SUCCESS;
}
/*
* Prevent non-system code (defined here to be non-persistent
* processes) from sending protected broadcasts.
*/
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.
final boolean isCallerSystem;
switch (UserHandle.getAppId(callingUid)) {
case Process.ROOT_UID:
case Process.SYSTEM_UID:
case Process.PHONE_UID:
case Process.SHELL_UID:
case Process.BLUETOOTH_UID:
case Process.NFC_UID:
isCallerSystem = true;
break;
default:
isCallerSystem = (callerApp != null) && callerApp.persistent;
break;
}
// Yell if the system is trying to send a non-protected broadcast.
// The vast majority of broadcasts sent from system callers should
// be protected to avoid security holes, so exceptions here should
// be incredibly rare.
if (!isProtectedBroadcast
&& !Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
// TODO: eventually switch over to hard throw
if (isCallerSystem) {
if (isProtectedBroadcast
|| Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
|| Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
|| AppWidgetManager.ACTION_APPWIDGET_UPDATE.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.
} else {
// 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.
Log.wtf(TAG, "Sending non-protected broadcast " + action
+ " from system", new Throwable());
}
} else if (callerApp == null || !callerApp.persistent) {
} else {
if (isProtectedBroadcast) {
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)) {
} 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,

View File

@@ -245,6 +245,7 @@ final class UserController {
mHandler.sendMessage(mHandler.obtainMessage(SYSTEM_USER_UNLOCK_MSG, userId, 0));
final Intent unlockedIntent = new Intent(Intent.ACTION_USER_UNLOCKED);
unlockedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
unlockedIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND);
mService.broadcastIntentLocked(null, null, unlockedIntent, null, null, 0, null,

View File

@@ -526,6 +526,7 @@ public class UserManagerService extends IUserManager.Stub {
if (parentHandle != null) {
intent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
intent.putExtra(Intent.EXTRA_USER, profileHandle);
intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtras(extras);
mContext.sendBroadcastAsUser(intent, parentHandle);
@@ -2073,6 +2074,7 @@ public class UserManagerService extends IUserManager.Stub {
managedProfileIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY |
Intent.FLAG_RECEIVER_FOREGROUND);
managedProfileIntent.putExtra(Intent.EXTRA_USER, new UserHandle(removedUserId));
managedProfileIntent.putExtra(Intent.EXTRA_USER_HANDLE, removedUserId);
mContext.sendBroadcastAsUser(managedProfileIntent, new UserHandle(parentUserId), null);
}