Merge "Make AppWidgets encryption-aware."
This commit is contained in:
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user