summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityManagerNative.java20
-rw-r--r--core/java/android/app/ActivityThread.java77
-rw-r--r--core/java/android/app/IActivityManager.java2
-rw-r--r--core/java/android/content/ContentResolver.java4
-rw-r--r--core/java/android/content/ContentService.java4
-rw-r--r--core/java/android/content/Intent.java9
-rw-r--r--core/java/com/android/internal/content/PackageMonitor.java51
-rw-r--r--core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk5
-rw-r--r--core/tests/hosttests/test-apps/DownloadManagerTestApp/AndroidManifest.xml4
-rw-r--r--core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java4
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java104
-rw-r--r--services/java/com/android/server/WallpaperManagerService.java45
-rw-r--r--services/java/com/android/server/am/ActivityManagerService.java49
-rw-r--r--services/java/com/android/server/am/UsageStatsService.java2
-rw-r--r--services/java/com/android/server/pm/PackageManagerService.java19
15 files changed, 261 insertions, 138 deletions
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 8436b2c..b0df660 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -1611,6 +1611,14 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
return true;
}
+ case GET_RUNNING_USER_IDS_TRANSACTION: {
+ data.enforceInterface(IActivityManager.descriptor);
+ int[] result = getRunningUserIds();
+ reply.writeNoException();
+ reply.writeIntArray(result);
+ return true;
+ }
+
case REMOVE_SUB_TASK_TRANSACTION:
{
data.enforceInterface(IActivityManager.descriptor);
@@ -3846,6 +3854,18 @@ class ActivityManagerProxy implements IActivityManager
return result;
}
+ public int[] getRunningUserIds() throws RemoteException {
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(IActivityManager.descriptor);
+ mRemote.transact(GET_RUNNING_USER_IDS_TRANSACTION, data, reply, 0);
+ reply.readException();
+ int[] result = reply.createIntArray();
+ reply.recycle();
+ data.recycle();
+ return result;
+ }
+
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 81d8765..67ecf5b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3638,39 +3638,45 @@ public final class ActivityThread {
}
}
- ArrayList<ComponentCallbacks2> collectComponentCallbacksLocked(
+ ArrayList<ComponentCallbacks2> collectComponentCallbacks(
boolean allActivities, Configuration newConfig) {
ArrayList<ComponentCallbacks2> callbacks
= new ArrayList<ComponentCallbacks2>();
- if (mActivities.size() > 0) {
- for (ActivityClientRecord ar : mActivities.values()) {
- Activity a = ar.activity;
- if (a != null) {
- Configuration thisConfig = applyConfigCompatMainThread(mCurDefaultDisplayDpi,
- newConfig, ar.packageInfo.mCompatibilityInfo.getIfNeeded());
- if (!ar.activity.mFinished && (allActivities || !ar.paused)) {
- // If the activity is currently resumed, its configuration
- // needs to change right now.
- callbacks.add(a);
- } else if (thisConfig != null) {
- // Otherwise, we will tell it about the change
- // the next time it is resumed or shown. Note that
- // the activity manager may, before then, decide the
- // activity needs to be destroyed to handle its new
- // configuration.
- if (DEBUG_CONFIGURATION) {
- Slog.v(TAG, "Setting activity "
- + ar.activityInfo.name + " newConfig=" + thisConfig);
+ synchronized (mPackages) {
+ final int N = mAllApplications.size();
+ for (int i=0; i<N; i++) {
+ callbacks.add(mAllApplications.get(i));
+ }
+ if (mActivities.size() > 0) {
+ for (ActivityClientRecord ar : mActivities.values()) {
+ Activity a = ar.activity;
+ if (a != null) {
+ Configuration thisConfig = applyConfigCompatMainThread(mCurDefaultDisplayDpi,
+ newConfig, ar.packageInfo.mCompatibilityInfo.getIfNeeded());
+ if (!ar.activity.mFinished && (allActivities || !ar.paused)) {
+ // If the activity is currently resumed, its configuration
+ // needs to change right now.
+ callbacks.add(a);
+ } else if (thisConfig != null) {
+ // Otherwise, we will tell it about the change
+ // the next time it is resumed or shown. Note that
+ // the activity manager may, before then, decide the
+ // activity needs to be destroyed to handle its new
+ // configuration.
+ if (DEBUG_CONFIGURATION) {
+ Slog.v(TAG, "Setting activity "
+ + ar.activityInfo.name + " newConfig=" + thisConfig);
+ }
+ ar.newConfig = thisConfig;
}
- ar.newConfig = thisConfig;
}
}
}
- }
- if (mServices.size() > 0) {
- for (Service service : mServices.values()) {
- callbacks.add(service);
+ if (mServices.size() > 0) {
+ for (Service service : mServices.values()) {
+ callbacks.add(service);
+ }
}
}
synchronized (mProviderMap) {
@@ -3680,10 +3686,6 @@ public final class ActivityThread {
}
}
}
- final int N = mAllApplications.size();
- for (int i=0; i<N; i++) {
- callbacks.add(mAllApplications.get(i));
- }
return callbacks;
}
@@ -3844,7 +3846,6 @@ public final class ActivityThread {
final void handleConfigurationChanged(Configuration config, CompatibilityInfo compat) {
- ArrayList<ComponentCallbacks2> callbacks = null;
int configDiff = 0;
synchronized (mPackages) {
@@ -3875,9 +3876,10 @@ public final class ActivityThread {
configDiff = mConfiguration.diff(config);
mConfiguration.updateFrom(config);
config = applyCompatConfiguration(mCurDefaultDisplayDpi);
- callbacks = collectComponentCallbacksLocked(false, config);
}
-
+
+ ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(false, config);
+
// Cleanup hardware accelerated stuff
WindowManagerGlobal.getInstance().trimLocalMemory();
@@ -3990,11 +3992,7 @@ public final class ActivityThread {
}
final void handleLowMemory() {
- ArrayList<ComponentCallbacks2> callbacks;
-
- synchronized (mPackages) {
- callbacks = collectComponentCallbacksLocked(true, null);
- }
+ ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
final int N = callbacks.size();
for (int i=0; i<N; i++) {
@@ -4022,10 +4020,7 @@ public final class ActivityThread {
final WindowManagerGlobal windowManager = WindowManagerGlobal.getInstance();
windowManager.startTrimMemory(level);
- ArrayList<ComponentCallbacks2> callbacks;
- synchronized (mPackages) {
- callbacks = collectComponentCallbacksLocked(true, null);
- }
+ ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null);
final int N = callbacks.size();
for (int i = 0; i < N; i++) {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index d6ebc9b..ed17d0e 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -327,6 +327,7 @@ public interface IActivityManager extends IInterface {
public int stopUser(int userid, IStopUserCallback callback) throws RemoteException;
public UserInfo getCurrentUser() throws RemoteException;
public boolean isUserRunning(int userid) throws RemoteException;
+ public int[] getRunningUserIds() throws RemoteException;
public boolean removeSubTask(int taskId, int subTaskIndex) throws RemoteException;
@@ -611,4 +612,5 @@ public interface IActivityManager extends IInterface {
int STOP_USER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+153;
int REGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+154;
int UNREGISTER_USER_SWITCH_OBSERVER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+155;
+ int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
}
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index cd1e882..4ab8272 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1219,7 +1219,7 @@ public abstract class ContentResolver {
public final void registerContentObserver(Uri uri, boolean notifyForDescendents,
ContentObserver observer)
{
- registerContentObserver(uri, notifyForDescendents, observer, UserHandle.myUserId());
+ registerContentObserver(uri, notifyForDescendents, observer, UserHandle.getCallingUserId());
}
/** @hide - designated user version */
@@ -1283,7 +1283,7 @@ public abstract class ContentResolver {
* @see #requestSync(android.accounts.Account, String, android.os.Bundle)
*/
public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
- notifyChange(uri, observer, syncToNetwork, UserHandle.myUserId());
+ notifyChange(uri, observer, syncToNetwork, UserHandle.getCallingUserId());
}
/**
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 5986dcd..0f6488a 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -154,15 +154,11 @@ public final class ContentService extends IContentService.Stub {
throw new IllegalArgumentException("You must pass a valid uri and observer");
}
- // STOPSHIP: disable the multi-user permission checks until a solid fix for the
- // content provider / observer case is in place.
- /*
final int callingUser = UserHandle.getCallingUserId();
if (callingUser != userHandle) {
mContext.enforceCallingOrSelfPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL,
"no permission to observe other users' provider view");
}
- */
if (userHandle < 0) {
if (userHandle == UserHandle.USER_CURRENT) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 383739b..b9518b8 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2797,6 +2797,15 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED";
/**
+ * @hide
+ * Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
+ * intents to indicate that at this point the package has been removed for
+ * all users on the device.
+ */
+ public static final String EXTRA_REMOVED_FOR_ALL_USERS
+ = "android.intent.extra.REMOVED_FOR_ALL_USERS";
+
+ /**
* Used as a boolean extra field in {@link android.content.Intent#ACTION_PACKAGE_REMOVED}
* intents to indicate that this is a replacement of the package, so this
* broadcast will immediately be followed by an add broadcast for a
diff --git a/core/java/com/android/internal/content/PackageMonitor.java b/core/java/com/android/internal/content/PackageMonitor.java
index 3477a90..20ecace 100644
--- a/core/java/com/android/internal/content/PackageMonitor.java
+++ b/core/java/com/android/internal/content/PackageMonitor.java
@@ -24,6 +24,7 @@ import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
+import android.os.UserHandle;
import java.util.HashSet;
@@ -62,11 +63,17 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
String[] mAppearingPackages;
String[] mModifiedPackages;
int mChangeType;
+ int mChangeUserId = UserHandle.USER_NULL;
boolean mSomePackagesChanged;
-
+
String[] mTempArray = new String[1];
-
+
public void register(Context context, Looper thread, boolean externalStorage) {
+ register(context, thread, null, externalStorage);
+ }
+
+ public void register(Context context, Looper thread, UserHandle user,
+ boolean externalStorage) {
if (mRegisteredContext != null) {
throw new IllegalStateException("Already registered");
}
@@ -84,10 +91,19 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
} else {
mRegisteredHandler = new Handler(thread);
}
- context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
- context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
- if (externalStorage) {
- context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
+ if (user != null) {
+ context.registerReceiverAsUser(this, user, sPackageFilt, null, mRegisteredHandler);
+ context.registerReceiverAsUser(this, user, sNonDataFilt, null, mRegisteredHandler);
+ if (externalStorage) {
+ context.registerReceiverAsUser(this, user, sExternalFilt, null,
+ mRegisteredHandler);
+ }
+ } else {
+ context.registerReceiver(this, sPackageFilt, null, mRegisteredHandler);
+ context.registerReceiver(this, sNonDataFilt, null, mRegisteredHandler);
+ if (externalStorage) {
+ context.registerReceiver(this, sExternalFilt, null, mRegisteredHandler);
+ }
}
}
@@ -125,6 +141,13 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
public void onPackageRemoved(String packageName, int uid) {
}
+ /**
+ * Called when a package is really removed (and not replaced) for
+ * all users on the device.
+ */
+ public void onPackageRemovedAllUsers(String packageName, int uid) {
+ }
+
public void onPackageUpdateStarted(String packageName, int uid) {
}
@@ -220,7 +243,11 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
public void onFinishPackageChanges() {
}
-
+
+ public int getChangingUserId() {
+ return mChangeUserId;
+ }
+
String getPackageName(Intent intent) {
Uri uri = intent.getData();
String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
@@ -229,6 +256,12 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
+ mChangeUserId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+ UserHandle.USER_NULL);
+ if (mChangeUserId == UserHandle.USER_NULL) {
+ throw new IllegalArgumentException(
+ "Intent broadcast does not contain user handle: " + intent);
+ }
onBeginPackageChanges();
mDisappearingPackages = mAppearingPackages = null;
@@ -281,6 +314,9 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
// it when it is re-added.
mSomePackagesChanged = true;
onPackageRemoved(pkg, uid);
+ if (intent.getBooleanExtra(Intent.EXTRA_REMOVED_FOR_ALL_USERS, false)) {
+ onPackageRemovedAllUsers(pkg, uid);
+ }
}
onPackageDisappeared(pkg, mChangeType);
}
@@ -344,5 +380,6 @@ public abstract class PackageMonitor extends android.content.BroadcastReceiver {
}
onFinishPackageChanges();
+ mChangeUserId = UserHandle.USER_NULL;
}
}
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
index 09dcac5..a288058 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
@@ -25,4 +25,9 @@ LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := DownloadManagerTestApp
+ifneq ($(TARGET_BUILD_VARIANT),user)
+# Need to run as system app to get access to Settings. This test won't work for user builds.
+LOCAL_CERTIFICATE := platform
+endif
+
include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/AndroidManifest.xml b/core/tests/hosttests/test-apps/DownloadManagerTestApp/AndroidManifest.xml
index 3f2be3c..c8d66ce 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/AndroidManifest.xml
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/AndroidManifest.xml
@@ -14,7 +14,8 @@
limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.frameworks.downloadmanagertests">
+ package="com.android.frameworks.downloadmanagertests"
+ android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
@@ -22,6 +23,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<application android:label="DownloadManagerTestApp">
<uses-library android:name="android.test.runner" />
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java
index 8e935f8..f493e9a 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/src/com/android/frameworks/downloadmanagertests/DownloadManagerBaseTest.java
@@ -262,7 +262,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
int state = enable ? 1 : 0;
// Change the system setting
- Settings.System.putInt(mContext.getContentResolver(), Settings.System.AIRPLANE_MODE_ON,
+ Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON,
state);
String timeoutMessage = "Timed out waiting for airplane mode to be " +
@@ -271,7 +271,7 @@ public class DownloadManagerBaseTest extends InstrumentationTestCase {
// wait for airplane mode to change state
int currentWaitTime = 0;
while (Settings.System.getInt(mContext.getContentResolver(),
- Settings.System.AIRPLANE_MODE_ON, -1) != state) {
+ Settings.Global.AIRPLANE_MODE_ON, -1) != state) {
timeoutWait(currentWaitTime, DEFAULT_WAIT_POLL_TIME, DEFAULT_MAX_WAIT_TIME,
timeoutMessage);
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 9839c16..f0b8812 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -23,7 +23,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.backup.BackupManager;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
@@ -33,20 +32,17 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
-import android.content.pm.UserInfo;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteQueryBuilder;
-import android.database.sqlite.SQLiteStatement;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileObserver;
import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
@@ -656,53 +652,59 @@ public class SettingsProvider extends ContentProvider {
}
}
- // Note: we assume that get/put operations for moved-to-global names have already
- // been directed to the new location on the caller side (otherwise we'd fix them
- // up here).
-
- DatabaseHelper dbHelper;
- SettingsCache cache;
-
- // Get methods
- if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
- dbHelper = getOrEstablishDatabase(callingUser);
- cache = sSystemCaches.get(callingUser);
- return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
- }
- if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
- dbHelper = getOrEstablishDatabase(callingUser);
- cache = sSecureCaches.get(callingUser);
- return lookupValue(dbHelper, TABLE_SECURE, cache, request);
- }
- if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
- // fast path: owner db & cache are immutable after onCreate() so we need not
- // guard on the attempt to look them up
- return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
- sGlobalCache, request);
- }
+ // Okay, permission checks have cleared. Reset to our own identity so we can
+ // manipulate all users' data with impunity.
+ long oldId = Binder.clearCallingIdentity();
+ try {
+ // Note: we assume that get/put operations for moved-to-global names have already
+ // been directed to the new location on the caller side (otherwise we'd fix them
+ // up here).
+ DatabaseHelper dbHelper;
+ SettingsCache cache;
+
+ // Get methods
+ if (Settings.CALL_METHOD_GET_SYSTEM.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call(system:" + request + ") for " + callingUser);
+ dbHelper = getOrEstablishDatabase(callingUser);
+ cache = sSystemCaches.get(callingUser);
+ return lookupValue(dbHelper, TABLE_SYSTEM, cache, request);
+ }
+ if (Settings.CALL_METHOD_GET_SECURE.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call(secure:" + request + ") for " + callingUser);
+ dbHelper = getOrEstablishDatabase(callingUser);
+ cache = sSecureCaches.get(callingUser);
+ return lookupValue(dbHelper, TABLE_SECURE, cache, request);
+ }
+ if (Settings.CALL_METHOD_GET_GLOBAL.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call(global:" + request + ") for " + callingUser);
+ // fast path: owner db & cache are immutable after onCreate() so we need not
+ // guard on the attempt to look them up
+ return lookupValue(getOrEstablishDatabase(UserHandle.USER_OWNER), TABLE_GLOBAL,
+ sGlobalCache, request);
+ }
- // Put methods - new value is in the args bundle under the key named by
- // the Settings.NameValueTable.VALUE static.
- final String newValue = (args == null)
- ? null : args.getString(Settings.NameValueTable.VALUE);
-
- final ContentValues values = new ContentValues();
- values.put(Settings.NameValueTable.NAME, request);
- values.put(Settings.NameValueTable.VALUE, newValue);
- if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser);
- insertForUser(Settings.System.CONTENT_URI, values, callingUser);
- } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser);
- insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
- } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
- if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser);
- insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
- } else {
- Slog.w(TAG, "call() with invalid method: " + method);
+ // Put methods - new value is in the args bundle under the key named by
+ // the Settings.NameValueTable.VALUE static.
+ final String newValue = (args == null)
+ ? null : args.getString(Settings.NameValueTable.VALUE);
+
+ final ContentValues values = new ContentValues();
+ values.put(Settings.NameValueTable.NAME, request);
+ values.put(Settings.NameValueTable.VALUE, newValue);
+ if (Settings.CALL_METHOD_PUT_SYSTEM.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call_put(system:" + request + "=" + newValue + ") for " + callingUser);
+ insertForUser(Settings.System.CONTENT_URI, values, callingUser);
+ } else if (Settings.CALL_METHOD_PUT_SECURE.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call_put(secure:" + request + "=" + newValue + ") for " + callingUser);
+ insertForUser(Settings.Secure.CONTENT_URI, values, callingUser);
+ } else if (Settings.CALL_METHOD_PUT_GLOBAL.equals(method)) {
+ if (LOCAL_LOGV) Slog.v(TAG, "call_put(global:" + request + "=" + newValue + ") for " + callingUser);
+ insertForUser(Settings.Global.CONTENT_URI, values, callingUser);
+ } else {
+ Slog.w(TAG, "call() with invalid method: " + method);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(oldId);
}
return null;
@@ -758,7 +760,7 @@ public class SettingsProvider extends ContentProvider {
return queryForUser(url, select, where, whereArgs, sort, UserHandle.getCallingUserId());
}
- public Cursor queryForUser(Uri url, String[] select, String where, String[] whereArgs,
+ private Cursor queryForUser(Uri url, String[] select, String where, String[] whereArgs,
String sort, int forUser) {
if (LOCAL_LOGV) Slog.v(TAG, "query(" + url + ") for user " + forUser);
SqlArguments args = new SqlArguments(url, where, whereArgs);
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index b027c1f..4225913 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -293,17 +293,18 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onPackageUpdateFinished(String packageName, int uid) {
synchronized (mLock) {
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
if (wallpaper.wallpaperComponent != null
&& wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
wallpaper.wallpaperUpdating = false;
ComponentName comp = wallpaper.wallpaperComponent;
clearWallpaperComponentLocked(wallpaper);
- // Do this only for the current user's wallpaper
- if (wallpaper.userId == mCurrentUserId
- && !bindWallpaperComponentLocked(comp, false, false,
- wallpaper, null)) {
+ if (!bindWallpaperComponentLocked(comp, false, false,
+ wallpaper, null)) {
Slog.w(TAG, "Wallpaper no longer available; reverting to default");
clearWallpaperLocked(false, wallpaper.userId, null);
}
@@ -315,11 +316,14 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onPackageModified(String packageName) {
synchronized (mLock) {
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
if (wallpaper.wallpaperComponent == null
|| !wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
- continue;
+ return;
}
doPackagesChangedLocked(true, wallpaper);
}
@@ -329,8 +333,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onPackageUpdateStarted(String packageName, int uid) {
synchronized (mLock) {
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
if (wallpaper.wallpaperComponent != null
&& wallpaper.wallpaperComponent.getPackageName().equals(packageName)) {
wallpaper.wallpaperUpdating = true;
@@ -343,8 +350,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
synchronized (mLock) {
boolean changed = false;
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return false;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
boolean res = doPackagesChangedLocked(doit, wallpaper);
changed |= res;
}
@@ -355,8 +365,11 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
@Override
public void onSomePackagesChanged() {
synchronized (mLock) {
- for (int i = 0; i < mWallpaperMap.size(); i++) {
- WallpaperData wallpaper = mWallpaperMap.valueAt(i);
+ if (mCurrentUserId != getChangingUserId()) {
+ return;
+ }
+ WallpaperData wallpaper = mWallpaperMap.get(mCurrentUserId);
+ if (wallpaper != null) {
doPackagesChangedLocked(true, wallpaper);
}
}
@@ -416,7 +429,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub {
ServiceManager.getService(Context.WINDOW_SERVICE));
mIPackageManager = AppGlobals.getPackageManager();
mMonitor = new MyPackageMonitor();
- mMonitor.register(context, null, true);
+ mMonitor.register(context, null, UserHandle.ALL, true);
getWallpaperDir(UserHandle.USER_OWNER).mkdirs();
loadSettingsLocked(UserHandle.USER_OWNER);
}
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 1f5fa4d..cd3aeff 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -147,6 +147,7 @@ import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
@@ -448,6 +449,11 @@ public final class ActivityManagerService extends ActivityManagerNative
final ArrayList<Integer> mUserLru = new ArrayList<Integer>();
/**
+ * Constant array of the users that are currently started.
+ */
+ int[] mStartedUserArray = new int[] { 0 };
+
+ /**
* Registered observers of the user switching mechanics.
*/
final RemoteCallbackList<IUserSwitchObserver> mUserSwitchObservers
@@ -832,7 +838,8 @@ public final class ActivityManagerService extends ActivityManagerNative
static ActivityManagerService mSelf;
static ActivityThread mSystemThread;
- private int mCurrentUserId;
+ private int mCurrentUserId = 0;
+ private int[] mCurrentUserArray = new int[] { 0 };
private UserManagerService mUserManager;
private final class AppDeathRecipient implements IBinder.DeathRecipient {
@@ -1568,6 +1575,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// User 0 is the first and only user that runs at boot.
mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
mUserLru.add(Integer.valueOf(0));
+ updateStartedUserArrayLocked();
GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
@@ -3750,6 +3758,7 @@ public final class ActivityManagerService extends ActivityManagerNative
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}
intent.putExtra(Intent.EXTRA_UID, uid);
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid));
broadcastIntentLocked(null, null, intent,
null, null, 0, null, null, null,
false, false,
@@ -9311,6 +9320,9 @@ public final class ActivityManagerService extends ActivityManagerNative
pw.print(mUserLru.get(i));
}
pw.println("]");
+ if (dumpAll) {
+ pw.print(" mStartedUserArray: "); pw.println(Arrays.toString(mStartedUserArray));
+ }
pw.println(" mHomeProcess: " + mHomeProcess);
pw.println(" mPreviousProcess: " + mPreviousProcess);
if (dumpAll) {
@@ -11498,7 +11510,7 @@ public final class ActivityManagerService extends ActivityManagerNative
userId = handleIncomingUserLocked(callingPid, callingUid, userId,
true, false, "broadcast", callerPackage);
- // Make sure that the user who is receiving this broadcast is started
+ // Make sure that the user who is receiving this broadcast is started.
// If not, we will just skip it.
if (userId != UserHandle.USER_ALL && mStartedUsers.get(userId) == null) {
if (callingUid != Process.SYSTEM_UID || (intent.getFlags()
@@ -11693,13 +11705,10 @@ public final class ActivityManagerService extends ActivityManagerNative
int[] users;
if (userId == UserHandle.USER_ALL) {
// Caller wants broadcast to go to all started users.
- users = new int[mStartedUsers.size()];
- for (int i=0; i<mStartedUsers.size(); i++) {
- users[i] = mStartedUsers.keyAt(i);
- }
+ users = mStartedUserArray;
} else {
// Caller wants broadcast to go to one specific user.
- users = new int[] {userId};
+ users = mCurrentUserArray;
}
// Figure out who all will receive this broadcast.
@@ -13975,9 +13984,11 @@ public final class ActivityManagerService extends ActivityManagerNative
// we need to start it now.
if (mStartedUsers.get(userId) == null) {
mStartedUsers.put(userId, new UserStartedState(new UserHandle(userId), false));
+ updateStartedUserArrayLocked();
}
mCurrentUserId = userId;
+ mCurrentUserArray = new int[] { userId };
final Integer userIdInt = Integer.valueOf(userId);
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
@@ -14256,6 +14267,7 @@ public final class ActivityManagerService extends ActivityManagerNative
// User can no longer run.
mStartedUsers.remove(userId);
mUserLru.remove(Integer.valueOf(userId));
+ updateStartedUserArrayLocked();
// Clean up all state and processes associated with the user.
// Kill all the processes for the user.
@@ -14312,6 +14324,29 @@ public final class ActivityManagerService extends ActivityManagerNative
}
@Override
+ public int[] getRunningUserIds() {
+ if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS)
+ != PackageManager.PERMISSION_GRANTED) {
+ String msg = "Permission Denial: isUserRunning() from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid()
+ + " requires " + android.Manifest.permission.INTERACT_ACROSS_USERS;
+ Slog.w(TAG, msg);
+ throw new SecurityException(msg);
+ }
+ synchronized (this) {
+ return mStartedUserArray;
+ }
+ }
+
+ private void updateStartedUserArrayLocked() {
+ mStartedUserArray = new int[mStartedUsers.size()];
+ for (int i=0; i<mStartedUsers.size(); i++) {
+ mStartedUserArray[i] = mStartedUsers.keyAt(i);
+ }
+ }
+
+ @Override
public void registerUserSwitchObserver(IUserSwitchObserver observer) {
if (checkCallingPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
diff --git a/services/java/com/android/server/am/UsageStatsService.java b/services/java/com/android/server/am/UsageStatsService.java
index 7059674..6dae4aa 100644
--- a/services/java/com/android/server/am/UsageStatsService.java
+++ b/services/java/com/android/server/am/UsageStatsService.java
@@ -650,7 +650,7 @@ public final class UsageStatsService extends IUsageStats.Stub {
public void monitorPackages() {
mPackageMonitor = new PackageMonitor() {
@Override
- public void onPackageRemoved(String packageName, int uid) {
+ public void onPackageRemovedAllUsers(String packageName, int uid) {
synchronized (mStatsLock) {
mLastResumeTimes.remove(packageName);
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index f0cc083..f3de8a4 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -719,7 +719,7 @@ public class PackageManagerService extends IPackageManager.Stub {
PackageInstalledInfo res = data.res;
if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
- res.removedInfo.sendBroadcast(false, true);
+ res.removedInfo.sendBroadcast(false, true, false);
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, res.uid);
// Determine the set of users who are adding this
@@ -5386,7 +5386,7 @@ public class PackageManagerService extends IPackageManager.Stub {
if (am != null) {
try {
if (userIds == null) {
- userIds = sUserManager.getUserIds();
+ userIds = am.getRunningUserIds();
}
for (int id : userIds) {
final Intent intent = new Intent(action,
@@ -5403,6 +5403,7 @@ public class PackageManagerService extends IPackageManager.Stub {
uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
intent.putExtra(Intent.EXTRA_UID, uid);
}
+ intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (DEBUG_BROADCASTS) {
RuntimeException here = new RuntimeException("here");
@@ -8051,18 +8052,23 @@ public class PackageManagerService extends IPackageManager.Stub {
} catch (RemoteException e) {
}
+ boolean removedForAllUsers = false;
+ boolean systemUpdate = false;
synchronized (mInstallLock) {
res = deletePackageLI(packageName,
(flags & PackageManager.DELETE_ALL_USERS) != 0
? UserHandle.ALL : new UserHandle(UserHandle.getUserId(uid)),
true, flags | REMOVE_CHATTY, info, true);
+ systemUpdate = info.isRemovedPackageSystemUpdate;
+ if (res && !systemUpdate && mPackages.get(packageName) == null) {
+ removedForAllUsers = true;
+ }
}
if (res) {
- boolean systemUpdate = info.isRemovedPackageSystemUpdate;
- info.sendBroadcast(true, systemUpdate);
+ info.sendBroadcast(true, systemUpdate, removedForAllUsers);
- // If the removed package was a system update, the old system packaged
+ // If the removed package was a system update, the old system package
// was re-enabled; we need to broadcast this information
if (systemUpdate) {
Bundle extras = new Bundle(1);
@@ -8100,13 +8106,14 @@ public class PackageManagerService extends IPackageManager.Stub {
// Clean up resources deleted packages.
InstallArgs args = null;
- void sendBroadcast(boolean fullRemove, boolean replacing) {
+ void sendBroadcast(boolean fullRemove, boolean replacing, boolean removedForAllUsers) {
Bundle extras = new Bundle(1);
extras.putInt(Intent.EXTRA_UID, removedAppId >= 0 ? removedAppId : uid);
extras.putBoolean(Intent.EXTRA_DATA_REMOVED, fullRemove);
if (replacing) {
extras.putBoolean(Intent.EXTRA_REPLACING, true);
}
+ extras.putBoolean(Intent.EXTRA_REMOVED_FOR_ALL_USERS, removedForAllUsers);
if (removedPackage != null) {
sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage,
extras, null, null, removedUsers);