diff options
Diffstat (limited to 'services')
19 files changed, 945 insertions, 722 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index a85b605..eb024e9 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -170,6 +170,15 @@ class AppWidgetService extends IAppWidgetService.Stub sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); + + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserRemoved(intent.getIntExtra(Intent.EXTRA_USERID, -1)); + } + }, userFilter); } @Override @@ -192,19 +201,6 @@ class AppWidgetService extends IAppWidgetService.Stub getImplForUser().deleteAllHosts(); } - void cancelBroadcasts(Provider p) { - if (p.broadcast != null) { - mAlarmManager.cancel(p.broadcast); - long token = Binder.clearCallingIdentity(); - try { - p.broadcast.cancel(); - } finally { - Binder.restoreCallingIdentity(token); - } - p.broadcast = null; - } - } - @Override public void bindAppWidgetId(int appWidgetId, ComponentName provider) throws RemoteException { getImplForUser().bindAppWidgetId(appWidgetId, provider); @@ -222,8 +218,15 @@ class AppWidgetService extends IAppWidgetService.Stub return getImplForUser().startListening(host, packageName, hostId, updatedViews); } - // TODO: Call this from PackageManagerService when a user is removed - public void removeUser(int userId) { + public void onUserRemoved(int userId) { + AppWidgetServiceImpl impl = mAppWidgetServices.get(userId); + if (userId < 1) return; + + if (impl == null) { + AppWidgetServiceImpl.getSettingsFile(userId).delete(); + } else { + impl.onUserRemoved(); + } } private AppWidgetServiceImpl getImplForUser() { diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index 182a884..b24823e 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -1484,9 +1484,13 @@ class AppWidgetServiceImpl { } } + static File getSettingsFile(int userId) { + return new File("/data/system/users/" + userId + "/" + SETTINGS_FILENAME); + } + AtomicFile savedStateFile() { File dir = new File("/data/system/users/" + mUserId); - File settingsFile = new File(dir, SETTINGS_FILENAME); + File settingsFile = getSettingsFile(mUserId); if (!dir.exists()) { dir.mkdirs(); if (mUserId == 0) { @@ -1500,6 +1504,16 @@ class AppWidgetServiceImpl { return new AtomicFile(settingsFile); } + void onUserRemoved() { + // prune the ones we don't want to keep + int N = mInstalledProviders.size(); + for (int i = N - 1; i >= 0; i--) { + Provider p = mInstalledProviders.get(i); + cancelBroadcasts(p); + } + getSettingsFile(mUserId).delete(); + } + void addProvidersForPackageLocked(String pkgName) { Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.setPackage(pkgName); diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index bd8ae17..a0d5beb 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -201,9 +201,9 @@ class BackupManagerService extends IBackupManager.Stub { BackupHandler mBackupHandler; PendingIntent mRunBackupIntent, mRunInitIntent; BroadcastReceiver mRunBackupReceiver, mRunInitReceiver; - // map UIDs to the set of backup client services within that UID's app set - final SparseArray<HashSet<ApplicationInfo>> mBackupParticipants - = new SparseArray<HashSet<ApplicationInfo>>(); + // map UIDs to the set of participating packages under that UID + final SparseArray<HashSet<String>> mBackupParticipants + = new SparseArray<HashSet<String>>(); // set of backup services that have pending changes class BackupRequest { public String packageName; @@ -960,7 +960,6 @@ class BackupManagerService extends IBackupManager.Stub { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_PACKAGE_ADDED); filter.addAction(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_REPLACED); filter.addDataScheme("package"); mContext.registerReceiver(mBroadcastReceiver, filter); // Register for events related to sdcard installation. @@ -1239,12 +1238,13 @@ class BackupManagerService extends IBackupManager.Stub { // Enqueue a new backup of every participant synchronized (mBackupParticipants) { - int N = mBackupParticipants.size(); + final int N = mBackupParticipants.size(); for (int i=0; i<N; i++) { - int uid = mBackupParticipants.keyAt(i); - HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i); - for (ApplicationInfo app: participants) { - dataChangedImpl(app.packageName); + HashSet<String> participants = mBackupParticipants.valueAt(i); + if (participants != null) { + for (String packageName : participants) { + dataChangedImpl(packageName); + } } } } @@ -1302,8 +1302,7 @@ class BackupManagerService extends IBackupManager.Stub { Bundle extras = intent.getExtras(); String pkgList[] = null; if (Intent.ACTION_PACKAGE_ADDED.equals(action) || - Intent.ACTION_PACKAGE_REMOVED.equals(action) || - Intent.ACTION_PACKAGE_REPLACED.equals(action)) { + Intent.ACTION_PACKAGE_REMOVED.equals(action)) { Uri uri = intent.getData(); if (uri == null) { return; @@ -1312,14 +1311,8 @@ class BackupManagerService extends IBackupManager.Stub { if (pkgName != null) { pkgList = new String[] { pkgName }; } - if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) { - // use the existing "add with replacement" logic - if (MORE_DEBUG) Slog.d(TAG, "PACKAGE_REPLACED, updating package " + pkgName); - added = replacing = true; - } else { - added = Intent.ACTION_PACKAGE_ADDED.equals(action); - replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); - } + added = Intent.ACTION_PACKAGE_ADDED.equals(action); + replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { added = true; pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); @@ -1331,20 +1324,23 @@ class BackupManagerService extends IBackupManager.Stub { if (pkgList == null || pkgList.length == 0) { return; } + + final int uid = extras.getInt(Intent.EXTRA_UID); if (added) { synchronized (mBackupParticipants) { if (replacing) { - updatePackageParticipantsLocked(pkgList); - } else { - addPackageParticipantsLocked(pkgList); + // This is the package-replaced case; we just remove the entry + // under the old uid and fall through to re-add. + removePackageParticipantsLocked(pkgList, uid); } + addPackageParticipantsLocked(pkgList); } } else { if (replacing) { // The package is being updated. We'll receive a PACKAGE_ADDED shortly. } else { synchronized (mBackupParticipants) { - removePackageParticipantsLocked(pkgList); + removePackageParticipantsLocked(pkgList, uid); } } } @@ -1391,12 +1387,12 @@ class BackupManagerService extends IBackupManager.Stub { for (PackageInfo pkg : targetPkgs) { if (packageName == null || pkg.packageName.equals(packageName)) { int uid = pkg.applicationInfo.uid; - HashSet<ApplicationInfo> set = mBackupParticipants.get(uid); + HashSet<String> set = mBackupParticipants.get(uid); if (set == null) { - set = new HashSet<ApplicationInfo>(); + set = new HashSet<String>(); mBackupParticipants.put(uid, set); } - set.add(pkg.applicationInfo); + set.add(pkg.packageName); if (MORE_DEBUG) Slog.v(TAG, "Agent found; added"); // If we've never seen this app before, schedule a backup for it @@ -1410,63 +1406,36 @@ class BackupManagerService extends IBackupManager.Stub { } // Remove the given packages' entries from our known active set. - void removePackageParticipantsLocked(String[] packageNames) { + void removePackageParticipantsLocked(String[] packageNames, int oldUid) { if (packageNames == null) { Slog.w(TAG, "removePackageParticipants with null list"); return; } - if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: #" + packageNames.length); - List<PackageInfo> knownPackages = allAgentPackages(); + if (DEBUG) Slog.v(TAG, "removePackageParticipantsLocked: uid=" + oldUid + + " #" + packageNames.length); for (String pkg : packageNames) { - removePackageParticipantsLockedInner(pkg, knownPackages); + // Known previous UID, so we know which package set to check + HashSet<String> set = mBackupParticipants.get(oldUid); + if (set != null && set.contains(pkg)) { + removePackageFromSetLocked(set, pkg); + if (set.isEmpty()) { + if (MORE_DEBUG) Slog.v(TAG, " last one of this uid; purging set"); + mBackupParticipants.remove(oldUid); + } + } } } - private void removePackageParticipantsLockedInner(String packageName, - List<PackageInfo> allPackages) { - if (MORE_DEBUG) { - Slog.v(TAG, "removePackageParticipantsLockedInner (" + packageName - + ") removing from " + allPackages.size() + " entries"); - for (PackageInfo p : allPackages) { - Slog.v(TAG, " - " + p.packageName); - } - } - for (PackageInfo pkg : allPackages) { - if (packageName == null || pkg.packageName.equals(packageName)) { - /* - int uid = -1; - try { - PackageInfo info = mPackageManager.getPackageInfo(packageName, 0); - uid = info.applicationInfo.uid; - } catch (NameNotFoundException e) { - // we don't know this package name, so just skip it for now - continue; - } - */ - final int uid = pkg.applicationInfo.uid; - if (MORE_DEBUG) Slog.i(TAG, " found pkg " + packageName + " uid=" + uid); - - HashSet<ApplicationInfo> set = mBackupParticipants.get(uid); - if (set != null) { - // Find the existing entry with the same package name, and remove it. - // We can't just remove(app) because the instances are different. - for (ApplicationInfo entry: set) { - if (MORE_DEBUG) Slog.i(TAG, " checking against " + entry.packageName); - if (entry.packageName.equals(pkg)) { - if (MORE_DEBUG) Slog.v(TAG, " removing participant " + pkg); - set.remove(entry); - removeEverBackedUp(pkg.packageName); - break; - } - } - if (set.size() == 0) { - mBackupParticipants.delete(uid); - } - } else { - if (MORE_DEBUG) Slog.i(TAG, " ... not found in uid mapping"); - } - } + private void removePackageFromSetLocked(final HashSet<String> set, + final String packageName) { + if (set.contains(packageName)) { + // Found it. Remove this one package from the bookkeeping, and + // if it's the last participating app under this uid we drop the + // (now-empty) set as well. + if (MORE_DEBUG) Slog.v(TAG, " removing participant " + packageName); + removeEverBackedUp(packageName); + set.remove(packageName); } } @@ -1497,24 +1466,6 @@ class BackupManagerService extends IBackupManager.Stub { return packages; } - // Reset the given package's known backup participants. Unlike add/remove, the update - // action cannot be passed a null package name. - void updatePackageParticipantsLocked(String[] packageNames) { - if (packageNames == null) { - Slog.e(TAG, "updatePackageParticipants called with null package list"); - return; - } - if (DEBUG) Slog.v(TAG, "updatePackageParticipantsLocked: #" + packageNames.length); - - if (packageNames.length > 0) { - List<PackageInfo> allApps = allAgentPackages(); - for (String packageName : packageNames) { - removePackageParticipantsLockedInner(packageName, allApps); - addPackageParticipantsLockedInner(packageName, allApps); - } - } - } - // Called from the backup task: record that the given app has been successfully // backed up at least once void logBackupComplete(String packageName) { @@ -4772,11 +4723,11 @@ class BackupManagerService extends IBackupManager.Stub { } private void dataChangedImpl(String packageName) { - HashSet<ApplicationInfo> targets = dataChangedTargets(packageName); + HashSet<String> targets = dataChangedTargets(packageName); dataChangedImpl(packageName, targets); } - private void dataChangedImpl(String packageName, HashSet<ApplicationInfo> targets) { + private void dataChangedImpl(String packageName, HashSet<String> targets) { // Record that we need a backup pass for the caller. Since multiple callers // may share a uid, we need to note all candidates within that uid and schedule // a backup pass for each of them. @@ -4790,27 +4741,23 @@ class BackupManagerService extends IBackupManager.Stub { synchronized (mQueueLock) { // Note that this client has made data changes that need to be backed up - for (ApplicationInfo app : targets) { - // validate the caller-supplied package name against the known set of - // packages associated with this uid - if (app.packageName.equals(packageName)) { - // Add the caller to the set of pending backups. If there is - // one already there, then overwrite it, but no harm done. - BackupRequest req = new BackupRequest(packageName); - if (mPendingBackups.put(app.packageName, req) == null) { - if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName); - - // Journal this request in case of crash. The put() - // operation returned null when this package was not already - // in the set; we want to avoid touching the disk redundantly. - writeToJournalLocked(packageName); + if (targets.contains(packageName)) { + // Add the caller to the set of pending backups. If there is + // one already there, then overwrite it, but no harm done. + BackupRequest req = new BackupRequest(packageName); + if (mPendingBackups.put(packageName, req) == null) { + if (DEBUG) Slog.d(TAG, "Now staging backup of " + packageName); + + // Journal this request in case of crash. The put() + // operation returned null when this package was not already + // in the set; we want to avoid touching the disk redundantly. + writeToJournalLocked(packageName); - if (MORE_DEBUG) { - int numKeys = mPendingBackups.size(); - Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:"); - for (BackupRequest b : mPendingBackups.values()) { - Slog.d(TAG, " + " + b); - } + if (MORE_DEBUG) { + int numKeys = mPendingBackups.size(); + Slog.d(TAG, "Now awaiting backup for " + numKeys + " participants:"); + for (BackupRequest b : mPendingBackups.values()) { + Slog.d(TAG, " + " + b); } } } @@ -4819,7 +4766,7 @@ class BackupManagerService extends IBackupManager.Stub { } // Note: packageName is currently unused, but may be in the future - private HashSet<ApplicationInfo> dataChangedTargets(String packageName) { + private HashSet<String> dataChangedTargets(String packageName) { // If the caller does not hold the BACKUP permission, it can only request a // backup of its own data. if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(), @@ -4831,11 +4778,11 @@ class BackupManagerService extends IBackupManager.Stub { // a caller with full permission can ask to back up any participating app // !!! TODO: allow backup of ANY app? - HashSet<ApplicationInfo> targets = new HashSet<ApplicationInfo>(); + HashSet<String> targets = new HashSet<String>(); synchronized (mBackupParticipants) { int N = mBackupParticipants.size(); for (int i = 0; i < N; i++) { - HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i); + HashSet<String> s = mBackupParticipants.valueAt(i); if (s != null) { targets.addAll(s); } @@ -4862,7 +4809,7 @@ class BackupManagerService extends IBackupManager.Stub { // ----- IBackupManager binder interface ----- public void dataChanged(final String packageName) { - final HashSet<ApplicationInfo> targets = dataChangedTargets(packageName); + final HashSet<String> targets = dataChangedTargets(packageName); if (targets == null) { Slog.w(TAG, "dataChanged but no participant pkg='" + packageName + "'" + " uid=" + Binder.getCallingUid()); @@ -4889,7 +4836,7 @@ class BackupManagerService extends IBackupManager.Stub { // If the caller does not hold the BACKUP permission, it can only request a // wipe of its own backed-up data. - HashSet<ApplicationInfo> apps; + HashSet<String> apps; if ((mContext.checkPermission(android.Manifest.permission.BACKUP, Binder.getCallingPid(), Binder.getCallingUid())) == PackageManager.PERMISSION_DENIED) { apps = mBackupParticipants.get(Binder.getCallingUid()); @@ -4897,30 +4844,27 @@ class BackupManagerService extends IBackupManager.Stub { // a caller with full permission can ask to back up any participating app // !!! TODO: allow data-clear of ANY app? if (DEBUG) Slog.v(TAG, "Privileged caller, allowing clear of other apps"); - apps = new HashSet<ApplicationInfo>(); + apps = new HashSet<String>(); int N = mBackupParticipants.size(); for (int i = 0; i < N; i++) { - HashSet<ApplicationInfo> s = mBackupParticipants.valueAt(i); + HashSet<String> s = mBackupParticipants.valueAt(i); if (s != null) { apps.addAll(s); } } } - // now find the given package in the set of candidate apps - for (ApplicationInfo app : apps) { - if (app.packageName.equals(packageName)) { - if (DEBUG) Slog.v(TAG, "Found the app - running clear process"); - // found it; fire off the clear request - synchronized (mQueueLock) { - long oldId = Binder.clearCallingIdentity(); - mWakelock.acquire(); - Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR, - new ClearParams(getTransport(mCurrentTransport), info)); - mBackupHandler.sendMessage(msg); - Binder.restoreCallingIdentity(oldId); - } - break; + // Is the given app an available participant? + if (apps.contains(packageName)) { + if (DEBUG) Slog.v(TAG, "Found the app - running clear process"); + // found it; fire off the clear request + synchronized (mQueueLock) { + long oldId = Binder.clearCallingIdentity(); + mWakelock.acquire(); + Message msg = mBackupHandler.obtainMessage(MSG_RUN_CLEAR, + new ClearParams(getTransport(mCurrentTransport), info)); + mBackupHandler.sendMessage(msg); + Binder.restoreCallingIdentity(oldId); } } } @@ -5838,9 +5782,9 @@ class BackupManagerService extends IBackupManager.Stub { int uid = mBackupParticipants.keyAt(i); pw.print(" uid: "); pw.println(uid); - HashSet<ApplicationInfo> participants = mBackupParticipants.valueAt(i); - for (ApplicationInfo app: participants) { - pw.println(" " + app.packageName); + HashSet<String> participants = mBackupParticipants.valueAt(i); + for (String app: participants) { + pw.println(" " + app); } } diff --git a/services/java/com/android/server/ClipboardService.java b/services/java/com/android/server/ClipboardService.java index 062ab74..2e2a278 100644 --- a/services/java/com/android/server/ClipboardService.java +++ b/services/java/com/android/server/ClipboardService.java @@ -34,6 +34,7 @@ import android.os.Parcel; import android.os.Process; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.os.UserId; import android.util.Pair; import android.util.Slog; @@ -204,7 +205,7 @@ public class ClipboardService extends IClipboard.Stub { PackageInfo pi; try { pi = mPm.getPackageInfo(pkg, 0); - if (pi.applicationInfo.uid != uid) { + if (!UserId.isSameApp(pi.applicationInfo.uid, uid)) { throw new SecurityException("Calling uid " + uid + " does not own package " + pkg); } diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java index 8ee12bc..6d83f30 100644 --- a/services/java/com/android/server/WallpaperManagerService.java +++ b/services/java/com/android/server/WallpaperManagerService.java @@ -25,9 +25,11 @@ import android.app.PendingIntent; import android.app.WallpaperInfo; import android.app.backup.BackupManager; import android.app.backup.WallpaperBackupHelper; +import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -36,6 +38,7 @@ import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.os.Binder; import android.os.Bundle; +import android.os.Environment; import android.os.FileUtils; import android.os.IBinder; import android.os.RemoteException; @@ -401,41 +404,48 @@ class WallpaperManagerService extends IWallpaperManager.Stub { wallpaper.wallpaperObserver.stopWatching(); } } - + public void systemReady() { if (DEBUG) Slog.v(TAG, "systemReady"); WallpaperData wallpaper = mWallpaperMap.get(0); switchWallpaper(wallpaper); wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper); wallpaper.wallpaperObserver.startWatching(); - ActivityManagerService ams = (ActivityManagerService) ServiceManager - .getService(Context.ACTIVITY_SERVICE); - ams.addUserListener(new ActivityManagerService.UserListener() { - - @Override - public void onUserChanged(int userId) { - switchUser(userId); - } + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_SWITCHED); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { @Override - public void onUserAdded(int userId) { - } - - @Override - public void onUserRemoved(int userId) { - } - - @Override - public void onUserLoggedOut(int userId) { + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (Intent.ACTION_USER_SWITCHED.equals(action)) { + switchUser(intent.getIntExtra(Intent.EXTRA_USERID, 0)); + } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + removeUser(intent.getIntExtra(Intent.EXTRA_USERID, 0)); + } } - - }); + }, userFilter); } String getName() { return mWallpaperMap.get(0).name; } + void removeUser(int userId) { + synchronized (mLock) { + WallpaperData wallpaper = mWallpaperMap.get(userId); + if (wallpaper != null) { + wallpaper.wallpaperObserver.stopWatching(); + mWallpaperMap.remove(userId); + } + File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER); + wallpaperFile.delete(); + File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO); + wallpaperInfoFile.delete(); + } + } + void switchUser(int userId) { synchronized (mLock) { mCurrentUserId = userId; @@ -861,7 +871,7 @@ class WallpaperManagerService extends IWallpaperManager.Stub { } private static JournaledFile makeJournaledFile(int userId) { - final String base = "/data/system/users/" + userId + "/" + WALLPAPER_INFO; + final String base = getWallpaperDir(userId) + "/" + WALLPAPER_INFO; return new JournaledFile(new File(base), new File(base + ".tmp")); } diff --git a/services/java/com/android/server/WiredAccessoryObserver.java b/services/java/com/android/server/WiredAccessoryObserver.java index a7a46dd..9b4eddc 100644 --- a/services/java/com/android/server/WiredAccessoryObserver.java +++ b/services/java/com/android/server/WiredAccessoryObserver.java @@ -66,7 +66,7 @@ class WiredAccessoryObserver extends UEventObserver { public String getDevName() { return mDevName; } public String getDevPath() { - return String.format("DEVPATH=/devices/virtual/switch/%s", mDevName); + return String.format("/devices/virtual/switch/%s", mDevName); } public String getSwitchStatePath() { @@ -158,7 +158,7 @@ class WiredAccessoryObserver extends UEventObserver { init(); // set initial status for (int i = 0; i < uEventInfo.size(); ++i) { UEventInfo uei = uEventInfo.get(i); - startObserving(uei.getDevPath()); + startObserving("DEVPATH="+uei.getDevPath()); } } } @@ -168,29 +168,20 @@ class WiredAccessoryObserver extends UEventObserver { if (LOG) Slog.v(TAG, "Headset UEVENT: " + event.toString()); try { + String devPath = event.get("DEVPATH"); String name = event.get("SWITCH_NAME"); int state = Integer.parseInt(event.get("SWITCH_STATE")); - updateState(name, state); + updateState(devPath, name, state); } catch (NumberFormatException e) { Slog.e(TAG, "Could not parse switch state from event " + event); } } - private synchronized final void updateState(String name, int state) + private synchronized final void updateState(String devPath, String name, int state) { - // FIXME: When ueventd informs of a change in state for a switch, it does not have to be - // the case that the name reported by /sys/class/switch/<device>/name is the same as - // <device>. For normal users of the linux switch class driver, it will be. But it is - // technically possible to hook the print_name method in the class driver and return a - // different name each and every time the name sysfs entry is queried. - // - // Right now this is not the case for any of the switch implementations used here. I'm not - // certain anyone would ever choose to implement such a dynamic name, or what it would mean - // for the implementation at this level, but if it ever happens, we will need to revisit - // this code. for (int i = 0; i < uEventInfo.size(); ++i) { UEventInfo uei = uEventInfo.get(i); - if (name.equals(uei.getDevName())) { + if (devPath.equals(uei.getDevPath())) { update(name, uei.computeNewHeadsetState(mHeadsetState, state)); return; } @@ -213,7 +204,7 @@ class WiredAccessoryObserver extends UEventObserver { curState = Integer.valueOf((new String(buffer, 0, len)).trim()); if (curState > 0) { - updateState(uei.getDevName(), curState); + updateState(uei.getDevPath(), uei.getDevName(), curState); } } catch (FileNotFoundException e) { diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 60749b3..78f17bc 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -152,6 +152,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; @@ -3038,7 +3039,7 @@ public final class ActivityManagerService extends ActivityManagerNative } final void logAppTooSlow(ProcessRecord app, long startTime, String msg) { - if (IS_USER_BUILD) { + if (true || IS_USER_BUILD) { return; } String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null); @@ -3582,9 +3583,14 @@ public final class ActivityManagerService extends ActivityManagerNative if (doit) { procs.add(app); } - } else if ((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid) - || app.processName.equals(packageName) - || app.processName.startsWith(procNamePrefix)) { + // If uid is specified and the uid and process name match + // Or, the uid is not specified and the process name matches + } else if (((uid > 0 && uid != Process.SYSTEM_UID && app.info.uid == uid) + && (app.processName.equals(packageName) + || app.processName.startsWith(procNamePrefix))) + || (uid < 0 + && (app.processName.equals(packageName) + || app.processName.startsWith(procNamePrefix)))) { if (app.setAdj >= minOomAdj) { if (!doit) { return true; @@ -3635,7 +3641,8 @@ public final class ActivityManagerService extends ActivityManagerNative for (i=0; i<mMainStack.mHistory.size(); i++) { ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i); final boolean samePackage = r.packageName.equals(name); - if ((samePackage || r.task == lastTask) + if (r.userId == userId + && (samePackage || r.task == lastTask) && (r.app == null || evenPersistent || !r.app.persistent)) { if (!doit) { if (r.finishing) { @@ -3685,7 +3692,7 @@ public final class ActivityManagerService extends ActivityManagerNative } ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>(); - for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) { + for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(userId).values()) { if (provider.info.packageName.equals(name) && (provider.proc == null || evenPersistent || !provider.proc.persistent)) { if (!doit) { @@ -4118,7 +4125,16 @@ public final class ActivityManagerService extends ActivityManagerNative } } }, pkgFilter); - + + IntentFilter userFilter = new IntentFilter(); + userFilter.addAction(Intent.ACTION_USER_REMOVED); + mContext.registerReceiver(new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + onUserRemoved(intent); + } + }, userFilter); + synchronized (this) { // Ensure that any processes we had put on hold are now started // up. @@ -12469,7 +12485,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (DEBUG_BROADCAST_LIGHT) Slog.v( TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent - + " ordered=" + ordered); + + " ordered=" + ordered + " userid=" + userId); if ((resultTo != null) && !ordered) { Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!"); } @@ -14593,25 +14609,6 @@ public final class ActivityManagerService extends ActivityManagerNative private int mCurrentUserId; private SparseIntArray mLoggedInUsers = new SparseIntArray(5); - private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3); - - public interface UserListener { - public void onUserChanged(int userId); - - public void onUserAdded(int userId); - - public void onUserRemoved(int userId); - - public void onUserLoggedOut(int userId); - } - - public void addUserListener(UserListener listener) { - synchronized (this) { - if (!mUserListeners.contains(listener)) { - mUserListeners.add(listener); - } - } - } public boolean switchUser(int userId) { final int callingUid = Binder.getCallingUid(); @@ -14622,8 +14619,6 @@ public final class ActivityManagerService extends ActivityManagerNative if (mCurrentUserId == userId) return true; - ArrayList<UserListener> listeners; - synchronized (this) { // Check if user is already logged in, otherwise check if user exists first before // adding to the list of logged in users. @@ -14640,23 +14635,44 @@ public final class ActivityManagerService extends ActivityManagerNative startHomeActivityLocked(userId); } - listeners = (ArrayList<UserListener>) mUserListeners.clone(); - } - // Inform the listeners - for (UserListener listener : listeners) { - listener.onUserChanged(userId); } + + // Inform of user switch + Intent addedIntent = new Intent(Intent.ACTION_USER_SWITCHED); + addedIntent.putExtra(Intent.EXTRA_USERID, userId); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + return true; } - private boolean userExists(int userId) { - try { - List<UserInfo> users = AppGlobals.getPackageManager().getUsers(); - for (UserInfo user : users) { - if (user.id == userId) { - return true; + private void onUserRemoved(Intent intent) { + int extraUserId = intent.getIntExtra(Intent.EXTRA_USERID, -1); + if (extraUserId < 1) return; + + // Kill all the processes for the user + ArrayList<Pair<String, Integer>> pkgAndUids = new ArrayList<Pair<String,Integer>>(); + synchronized (this) { + HashMap<String,SparseArray<ProcessRecord>> map = mProcessNames.getMap(); + for (Entry<String, SparseArray<ProcessRecord>> uidMap : map.entrySet()) { + SparseArray<ProcessRecord> uids = uidMap.getValue(); + for (int i = 0; i < uids.size(); i++) { + if (UserId.getUserId(uids.keyAt(i)) == extraUserId) { + pkgAndUids.add(new Pair<String,Integer>(uidMap.getKey(), uids.keyAt(i))); + } } } + + for (Pair<String,Integer> pkgAndUid : pkgAndUids) { + forceStopPackageLocked(pkgAndUid.first, pkgAndUid.second, + false, false, true, true, extraUserId); + } + } + } + + private boolean userExists(int userId) { + try { + UserInfo user = AppGlobals.getPackageManager().getUser(userId); + return user != null; } catch (RemoteException re) { // Won't happen, in same process } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 067bf28..1593707 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -134,6 +134,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -404,7 +405,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Delay time in millisecs static final int BROADCAST_DELAY = 10 * 1000; - final UserManager mUserManager; + static UserManager sUserManager; // Stores a list of users whose package restrictions file needs to be updated private HashSet<Integer> mDirtyUsers = new HashSet<Integer>(); @@ -632,7 +633,7 @@ public class PackageManagerService extends IPackageManager.Stub { packages[i] = ent.getKey(); components[i] = ent.getValue(); PackageSetting ps = mSettings.mPackages.get(ent.getKey()); - uids[i] = (ps != null) ? ps.uid : -1; + uids[i] = (ps != null) ? ps.appId : -1; i++; } size = i; @@ -676,14 +677,15 @@ public class PackageManagerService extends IPackageManager.Stub { } sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, res.pkg.applicationInfo.packageName, - extras, null, null); + extras, null, null, UserId.USER_ALL); if (update) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, res.pkg.applicationInfo.packageName, - extras, null, null); + extras, null, null, UserId.USER_ALL); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, null, - res.pkg.applicationInfo.packageName, null); + res.pkg.applicationInfo.packageName, null, + UserId.USER_ALL); } if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now @@ -820,6 +822,7 @@ public class PackageManagerService extends IPackageManager.Stub { } void scheduleWritePackageRestrictionsLocked(int userId) { + if (!sUserManager.exists(userId)) return; mDirtyUsers.add(userId); if (!mHandler.hasMessages(WRITE_PACKAGE_RESTRICTIONS)) { mHandler.sendEmptyMessageDelayed(WRITE_PACKAGE_RESTRICTIONS, WRITE_SETTINGS_DELAY); @@ -920,7 +923,7 @@ public class PackageManagerService extends IPackageManager.Stub { mUserAppDataDir = new File(dataDir, "user"); mDrmAppPrivateInstallDir = new File(dataDir, "app-private"); - mUserManager = new UserManager(mInstaller, mUserAppDataDir); + sUserManager = new UserManager(mInstaller, mUserAppDataDir); readPermissions(); @@ -1086,7 +1089,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " no longer exists; wiping its data"; reportSettingsProblem(Log.WARN, msg); mInstaller.remove(ps.name, 0); - mUserManager.removePackageForAllUsers(ps.name); + sUserManager.removePackageForAllUsers(ps.name); } } } @@ -1242,7 +1245,7 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Couldn't remove app data directory for package: " + ps.name + ", retcode=" + retCode); } else { - mUserManager.removePackageForAllUsers(ps.name); + sUserManager.removePackageForAllUsers(ps.name); } if (ps.codePath != null) { if (!ps.codePath.delete()) { @@ -1506,29 +1509,39 @@ public class PackageManagerService extends IPackageManager.Stub { return cur; } - PackageInfo generatePackageInfo(PackageParser.Package p, int flags) { + PackageInfo generatePackageInfo(PackageParser.Package p, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; + PackageInfo pi; if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { // The package has been uninstalled but has retained data and resources. - return PackageParser.generatePackageInfo(p, null, flags, 0, 0, null); - } - final PackageSetting ps = (PackageSetting)p.mExtras; - if (ps == null) { - return null; + pi = PackageParser.generatePackageInfo(p, null, flags, 0, 0, null, false, 0, userId); + } else { + final PackageSetting ps = (PackageSetting) p.mExtras; + if (ps == null) { + return null; + } + final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; + pi = PackageParser.generatePackageInfo(p, gp.gids, flags, + ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions, + ps.getStopped(userId), ps.getEnabled(userId), userId); + pi.applicationInfo.enabledSetting = ps.getEnabled(userId); + pi.applicationInfo.enabled = + pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_DEFAULT + || pi.applicationInfo.enabledSetting == COMPONENT_ENABLED_STATE_ENABLED; } - final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; - return PackageParser.generatePackageInfo(p, gp.gids, flags, - ps.firstInstallTime, ps.lastUpdateTime, gp.grantedPermissions); + return pi; } @Override public PackageInfo getPackageInfo(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getPackageInfo " + packageName + ": " + p); if (p != null) { - return generatePackageInfo(p, flags); + return generatePackageInfo(p, flags, userId); } if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { return generatePackageInfoFromSettingsLPw(packageName, flags, userId); @@ -1563,6 +1576,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public int getPackageUid(String packageName, int userId) { + if (!sUserManager.exists(userId)) return -1; // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1673,6 +1687,7 @@ public class PackageManagerService extends IPackageManager.Stub { private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { if (ps.pkg == null) { @@ -1682,15 +1697,18 @@ public class PackageManagerService extends IPackageManager.Stub { } return null; } - return PackageParser.generateApplicationInfo(ps.pkg, flags); + return PackageParser.generateApplicationInfo(ps.pkg, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } return null; } private PackageInfo generatePackageInfoFromSettingsLPw(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { + PackageParser.Package pkg = new PackageParser.Package(packageName); if (ps.pkg == null) { ps.pkg = new PackageParser.Package(packageName); ps.pkg.applicationInfo.packageName = packageName; @@ -1701,15 +1719,16 @@ public class PackageManagerService extends IPackageManager.Stub { getDataPathForPackage(ps.pkg.packageName, 0).getPath(); ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; } - ps.pkg.mSetEnabled = ps.getEnabled(userId); - ps.pkg.mSetStopped = ps.getStopped(userId); - return generatePackageInfo(ps.pkg, flags); + // ps.pkg.mSetEnabled = ps.getEnabled(userId); + // ps.pkg.mSetStopped = ps.getStopped(userId); + return generatePackageInfo(ps.pkg, flags, userId); } return null; } @Override public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; // writer synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); @@ -1717,8 +1736,11 @@ public class PackageManagerService extends IPackageManager.Stub { TAG, "getApplicationInfo " + packageName + ": " + p); if (p != null) { + PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps == null) return null; // Note: isEnabledLP() does not apply here - always return info - return PackageParser.generateApplicationInfo(p, flags); + return PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId), + ps.getEnabled(userId)); } if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; @@ -1782,12 +1804,16 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; synchronized (mPackages) { PackageParser.Activity a = mActivities.mActivities.get(component); if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getActivityInfo " + component + ": " + a); if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { - return PackageParser.generateActivityInfo(a, flags, userId); + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } if (mResolveComponentName.equals(component)) { return mResolveActivity; @@ -1798,12 +1824,16 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; synchronized (mPackages) { PackageParser.Activity a = mReceivers.mActivities.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getReceiverInfo " + component + ": " + a); if (a != null && mSettings.isEnabledLPr(a.info, flags, userId)) { - return PackageParser.generateActivityInfo(a, flags, userId); + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateActivityInfo(a, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } } return null; @@ -1811,12 +1841,16 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; synchronized (mPackages) { PackageParser.Service s = mServices.mServices.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getServiceInfo " + component + ": " + s); if (s != null && mSettings.isEnabledLPr(s.info, flags, userId)) { - return PackageParser.generateServiceInfo(s, flags, userId); + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateServiceInfo(s, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } } return null; @@ -1824,12 +1858,16 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; synchronized (mPackages) { PackageParser.Provider p = mProvidersByComponent.get(component); if (DEBUG_PACKAGE_INFO) Log.v( TAG, "getProviderInfo " + component + ": " + p); if (p != null && mSettings.isEnabledLPr(p.info, flags, userId)) { - return PackageParser.generateProviderInfo(p, flags, userId); + PackageSetting ps = mSettings.mPackages.get(component.getPackageName()); + if (ps == null) return null; + return PackageParser.generateProviderInfo(p, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } } return null; @@ -2253,6 +2291,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId); return chooseBestActivity(intent, resolvedType, flags, query, userId); } @@ -2294,6 +2333,7 @@ public class PackageManagerService extends IPackageManager.Stub { ResolveInfo findPreferredActivity(Intent intent, String resolvedType, int flags, List<ResolveInfo> query, int priority, int userId) { + if (!sUserManager.exists(userId)) return null; // writer synchronized (mPackages) { if (intent.getSelector() != null) { @@ -2389,6 +2429,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { @@ -2427,6 +2468,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; final String resultsAction = intent.getAction(); List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags @@ -2596,6 +2638,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { @@ -2632,6 +2675,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) { List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId); + if (!sUserManager.exists(userId)) return null; if (query != null) { if (query.size() >= 1) { // If there is more than one service with the same priority, @@ -2645,6 +2689,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { @@ -2723,7 +2768,7 @@ public class PackageManagerService extends IPackageManager.Stub { } else { final PackageParser.Package p = mPackages.get(packageName); if (p != null) { - pi = generatePackageInfo(p, flags); + pi = generatePackageInfo(p, flags, userId); } } @@ -2743,6 +2788,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, String lastRead, int userId) { + if (!sUserManager.exists(userId)) return null; final ParceledListSlice<ApplicationInfo> list = new ParceledListSlice<ApplicationInfo>(); final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; final String[] keys; @@ -2763,15 +2809,16 @@ public class PackageManagerService extends IPackageManager.Stub { final String packageName = keys[i++]; ApplicationInfo ai = null; + final PackageSetting ps = mSettings.mPackages.get(packageName); if (listUninstalled) { - final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { ai = generateApplicationInfoFromSettingsLPw(ps.name, flags, userId); } } else { final PackageParser.Package p = mPackages.get(packageName); - if (p != null) { - ai = PackageParser.generateApplicationInfo(p, flags, userId); + if (p != null && ps != null) { + ai = PackageParser.generateApplicationInfo(p, flags, ps.getStopped(userId), + ps.getEnabled(userId), userId); } } @@ -2794,13 +2841,17 @@ public class PackageManagerService extends IPackageManager.Stub { // reader synchronized (mPackages) { final Iterator<PackageParser.Package> i = mPackages.values().iterator(); - final int userId = UserId.getUserId(Binder.getCallingUid()); + final int userId = UserId.getCallingUserId(); while (i.hasNext()) { final PackageParser.Package p = i.next(); if (p.applicationInfo != null && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0 && (!mSafeMode || isSystemApp(p))) { - finalList.add(PackageParser.generateApplicationInfo(p, flags, userId)); + PackageSetting ps = mSettings.mPackages.get(p.packageName); + finalList.add(PackageParser.generateApplicationInfo(p, flags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId)); } } } @@ -2810,14 +2861,21 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public ProviderInfo resolveContentProvider(String name, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; // reader synchronized (mPackages) { final PackageParser.Provider provider = mProviders.get(name); + PackageSetting ps = provider != null + ? mSettings.mPackages.get(provider.owner.packageName) + : null; return provider != null && mSettings.isEnabledLPr(provider.info, flags, userId) && (!mSafeMode || (provider.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0) - ? PackageParser.generateProviderInfo(provider, flags, userId) + ? PackageParser.generateProviderInfo(provider, flags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId) : null; } } @@ -2831,16 +2889,20 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { final Iterator<Map.Entry<String, PackageParser.Provider>> i = mProviders.entrySet() .iterator(); - final int userId = UserId.getUserId(Binder.getCallingUid()); + final int userId = UserId.getCallingUserId(); while (i.hasNext()) { Map.Entry<String, PackageParser.Provider> entry = i.next(); PackageParser.Provider p = entry.getValue(); + PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); if (p.syncable && (!mSafeMode || (p.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0)) { outNames.add(entry.getKey()); - outInfo.add(PackageParser.generateProviderInfo(p, 0, userId)); + outInfo.add(PackageParser.generateProviderInfo(p, 0, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId)); } } } @@ -2857,6 +2919,7 @@ public class PackageManagerService extends IPackageManager.Stub { UserId.getUserId(uid) : UserId.getCallingUserId(); while (i.hasNext()) { final PackageParser.Provider p = i.next(); + PackageSetting ps = mSettings.mPackages.get(p.owner.packageName); if (p.info.authority != null && (processName == null || (p.info.processName.equals(processName) @@ -2867,7 +2930,10 @@ public class PackageManagerService extends IPackageManager.Stub { if (finalList == null) { finalList = new ArrayList<ProviderInfo>(3); } - finalList.add(PackageParser.generateProviderInfo(p, flags, userId)); + finalList.add(PackageParser.generateProviderInfo(p, flags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId)); } } } @@ -3511,7 +3577,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } - pkg.applicationInfo.uid = pkgSetting.uid; + pkg.applicationInfo.uid = pkgSetting.appId; pkg.mExtras = pkgSetting; if (!verifySignaturesLP(pkgSetting, pkg)) { @@ -3618,7 +3684,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (ret >= 0) { // TODO: Kill the processes first // Remove the data directories for all users - mUserManager.removePackageForAllUsers(pkgName); + sUserManager.removePackageForAllUsers(pkgName); // Old data gone! String msg = "System package " + pkg.packageName + " has changed from uid: " @@ -3639,7 +3705,7 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } // Create data directories for all users - mUserManager.installPackageForAllUsers(pkgName, + sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid); } if (!recovered) { @@ -3681,7 +3747,7 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } // Create data directories for all users - mUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid); + sUserManager.installPackageForAllUsers(pkgName, pkg.applicationInfo.uid); if (dataPath.exists()) { pkg.applicationInfo.dataDir = dataPath.getPath(); @@ -4510,12 +4576,14 @@ public class PackageManagerService extends IPackageManager.Stub { extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, int userId) { + if (!sUserManager.exists(userId)) return null; mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; return super.queryIntent(intent, resolvedType, defaultOnly, userId); } public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; mFlags = flags; return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId); @@ -4523,6 +4591,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) { + if (!sUserManager.exists(userId)) return null; if (packageActivities == null) { return null; } @@ -4605,6 +4674,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter, int userId) { + if (!sUserManager.exists(userId)) return true; PackageParser.Package p = filter.activity.owner; if (p != null) { PackageSetting ps = (PackageSetting)p.mExtras; @@ -4626,6 +4696,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, int match, int userId) { + if (!sUserManager.exists(userId)) return null; if (!mSettings.isEnabledLPr(info.activity.info, mFlags, userId)) { return null; } @@ -4635,7 +4706,11 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final ResolveInfo res = new ResolveInfo(); - res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, userId); + PackageSetting ps = (PackageSetting) activity.owner.mExtras; + res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId); if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = info; } @@ -4696,6 +4771,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; mFlags = flags; return super.queryIntent(intent, resolvedType, (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId); @@ -4703,6 +4779,7 @@ public class PackageManagerService extends IPackageManager.Stub { public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, int flags, ArrayList<PackageParser.Service> packageServices, int userId) { + if (!sUserManager.exists(userId)) return null; if (packageServices == null) { return null; } @@ -4780,6 +4857,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter, int userId) { + if (!sUserManager.exists(userId)) return true; PackageParser.Package p = filter.service.owner; if (p != null) { PackageSetting ps = (PackageSetting)p.mExtras; @@ -4802,6 +4880,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, int match, int userId) { + if (!sUserManager.exists(userId)) return null; final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter; if (!mSettings.isEnabledLPr(info.service.info, mFlags, userId)) { return null; @@ -4812,7 +4891,11 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final ResolveInfo res = new ResolveInfo(); - res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, userId); + PackageSetting ps = (PackageSetting) service.owner.mExtras; + res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId); if ((mFlags&PackageManager.GET_RESOLVED_FILTER) != 0) { res.filter = filter; } @@ -4903,23 +4986,32 @@ public class PackageManagerService extends IPackageManager.Stub { }; static final void sendPackageBroadcast(String action, String pkg, - Bundle extras, String targetPkg, IIntentReceiver finishedReceiver) { + Bundle extras, String targetPkg, IIntentReceiver finishedReceiver, int userId) { IActivityManager am = ActivityManagerNative.getDefault(); if (am != null) { try { - final Intent intent = new Intent(action, - pkg != null ? Uri.fromParts("package", pkg, null) : null); - if (extras != null) { - intent.putExtras(extras); - } - if (targetPkg != null) { - intent.setPackage(targetPkg); - } - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); - // TODO: Fix the userId argument - am.broadcastIntent(null, intent, null, finishedReceiver, - 0, null, null, null, finishedReceiver != null, false, - Binder.getOrigCallingUser()); + int[] userIds = userId == UserId.USER_ALL + ? sUserManager.getUserIds() + : new int[] {userId}; + for (int id : userIds) { + final Intent intent = new Intent(action, + pkg != null ? Uri.fromParts("package", pkg, null) : null); + if (extras != null) { + intent.putExtras(extras); + } + if (targetPkg != null) { + intent.setPackage(targetPkg); + } + // Modify the UID when posting to other users + int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); + if (uid > 0 && id > 0) { + uid = UserId.getUid(id, UserId.getAppId(uid)); + intent.putExtra(Intent.EXTRA_UID, uid); + } + intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); + am.broadcastIntent(null, intent, null, finishedReceiver, + 0, null, null, null, finishedReceiver != null, false, id); + } } catch (RemoteException ex) { } } @@ -5062,13 +5154,13 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putInt(Intent.EXTRA_UID, removedUid); extras.putBoolean(Intent.EXTRA_DATA_REMOVED, false); sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, null, null); + extras, null, null, UserId.USER_ALL); } if (addedPackage != null) { Bundle extras = new Bundle(1); extras.putInt(Intent.EXTRA_UID, addedUid); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, addedPackage, - extras, null, null); + extras, null, null, UserId.USER_ALL); } } @@ -7092,11 +7184,11 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putBoolean(Intent.EXTRA_REPLACING, true); sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName, - extras, null, null); + extras, null, null, UserId.USER_ALL); sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName, - extras, null, null); + extras, null, null, UserId.USER_ALL); sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED, null, - null, packageName, null); + null, packageName, null, UserId.USER_ALL); } } // Force a gc here. @@ -7129,14 +7221,15 @@ public class PackageManagerService extends IPackageManager.Stub { } if (removedPackage != null) { sendPackageBroadcast(Intent.ACTION_PACKAGE_REMOVED, removedPackage, - extras, null, null); + extras, null, null, UserId.USER_ALL); if (fullRemove && !replacing) { sendPackageBroadcast(Intent.ACTION_PACKAGE_FULLY_REMOVED, removedPackage, - extras, null, null); + extras, null, null, UserId.USER_ALL); } } if (removedUid >= 0) { - sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null); + sendPackageBroadcast(Intent.ACTION_UID_REMOVED, null, extras, null, null, + UserId.getUserId(removedUid)); } } } @@ -7168,7 +7261,7 @@ public class PackageManagerService extends IPackageManager.Stub { // we don't consider this to be a failure of the core package deletion } else { // TODO: Kill the processes first - mUserManager.removePackageForAllUsers(packageName); + sUserManager.removePackageForAllUsers(packageName); } schedulePackageCleaning(packageName); } @@ -7732,12 +7825,14 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public void setApplicationEnabledSetting(String appPackageName, int newState, int flags, int userId) { + if (!sUserManager.exists(userId)) return; setEnabledSetting(appPackageName, null, newState, flags, userId); } @Override public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId) { + if (!sUserManager.exists(userId)) return; setEnabledSetting(componentName.getPackageName(), componentName.getClassName(), newState, flags, userId); } @@ -7776,11 +7871,11 @@ public class PackageManagerService extends IPackageManager.Stub { + "/" + className); } // Allow root and verify that userId is not being specified by a different user - if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.uid)) { + if (!allowedByPermission && !UserId.isSameApp(uid, pkgSetting.appId)) { throw new SecurityException( "Permission Denial: attempt to change component state from pid=" + Binder.getCallingPid() - + ", uid=" + uid + ", package uid=" + pkgSetting.uid); + + ", uid=" + uid + ", package uid=" + pkgSetting.appId); } if (className == null) { // We're dealing with an application/package level state change @@ -7789,7 +7884,7 @@ public class PackageManagerService extends IPackageManager.Stub { return; } pkgSetting.setEnabled(newState, userId); - pkgSetting.pkg.mSetEnabled = newState; + // pkgSetting.pkg.mSetEnabled = newState; } else { // We're dealing with a component level state change // First, verify that this is a valid class name. @@ -7825,7 +7920,7 @@ public class PackageManagerService extends IPackageManager.Stub { } } mSettings.writePackageRestrictionsLPr(userId); - packageUid = pkgSetting.uid; + packageUid = UserId.getUid(userId, pkgSetting.appId); components = mPendingBroadcasts.get(packageName); final boolean newPackage = components == null; if (newPackage) { @@ -7873,10 +7968,12 @@ public class PackageManagerService extends IPackageManager.Stub { extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList); extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag); extras.putInt(Intent.EXTRA_UID, packageUid); - sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null); + sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null, + UserId.getUserId(packageUid)); } public void setPackageStoppedState(String packageName, boolean stopped, int userId) { + if (!sUserManager.exists(userId)) return; final int uid = Binder.getCallingUid(); final int permission = mContext.checkCallingOrSelfPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); @@ -7900,6 +7997,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public int getApplicationEnabledSetting(String packageName, int userId) { + if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int uid = Binder.getCallingUid(); checkValidCaller(uid, userId); // reader @@ -7910,6 +8008,7 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public int getComponentEnabledSetting(ComponentName componentName, int userId) { + if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED; int uid = Binder.getCallingUid(); checkValidCaller(uid, userId); // reader @@ -8383,7 +8482,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " at code path: " + ps.codePathString); // We do have a valid package installed on sdcard processCids.put(args, ps.codePathString); - int uid = ps.uid; + int uid = ps.appId; if (uid != -1) { uidList[num++] = uid; } @@ -8436,7 +8535,7 @@ public class PackageManagerService extends IPackageManager.Stub { } String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; - sendPackageBroadcast(action, null, extras, null, finishedReceiver); + sendPackageBroadcast(action, null, extras, null, finishedReceiver, UserId.USER_ALL); } } @@ -8860,8 +8959,12 @@ public class PackageManagerService extends IPackageManager.Stub { // TODO(kroot): Add a real permission for creating users enforceSystemOrRoot("Only the system can create users"); - // TODO(kroot): fix this API - UserInfo userInfo = mUserManager.createUser(name, flags, new ArrayList<ApplicationInfo>()); + UserInfo userInfo = sUserManager.createUser(name, flags); + if (userInfo != null) { + Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); + addedIntent.putExtra(Intent.EXTRA_USERID, userInfo.id); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + } return userInfo; } @@ -8869,13 +8972,34 @@ public class PackageManagerService extends IPackageManager.Stub { // TODO(kroot): Add a real permission for removing users enforceSystemOrRoot("Only the system can remove users"); - if (userId == 0) { + if (userId == 0 || !sUserManager.exists(userId)) { return false; } - mUserManager.removeUser(userId); + + cleanUpUser(userId); + + if (sUserManager.removeUser(userId)) { + // Let other services shutdown any activity + Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED); + addedIntent.putExtra(Intent.EXTRA_USERID, userId); + mContext.sendBroadcast(addedIntent, android.Manifest.permission.MANAGE_ACCOUNTS); + } + sUserManager.removePackageFolders(userId); return true; } + private void cleanUpUser(int userId) { + // Disable all the packages for the user first + synchronized (mPackages) { + Set<Entry<String, PackageSetting>> entries = mSettings.mPackages.entrySet(); + for (Entry<String, PackageSetting> entry : entries) { + entry.getValue().removeUser(userId); + } + if (mDirtyUsers.remove(userId)); + mSettings.removeUserLPr(userId); + } + } + @Override public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException { mContext.enforceCallingOrSelfPermission( @@ -8887,8 +9011,22 @@ public class PackageManagerService extends IPackageManager.Stub { } } + @Override public List<UserInfo> getUsers() { - return mUserManager.getUsers(); + enforceSystemOrRoot("Only the system can query users"); + return sUserManager.getUsers(); + } + + @Override + public UserInfo getUser(int userId) { + enforceSystemOrRoot("Only the system can remove users"); + return sUserManager.getUser(userId); + } + + @Override + public void updateUserName(int userId, String name) { + enforceSystemOrRoot("Only the system can rename users"); + sUserManager.updateUserName(userId, name); } @Override diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java index 48ed9bf..f7f0870 100644 --- a/services/java/com/android/server/pm/PackageSetting.java +++ b/services/java/com/android/server/pm/PackageSetting.java @@ -24,7 +24,7 @@ import java.io.File; * Settings data for a particular package we know about. */ final class PackageSetting extends PackageSettingBase { - int uid; + int appId; PackageParser.Package pkg; SharedUserSetting sharedUser; @@ -41,7 +41,7 @@ final class PackageSetting extends PackageSettingBase { PackageSetting(PackageSetting orig) { super(orig); - uid = orig.uid; + appId = orig.appId; pkg = orig.pkg; sharedUser = orig.sharedUser; } @@ -50,6 +50,6 @@ final class PackageSetting extends PackageSettingBase { public String toString() { return "PackageSetting{" + Integer.toHexString(System.identityHashCode(this)) - + " " + name + "/" + uid + "}"; + + " " + name + "/" + appId + "}"; } }
\ No newline at end of file diff --git a/services/java/com/android/server/pm/PackageSettingBase.java b/services/java/com/android/server/pm/PackageSettingBase.java index b7cf8d6..56f2166 100644 --- a/services/java/com/android/server/pm/PackageSettingBase.java +++ b/services/java/com/android/server/pm/PackageSettingBase.java @@ -273,4 +273,13 @@ class PackageSettingBase extends GrantedPermissions { return COMPONENT_ENABLED_STATE_DEFAULT; } } + + void removeUser(int userId) { + enabled.delete(userId); + stopped.delete(userId); + enabledComponents.delete(userId); + disabledComponents.delete(userId); + notLaunched.delete(userId); + } + } diff --git a/services/java/com/android/server/pm/Settings.java b/services/java/com/android/server/pm/Settings.java index b541c8c..bb7f4fc 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -275,7 +275,7 @@ final class Settings { p.pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } PackageSetting ret = addPackageLPw(name, p.realName, p.codePath, p.resourcePath, - p.nativeLibraryPathString, p.uid, p.versionCode, p.pkgFlags); + p.nativeLibraryPathString, p.appId, p.versionCode, p.pkgFlags); mDisabledSysPackages.remove(name); return ret; } @@ -284,7 +284,7 @@ final class Settings { String nativeLibraryPathString, int uid, int vc, int pkgFlags) { PackageSetting p = mPackages.get(name); if (p != null) { - if (p.uid == uid) { + if (p.appId == uid) { return p; } PackageManagerService.reportSettingsProblem(Log.ERROR, @@ -293,7 +293,7 @@ final class Settings { } p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, vc, pkgFlags); - p.uid = uid; + p.appId = uid; if (addUserIdLPw(uid, p, name)) { mPackages.put(name, p); return p; @@ -407,7 +407,7 @@ final class Settings { p.copyFrom(origPackage); p.signatures = s; p.sharedUser = origPackage.sharedUser; - p.uid = origPackage.uid; + p.appId = origPackage.appId; p.origPackage = origPackage; mRenamedPackages.put(name, origPackage.name); name = origPackage.name; @@ -435,7 +435,7 @@ final class Settings { } } if (sharedUser != null) { - p.uid = sharedUser.userId; + p.appId = sharedUser.userId; } else { // Clone the setting here for disabled system packages PackageSetting dis = mDisabledSysPackages.get(name); @@ -447,7 +447,7 @@ final class Settings { if (dis.signatures.mSignatures != null) { p.signatures.mSignatures = dis.signatures.mSignatures.clone(); } - p.uid = dis.uid; + p.appId = dis.appId; // Clone permissions p.grantedPermissions = new HashSet<String>(dis.grantedPermissions); // Clone component info @@ -464,14 +464,14 @@ final class Settings { } } // Add new setting to list of user ids - addUserIdLPw(p.uid, p, name); + addUserIdLPw(p.appId, p, name); } else { // Assign new user id - p.uid = newUserIdLPw(p); + p.appId = newUserIdLPw(p); } } } - if (p.uid < 0) { + if (p.appId < 0) { PackageManagerService.reportSettingsProblem(Log.WARN, "Package " + name + " could not be assigned a valid uid"); return null; @@ -539,9 +539,9 @@ final class Settings { + p.sharedUser + " but is now " + sharedUser + "; I am not changing its files so it will probably fail!"); p.sharedUser.packages.remove(p); - } else if (p.uid != sharedUser.userId) { + } else if (p.appId != sharedUser.userId) { PackageManagerService.reportSettingsProblem(Log.ERROR, - "Package " + p.name + " was user id " + p.uid + "Package " + p.name + " was user id " + p.appId + " but is now user " + sharedUser + " with id " + sharedUser.userId + "; I am not changing its files so it will probably fail!"); @@ -549,7 +549,7 @@ final class Settings { sharedUser.packages.add(p); p.sharedUser = sharedUser; - p.uid = sharedUser.userId; + p.appId = sharedUser.userId; } } @@ -614,8 +614,8 @@ final class Settings { return p.sharedUser.userId; } } else { - removeUserIdLPw(p.uid); - return p.uid; + removeUserIdLPw(p.appId); + return p.appId; } } return -1; @@ -628,7 +628,7 @@ final class Settings { p.sharedUser.packages.remove(p); p.sharedUser.packages.add(newp); } else { - replaceUserIdLPw(p.uid, newp); + replaceUserIdLPw(p.appId, newp); } } mPackages.put(name, newp); @@ -1317,9 +1317,9 @@ final class Settings { serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); } if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", Integer.toString(pkg.uid)); + serializer.attribute(null, "userId", Integer.toString(pkg.appId)); } else { - serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid)); + serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId)); } serializer.startTag(null, "perms"); if (pkg.sharedUser == null) { @@ -1364,9 +1364,9 @@ final class Settings { serializer.attribute(null, "ut", Long.toHexString(pkg.lastUpdateTime)); serializer.attribute(null, "version", String.valueOf(pkg.versionCode)); if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", Integer.toString(pkg.uid)); + serializer.attribute(null, "userId", Integer.toString(pkg.appId)); } else { - serializer.attribute(null, "sharedUserId", Integer.toString(pkg.uid)); + serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId)); } if (pkg.uidError) { serializer.attribute(null, "uidError", "true"); @@ -1607,7 +1607,7 @@ final class Settings { final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator(); while (disabledIt.hasNext()) { final PackageSetting disabledPs = disabledIt.next(); - final Object id = getUserIdLPr(disabledPs.uid); + final Object id = getUserIdLPr(disabledPs.appId); if (id != null && id instanceof SharedUserSetting) { disabledPs.sharedUser = (SharedUserSetting) id; } @@ -1753,10 +1753,10 @@ final class Settings { } } String idStr = parser.getAttributeValue(null, "userId"); - ps.uid = idStr != null ? Integer.parseInt(idStr) : 0; - if (ps.uid <= 0) { + ps.appId = idStr != null ? Integer.parseInt(idStr) : 0; + if (ps.appId <= 0) { String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); - ps.uid = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; + ps.appId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; } int outerDepth = parser.getDepth(); int type; @@ -2164,6 +2164,13 @@ final class Settings { } } + void removeUserLPr(int userId) { + File file = getUserPackagesStateFile(userId); + file.delete(); + file = getUserPackagesStateBackupFile(userId); + file.delete(); + } + // Returns -1 if we could not find an available UserId to assign private int newUserIdLPw(Object obj) { // Let's be stupidly inefficient for now... @@ -2265,11 +2272,11 @@ final class Settings { if (pkgSetting == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } - if (!allowedByPermission && (appId != pkgSetting.uid)) { + if (!allowedByPermission && (appId != pkgSetting.appId)) { throw new SecurityException( "Permission Denial: attempt to change stopped state from pid=" + Binder.getCallingPid() - + ", uid=" + uid + ", package uid=" + pkgSetting.uid); + + ", uid=" + uid + ", package uid=" + pkgSetting.appId); } if (DEBUG_STOPPED) { if (stopped) { @@ -2285,7 +2292,7 @@ final class Settings { if (pkgSetting.installerPackageName != null) { PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgSetting.name, null, - pkgSetting.installerPackageName, null); + pkgSetting.installerPackageName, null, userId); } pkgSetting.setNotLaunched(false, userId); } @@ -2369,7 +2376,7 @@ final class Settings { pw.println(ps.name); } - pw.print(" userId="); pw.print(ps.uid); + pw.print(" userId="); pw.print(ps.appId); pw.print(" gids="); pw.println(PackageManagerService.arrayToString(ps.gids)); pw.print(" sharedUser="); pw.println(ps.sharedUser); pw.print(" pkg="); pw.println(ps.pkg); @@ -2513,7 +2520,7 @@ final class Settings { pw.println(ps.name); } pw.print(" userId="); - pw.println(ps.uid); + pw.println(ps.appId); pw.print(" sharedUser="); pw.println(ps.sharedUser); pw.print(" codePath="); diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java index 959e570..4e9e666 100644 --- a/services/java/com/android/server/pm/UserManager.java +++ b/services/java/com/android/server/pm/UserManager.java @@ -16,6 +16,7 @@ package com.android.server.pm; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastXmlSerializer; import android.content.pm.ApplicationInfo; @@ -58,7 +59,7 @@ public class UserManager { private static final String USER_INFO_DIR = "system" + File.separator + "users"; private static final String USER_LIST_FILENAME = "userlist.xml"; - private SparseArray<UserInfo> mUsers; + private SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>(); private final File mUsersDir; private final File mUserListFile; @@ -91,11 +92,36 @@ public class UserManager { } public List<UserInfo> getUsers() { - ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); - for (int i = 0; i < mUsers.size(); i++) { - users.add(mUsers.valueAt(i)); + synchronized (mUsers) { + ArrayList<UserInfo> users = new ArrayList<UserInfo>(mUsers.size()); + for (int i = 0; i < mUsers.size(); i++) { + users.add(mUsers.valueAt(i)); + } + return users; + } + } + + public UserInfo getUser(int userId) { + synchronized (mUsers) { + UserInfo info = mUsers.get(userId); + return info; + } + } + + public boolean exists(int userId) { + synchronized (mUsers) { + return ArrayUtils.contains(mUserIds, userId); + } + } + + public void updateUserName(int userId, String name) { + synchronized (mUsers) { + UserInfo info = mUsers.get(userId); + if (name != null && !name.equals(info.name)) { + info.name = name; + writeUserLocked(info); + } } - return users; } /** @@ -108,9 +134,14 @@ public class UserManager { } private void readUserList() { - mUsers = new SparseArray<UserInfo>(); + synchronized (mUsers) { + readUserListLocked(); + } + } + + private void readUserListLocked() { if (!mUserListFile.exists()) { - fallbackToSingleUser(); + fallbackToSingleUserLocked(); return; } FileInputStream fis = null; @@ -126,7 +157,7 @@ public class UserManager { if (type != XmlPullParser.START_TAG) { Slog.e(LOG_TAG, "Unable to read user list"); - fallbackToSingleUser(); + fallbackToSingleUserLocked(); return; } @@ -139,11 +170,11 @@ public class UserManager { } } } - updateUserIds(); + updateUserIdsLocked(); } catch (IOException ioe) { - fallbackToSingleUser(); + fallbackToSingleUserLocked(); } catch (XmlPullParserException pe) { - fallbackToSingleUser(); + fallbackToSingleUserLocked(); } finally { if (fis != null) { try { @@ -154,15 +185,15 @@ public class UserManager { } } - private void fallbackToSingleUser() { + private void fallbackToSingleUserLocked() { // Create the primary user UserInfo primary = new UserInfo(0, "Primary", UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY); mUsers.put(0, primary); - updateUserIds(); + updateUserIdsLocked(); - writeUserList(); - writeUser(primary); + writeUserListLocked(); + writeUserLocked(primary); } /* @@ -172,7 +203,7 @@ public class UserManager { * <name>Primary</name> * </user> */ - private void writeUser(UserInfo userInfo) { + private void writeUserLocked(UserInfo userInfo) { FileOutputStream fos = null; try { final File mUserFile = new File(mUsersDir, userInfo.id + ".xml"); @@ -216,7 +247,7 @@ public class UserManager { * <user id="2"></user> * </users> */ - private void writeUserList() { + private void writeUserListLocked() { FileOutputStream fos = null; try { fos = new FileOutputStream(mUserListFile); @@ -309,17 +340,19 @@ public class UserManager { return null; } - public UserInfo createUser(String name, int flags, List<ApplicationInfo> apps) { + public UserInfo createUser(String name, int flags) { int userId = getNextAvailableId(); UserInfo userInfo = new UserInfo(userId, name, flags); File userPath = new File(mBaseUserPath, Integer.toString(userId)); - if (!createPackageFolders(userId, userPath, apps)) { + if (!createPackageFolders(userId, userPath)) { return null; } - mUsers.put(userId, userInfo); - writeUserList(); - writeUser(userInfo); - updateUserIds(); + synchronized (mUsers) { + mUsers.put(userId, userInfo); + writeUserListLocked(); + writeUserLocked(userInfo); + updateUserIdsLocked(); + } return userInfo; } @@ -328,7 +361,13 @@ public class UserManager { * after the user's processes have been terminated. * @param id the user's id */ - public void removeUser(int id) { + public boolean removeUser(int id) { + synchronized (mUsers) { + return removeUserLocked(id); + } + } + + private boolean removeUserLocked(int id) { // Remove from the list UserInfo userInfo = mUsers.get(id); if (userInfo != null) { @@ -338,11 +377,11 @@ public class UserManager { File userFile = new File(mUsersDir, id + ".xml"); userFile.delete(); // Update the user list - writeUserList(); - // Remove the data directories for all packages for this user - removePackageFolders(id); - updateUserIds(); + writeUserListLocked(); + updateUserIdsLocked(); + return true; } + return false; } public void installPackageForAllUsers(String packageName, int uid) { @@ -376,7 +415,7 @@ public class UserManager { /** * Caches the list of user ids in an array, adjusting the array size when necessary. */ - private void updateUserIds() { + private void updateUserIdsLocked() { if (mUserIds == null || mUserIds.length != mUsers.size()) { mUserIds = new int[mUsers.size()]; } @@ -402,11 +441,10 @@ public class UserManager { return i; } - private boolean createPackageFolders(int id, File userPath, final List<ApplicationInfo> apps) { + private boolean createPackageFolders(int id, File userPath) { // mInstaller may not be available for unit-tests. - if (mInstaller == null || apps == null) return true; + if (mInstaller == null) return true; - final long startTime = SystemClock.elapsedRealtime(); // Create the user path userPath.mkdir(); FileUtils.setPermissions(userPath.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG @@ -414,13 +452,10 @@ public class UserManager { mInstaller.cloneUserData(0, id, false); - final long stopTime = SystemClock.elapsedRealtime(); - Log.i(LOG_TAG, - "Time to create " + apps.size() + " packages = " + (stopTime - startTime) + "ms"); return true; } - private boolean removePackageFolders(int id) { + boolean removePackageFolders(int id) { // mInstaller may not be available for unit-tests. if (mInstaller == null) return true; diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index 1442883..6269420 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -51,7 +51,7 @@ class AppWindowToken extends WindowToken { int groupId = -1; boolean appFullscreen; int requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED; - + // The input dispatching timeout for this application token in nanoseconds. long inputDispatchingTimeoutNanos; @@ -225,7 +225,7 @@ class AppWindowToken extends WindowToken { if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "performing show on: " + w); w.performShowLocked(); - isAnimating |= w.isAnimating(); + isAnimating |= w.mWinAnimator.isAnimating(); } return isAnimating; } @@ -243,11 +243,11 @@ class AppWindowToken extends WindowToken { // cache often used attributes locally final float tmpFloats[] = service.mTmpFloats; thumbnailTransformation.getMatrix().getValues(tmpFloats); - if (WindowManagerService.SHOW_TRANSACTIONS) service.logSurface(thumbnail, + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail, "thumbnail", "POS " + tmpFloats[Matrix.MTRANS_X] + ", " + tmpFloats[Matrix.MTRANS_Y], null); thumbnail.setPosition(tmpFloats[Matrix.MTRANS_X], tmpFloats[Matrix.MTRANS_Y]); - if (WindowManagerService.SHOW_TRANSACTIONS) service.logSurface(thumbnail, + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(thumbnail, "thumbnail", "alpha=" + thumbnailTransformation.getAlpha() + " layer=" + thumbnailLayer + " matrix=[" + tmpFloats[Matrix.MSCALE_X] @@ -358,7 +358,7 @@ class AppWindowToken extends WindowToken { final int N = windows.size(); for (int i=0; i<N; i++) { - windows.get(i).finishExit(); + windows.get(i).mWinAnimator.finishExit(); } updateReportedVisibilityLocked(); @@ -388,7 +388,7 @@ class AppWindowToken extends WindowToken { if (WindowManagerService.DEBUG_VISIBILITY) { Slog.v(WindowManagerService.TAG, "Win " + win + ": isDrawn=" + win.isDrawnLw() - + ", isAnimating=" + win.isAnimating()); + + ", isAnimating=" + win.mWinAnimator.isAnimating()); if (!win.isDrawnLw()) { Slog.v(WindowManagerService.TAG, "Not displayed: s=" + win.mSurface + " pv=" + win.mPolicyVisibility @@ -398,17 +398,17 @@ class AppWindowToken extends WindowToken { + " th=" + (win.mAppToken != null ? win.mAppToken.hiddenRequested : false) - + " a=" + win.mAnimating); + + " a=" + win.mWinAnimator.mAnimating); } } numInteresting++; if (win.isDrawnLw()) { numDrawn++; - if (!win.isAnimating()) { + if (!win.mWinAnimator.isAnimating()) { numVisible++; } nowGone = false; - } else if (win.isAnimating()) { + } else if (win.mWinAnimator.isAnimating()) { nowGone = false; } } diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java index 85495ea..d8f2254 100644 --- a/services/java/com/android/server/wm/DimAnimator.java +++ b/services/java/com/android/server/wm/DimAnimator.java @@ -82,7 +82,7 @@ class DimAnimator { /** * Set's the dim surface's layer and update dim parameters that will be used in - * {@link updateSurface} after all windows are examined. + * {@link #updateSurface} after all windows are examined. */ void updateParameters(Resources res, WindowState w, long currentTime) { mDimSurface.setLayer(w.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM); @@ -94,15 +94,15 @@ class DimAnimator { // If the desired dim level has changed, then // start an animation to it. mLastDimAnimTime = currentTime; - long duration = (w.mAnimating && w.mAnimation != null) - ? w.mAnimation.computeDurationHint() + long duration = (w.mWinAnimator.mAnimating && w.mWinAnimator.mAnimation != null) + ? w.mWinAnimator.mAnimation.computeDurationHint() : WindowManagerService.DEFAULT_DIM_DURATION; if (target > mDimTargetAlpha) { TypedValue tv = new TypedValue(); res.getValue(com.android.internal.R.fraction.config_dimBehindFadeDuration, tv, true); if (tv.type == TypedValue.TYPE_FRACTION) { - duration = (long)tv.getFraction((float)duration, (float)duration); + duration = (long)tv.getFraction(duration, duration); } else if (tv.type >= TypedValue.TYPE_FIRST_INT && tv.type <= TypedValue.TYPE_LAST_INT) { duration = tv.data; diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java index fbfd9ec..81e0a17 100644 --- a/services/java/com/android/server/wm/WindowAnimator.java +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -79,7 +79,7 @@ public class WindowAnimator { } } } - + final int NEAT = mService.mExitingAppTokens.size(); for (i=0; i<NEAT; i++) { final AppWindowToken appToken = mService.mExitingAppTokens.get(i); @@ -115,6 +115,7 @@ public class WindowAnimator { for (int i = mService.mWindows.size() - 1; i >= 0; i--) { WindowState w = mService.mWindows.get(i); + WindowStateAnimator winAnimator = w.mWinAnimator; final WindowManager.LayoutParams attrs = w.mAttrs; @@ -143,7 +144,7 @@ public class WindowAnimator { // let's do something. Animation a = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.window_move_from_decor); - w.setAnimation(a); + winAnimator.setAnimation(a); w.mAnimDw = w.mLastFrame.left - w.mFrame.left; w.mAnimDh = w.mLastFrame.top - w.mFrame.top; } else { @@ -151,8 +152,8 @@ public class WindowAnimator { w.mAnimDh = mInnerDh; } - final boolean wasAnimating = w.mWasAnimating; - final boolean nowAnimating = w.stepAnimationLocked(mCurrentTime); + final boolean wasAnimating = winAnimator.mWasAnimating; + final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime); if (WindowManagerService.DEBUG_WALLPAPER) { Slog.v(TAG, w + ": wasAnimating=" + wasAnimating + @@ -163,17 +164,17 @@ public class WindowAnimator { // an animating window and take care of a request to run // a detached wallpaper animation. if (nowAnimating) { - if (w.mAnimation != null) { + if (winAnimator.mAnimation != null) { if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 - && w.mAnimation.getDetachWallpaper()) { + && winAnimator.mAnimation.getDetachWallpaper()) { mService.mInnerFields.mDetachedWallpaper = w; } - if (w.mAnimation.getBackgroundColor() != 0) { + if (winAnimator.mAnimation.getBackgroundColor() != 0) { if (mWindowAnimationBackground == null || (w.mAnimLayer < mWindowAnimationBackground.mAnimLayer)) { mWindowAnimationBackground = w; mWindowAnimationBackgroundColor = - w.mAnimation.getBackgroundColor(); + winAnimator.mAnimation.getBackgroundColor(); } } } @@ -200,7 +201,7 @@ public class WindowAnimator { } } - if (wasAnimating && !w.mAnimating && mService.mWallpaperTarget == w) { + if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == w) { mService.mInnerFields.mWallpaperMayChange = true; mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { @@ -219,7 +220,7 @@ public class WindowAnimator { mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3"); } mService.mFocusMayChange = true; - } else if (w.isReadyForDisplay() && w.mAnimation == null) { + } else if (w.isReadyForDisplay() && winAnimator.mAnimation == null) { mForceHiding = true; } } else if (mPolicy.canBeForceHidden(w, attrs)) { @@ -241,7 +242,7 @@ public class WindowAnimator { // clean up later. Animation a = mPolicy.createForceHideEnterAnimation(); if (a != null) { - w.setAnimation(a); + winAnimator.setAnimation(a); } } if (mCurrentFocus == null || mCurrentFocus.mLayer < w.mLayer) { @@ -277,7 +278,7 @@ public class WindowAnimator { WindowManagerService.DEBUG_ORIENTATION) { Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw() - + ", isAnimating=" + w.isAnimating()); + + ", isAnimating=" + winAnimator.isAnimating()); if (!w.isDrawnLw()) { Slog.v(TAG, "Not displayed: s=" + w.mSurface + " pv=" + w.mPolicyVisibility @@ -285,7 +286,7 @@ public class WindowAnimator { + " cdp=" + w.mCommitDrawPending + " ah=" + w.mAttachedHidden + " th=" + atoken.hiddenRequested - + " a=" + w.mAnimating); + + " a=" + winAnimator.mAnimating); } } if (w != atoken.startingWindow) { diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 3ecbf77..9635b33 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -89,6 +89,7 @@ import android.os.TokenWatcher; import android.provider.Settings; import android.util.DisplayMetrics; import android.util.EventLog; +import android.util.FloatMath; import android.util.Log; import android.util.Pair; import android.util.Slog; @@ -1237,7 +1238,7 @@ public class WindowManagerService extends IWindowManager.Stub if (highestTarget != null) { if (DEBUG_INPUT_METHOD) Slog.v(TAG, "mNextAppTransition=" + mNextAppTransition + " " + highestTarget - + " animating=" + highestTarget.isAnimating() + + " animating=" + highestTarget.mWinAnimator.isAnimating() + " layer=" + highestTarget.mAnimLayer + " new layer=" + w.mAnimLayer); @@ -1247,7 +1248,7 @@ public class WindowManagerService extends IWindowManager.Stub mInputMethodTargetWaitingAnim = true; mInputMethodTarget = highestTarget; return highestPos + 1; - } else if (highestTarget.isAnimating() && + } else if (highestTarget.mWinAnimator.isAnimating() && highestTarget.mAnimLayer > w.mAnimLayer) { // If the window we are currently targeting is involved // with an animation, and it is on top of the next target @@ -1600,7 +1601,7 @@ public class WindowManagerService extends IWindowManager.Stub foundI = i; if (w == mWallpaperTarget && ((w.mAppToken != null && w.mAppToken.animation != null) - || w.mAnimation != null)) { + || w.mWinAnimator.mAnimation != null)) { // The current wallpaper target is animating, so we'll // look behind it for another possible target and figure // out what is going on below. @@ -1657,9 +1658,9 @@ public class WindowManagerService extends IWindowManager.Stub // Now what is happening... if the current and new targets are // animating, then we are in our super special mode! if (foundW != null && oldW != null) { - boolean oldAnim = oldW.mAnimation != null + boolean oldAnim = oldW.mWinAnimator.mAnimation != null || (oldW.mAppToken != null && oldW.mAppToken.animation != null); - boolean foundAnim = foundW.mAnimation != null + boolean foundAnim = foundW.mWinAnimator.mAnimation != null || (foundW.mAppToken != null && foundW.mAppToken.animation != null); if (DEBUG_WALLPAPER) { Slog.v(TAG, "New animation: " + foundAnim @@ -1711,10 +1712,10 @@ public class WindowManagerService extends IWindowManager.Stub } else if (mLowerWallpaperTarget != null) { // Is it time to stop animating? - boolean lowerAnimating = mLowerWallpaperTarget.mAnimation != null + boolean lowerAnimating = mLowerWallpaperTarget.mWinAnimator.mAnimation != null || (mLowerWallpaperTarget.mAppToken != null && mLowerWallpaperTarget.mAppToken.animation != null); - boolean upperAnimating = mUpperWallpaperTarget.mAnimation != null + boolean upperAnimating = mUpperWallpaperTarget.mWinAnimator.mAnimation != null || (mUpperWallpaperTarget.mAppToken != null && mUpperWallpaperTarget.mAppToken.animation != null); if (!lowerAnimating || !upperAnimating) { @@ -2302,7 +2303,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Remove " + win + ": mSurface=" + win.mSurface + " mExiting=" + win.mExiting - + " isAnimating=" + win.isAnimating() + + " isAnimating=" + win.mWinAnimator.isAnimating() + " app-animation=" + (win.mAppToken != null ? win.mAppToken.animation : null) + " inPendingTransaction=" @@ -2329,7 +2330,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mExiting = true; } } - if (win.mExiting || win.isAnimating()) { + if (win.mExiting || win.mWinAnimator.isAnimating()) { // The exit animation is running... wait for it! //Slog.i(TAG, "*** Running exit animation..."); win.mExiting = true; @@ -2698,7 +2699,7 @@ public class WindowManagerService extends IWindowManager.Stub (win.mAppToken == null || !win.mAppToken.clientHidden)) { displayed = !win.isVisibleLw(); if (win.mExiting) { - win.cancelExitAnimationForNextAnimationLocked(); + win.mWinAnimator.cancelExitAnimationForNextAnimationLocked(); } if (win.mDestroying) { win.mDestroying = false; @@ -2802,7 +2803,7 @@ public class WindowManagerService extends IWindowManager.Stub applyAnimationLocked(win, transit, false)) { focusMayChange = true; win.mExiting = true; - } else if (win.isAnimating()) { + } else if (win.mWinAnimator.isAnimating()) { // Currently in a hide animation... turn this into // an exit. win.mExiting = true; @@ -2811,7 +2812,7 @@ public class WindowManagerService extends IWindowManager.Stub // window, we need to change both of them inside // of a transaction to avoid artifacts. win.mExiting = true; - win.mAnimating = true; + win.mWinAnimator.mAnimating = true; } else { if (mInputMethodWindow == win) { mInputMethodWindow = null; @@ -3025,7 +3026,8 @@ public class WindowManagerService extends IWindowManager.Stub */ boolean applyAnimationLocked(WindowState win, int transit, boolean isEntrance) { - if (win.mLocalAnimating && win.mAnimationIsEntrance == isEntrance) { + if (win.mWinAnimator.mLocalAnimating && + win.mWinAnimator.mAnimationIsEntrance == isEntrance) { // If we are trying to apply an animation, but already running // an animation of the same type, then just leave that one alone. return true; @@ -3062,7 +3064,7 @@ public class WindowManagerService extends IWindowManager.Stub } if (DEBUG_ANIM) Slog.v(TAG, "applyAnimation: win=" + win + " anim=" + anim + " attr=0x" + Integer.toHexString(attr) - + " mAnimation=" + win.mAnimation + + " mAnimation=" + win.mWinAnimator.mAnimation + " isEntrance=" + isEntrance); if (a != null) { if (DEBUG_ANIM) { @@ -3073,14 +3075,14 @@ public class WindowManagerService extends IWindowManager.Stub } Slog.v(TAG, "Loaded animation " + a + " for " + win, e); } - win.setAnimation(a); - win.mAnimationIsEntrance = isEntrance; + win.mWinAnimator.setAnimation(a); + win.mWinAnimator.mAnimationIsEntrance = isEntrance; } } else { - win.clearAnimation(); + win.mWinAnimator.clearAnimation(); } - return win.mAnimation != null; + return win.mWinAnimator.mAnimation != null; } private Animation loadAnimation(WindowManager.LayoutParams lp, int animAttr) { @@ -3369,7 +3371,7 @@ public class WindowManagerService extends IWindowManager.Stub for (int i=0; i<N; i++) { WindowState win = wtoken.windows.get(i); - if (win.isAnimating()) { + if (win.mWinAnimator.isAnimating()) { delayed = true; } @@ -4062,7 +4064,7 @@ public class WindowManagerService extends IWindowManager.Stub continue; } - if (win.isAnimating()) { + if (win.mWinAnimator.isAnimating()) { delayed = true; } @@ -5261,8 +5263,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(mWindowMap) { long ident = Binder.clearCallingIdentity(); - dw = mAppDisplayWidth; - dh = mAppDisplayHeight; + dw = mCurDisplayWidth; + dh = mCurDisplayHeight; int aboveAppLayer = mPolicy.windowTypeToLayerLw( WindowManager.LayoutParams.TYPE_APPLICATION) * TYPE_LAYER_MULTIPLIER @@ -5382,7 +5384,7 @@ public class WindowManagerService extends IWindowManager.Stub Bitmap bm = Bitmap.createBitmap(width, height, rawss.getConfig()); Matrix matrix = new Matrix(); ScreenRotationAnimation.createRotationMatrix(rot, dw, dh, matrix); - matrix.postTranslate(-(int)(frame.left*scale), -(int)(frame.top*scale)); + matrix.postTranslate(-FloatMath.ceil(frame.left*scale), -FloatMath.ceil(frame.top*scale)); Canvas canvas = new Canvas(bm); canvas.drawBitmap(rawss, matrix, null); canvas.setBitmap(null); @@ -8098,11 +8100,11 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows"); mAnimator.mForceHiding = true; } else if (mPolicy.canBeForceHidden(w, attrs)) { - if (!w.mAnimating) { + if (!w.mWinAnimator.mAnimating) { // We set the animation above so it // is not yet running. // TODO(cmautner): We lose the enter animation when this occurs. - w.clearAnimation(); + w.mWinAnimator.clearAnimation(); } } } @@ -9769,7 +9771,7 @@ public class WindowManagerService extends IWindowManager.Stub public interface OnHardKeyboardStatusChangeListener { public void onHardKeyboardStatusChange(boolean available, boolean enabled); } - + void debugLayoutRepeats(final String msg) { if (mLayoutRepeatCount >= LAYOUT_REPEAT_THRESHOLD) { Slog.v(TAG, "Layouts looping: " + msg); diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 1146189..615cd80 100644 --- a/services/java/com/android/server/wm/WindowState.java +++ b/services/java/com/android/server/wm/WindowState.java @@ -45,7 +45,6 @@ import android.view.ViewTreeObserver; import android.view.WindowManager; import android.view.WindowManagerPolicy; import android.view.WindowManager.LayoutParams; -import android.view.animation.Animation; import android.view.animation.Transformation; import java.io.PrintWriter; @@ -91,7 +90,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mAttachedHidden; // is our parent window hidden? boolean mLastHidden; // was this window last hidden? boolean mWallpaperVisible; // for wallpaper, what was last vis report? - boolean mWasAnimating; // Were we animating going into the most recent animation step? /** * The window size that was requested by the application. These are in @@ -110,9 +108,9 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean mTurnOnScreen; int mLayoutSeq = -1; - + Configuration mConfiguration = null; - + /** * Actual frame shown on-screen (may be modified by animation). These * are in the screen's coordinate space (WITH the compatibility scale @@ -212,15 +210,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { // an enter animation. boolean mEnterAnimationPending; - // Currently running animation. - boolean mAnimating; - boolean mLocalAnimating; - Animation mAnimation; - boolean mAnimationIsEntrance; - boolean mHasTransformation; - boolean mHasLocalTransformation; - final Transformation mTransformation = new Transformation(); - // If a window showing a wallpaper: the requested offset for the // wallpaper; if a wallpaper window: the currently applied offset. float mWallpaperX = -1; @@ -305,6 +294,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { int mAnimDw; int mAnimDh; + final WindowStateAnimator mWinAnimator; + WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState attachedWindow, int seq, WindowManager.LayoutParams a, int viewVisibility) { @@ -333,6 +324,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mBaseLayer = 0; mSubLayer = 0; mInputWindowHandle = null; + mWinAnimator = null; return; } mDeathRecipient = deathRecipient; @@ -369,9 +361,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { mIsFloatingLayer = mIsImWindow || mIsWallpaper; } + mWinAnimator = new WindowStateAnimator(service, this, mAttachedWindow); + WindowState appWin = this; while (appWin.mAttachedWindow != null) { - appWin = mAttachedWindow; + appWin = appWin.mAttachedWindow; } WindowToken appToken = appWin.mToken; while (appToken.appWindowToken == null) { @@ -405,6 +399,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { mSession.windowAddedLocked(); } + @Override public void computeFrameLw(Rect pf, Rect df, Rect cf, Rect vf) { mHaveFrame = true; @@ -547,38 +542,47 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } + @Override public Rect getFrameLw() { return mFrame; } + @Override public RectF getShownFrameLw() { return mShownFrame; } + @Override public Rect getDisplayFrameLw() { return mDisplayFrame; } + @Override public Rect getContentFrameLw() { return mContentFrame; } + @Override public Rect getVisibleFrameLw() { return mVisibleFrame; } + @Override public boolean getGivenInsetsPendingLw() { return mGivenInsetsPending; } + @Override public Rect getGivenContentInsetsLw() { return mGivenContentInsets; } + @Override public Rect getGivenVisibleInsetsLw() { return mGivenVisibleInsets; } + @Override public WindowManager.LayoutParams getAttrs() { return mAttrs; } @@ -632,41 +636,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { return mAppToken != null ? mAppToken.firstWindowDrawn : false; } - public void setAnimation(Animation anim) { - if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Setting animation in " + this + ": " + anim); - mAnimating = false; - mLocalAnimating = false; - mAnimation = anim; - mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); - mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale); - // Start out animation gone if window is gone, or visible if window is visible. - mTransformation.clear(); - mTransformation.setAlpha(mLastHidden ? 0 : 1); - mHasLocalTransformation = true; - } - - public void clearAnimation() { - if (mAnimation != null) { - mAnimating = true; - mLocalAnimating = false; - mAnimation.cancel(); - mAnimation = null; - } - } - - // TODO: Fix and call finishExit() instead of cancelExitAnimationForNextAnimationLocked() - // for avoiding the code duplication. - void cancelExitAnimationForNextAnimationLocked() { - if (!mExiting) return; - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; - destroySurfaceLocked(); - } - mExiting = false; - } - Surface createSurfaceLocked() { if (mSurface == null) { mReportDestroySurface = false; @@ -931,7 +900,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { + (mAppToken != null ? mAppToken.hiddenRequested : false) + " tok.hidden=" + (mAppToken != null ? mAppToken.hidden : false) - + " animating=" + mAnimating + + " animating=" + mWinAnimator.mAnimating + " tok animating=" + (mAppToken != null ? mAppToken.animating : false)); if (!mService.showSurfaceRobustlyLocked(this)) { @@ -978,11 +947,11 @@ final class WindowState implements WindowManagerPolicy.WindowState { // will do an animation to reveal it from behind the // starting window, so there is no need for it to also // be doing its own stuff. - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; + if (mWinAnimator.mAnimation != null) { + mWinAnimator.mAnimation.cancel(); + mWinAnimator.mAnimation = null; // Make sure we clean up the animation. - mAnimating = true; + mWinAnimator.mAnimating = true; } mService.mFinishedStarting.add(mAppToken); mService.mH.sendEmptyMessage(H.FINISHED_STARTING); @@ -995,192 +964,6 @@ final class WindowState implements WindowManagerPolicy.WindowState { return true; } - private boolean stepAnimation(long currentTime) { - if ((mAnimation == null) || !mLocalAnimating) { - return false; - } - mTransformation.clear(); - final boolean more = mAnimation.getTransformation(currentTime, mTransformation); - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Stepped animation in " + this + - ": more=" + more + ", xform=" + mTransformation); - return more; - } - - // This must be called while inside a transaction. Returns true if - // there is more animation to run. - boolean stepAnimationLocked(long currentTime) { - // Save the animation state as it was before this step so WindowManagerService can tell if - // we just started or just stopped animating by comparing mWasAnimating with isAnimating(). - mWasAnimating = mAnimating; - if (mService.okToDisplay()) { - // We will run animations as long as the display isn't frozen. - - if (isDrawnLw() && mAnimation != null) { - mHasTransformation = true; - mHasLocalTransformation = true; - if (!mLocalAnimating) { - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Starting animation in " + this + - " @ " + currentTime + ": ww=" + mFrame.width() + - " wh=" + mFrame.height() + - " dw=" + mAnimDw + " dh=" + mAnimDh + - " scale=" + mService.mWindowAnimationScale); - mAnimation.initialize(mFrame.width(), mFrame.height(), mAnimDw, mAnimDh); - mAnimation.setStartTime(currentTime); - mLocalAnimating = true; - mAnimating = true; - } - if ((mAnimation != null) && mLocalAnimating) { - if (stepAnimation(currentTime)) { - return true; - } - } - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Finished animation in " + this + - " @ " + currentTime); - //WindowManagerService.this.dump(); - } - mHasLocalTransformation = false; - if ((!mLocalAnimating || mAnimationIsEntrance) && mAppToken != null - && mAppToken.animation != null) { - // When our app token is animating, we kind-of pretend like - // we are as well. Note the mLocalAnimating mAnimationIsEntrance - // part of this check means that we will only do this if - // our window is not currently exiting, or it is not - // locally animating itself. The idea being that one that - // is exiting and doing a local animation should be removed - // once that animation is done. - mAnimating = true; - mHasTransformation = true; - mTransformation.clear(); - return false; - } else if (mHasTransformation) { - // Little trick to get through the path below to act like - // we have finished an animation. - mAnimating = true; - } else if (isAnimating()) { - mAnimating = true; - } - } else if (mAnimation != null) { - // If the display is frozen, and there is a pending animation, - // clear it and make sure we run the cleanup code. - mAnimating = true; - mLocalAnimating = true; - mAnimation.cancel(); - mAnimation = null; - } - - if (!mAnimating && !mLocalAnimating) { - return false; - } - - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mExiting - + ", reportedVisible=" - + (mAppToken != null ? mAppToken.reportedVisible : false)); - - mAnimating = false; - mLocalAnimating = false; - if (mAnimation != null) { - mAnimation.cancel(); - mAnimation = null; - } - if (mService.mWindowDetachedWallpaper == this) { - mService.mWindowDetachedWallpaper = null; - } - mAnimLayer = mLayer; - if (mIsImWindow) { - mAnimLayer += mService.mInputMethodAnimLayerAdjustment; - } else if (mIsWallpaper) { - mAnimLayer += mService.mWallpaperAnimLayerAdjustment; - } - if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this - + " anim layer: " + mAnimLayer); - mHasTransformation = false; - mHasLocalTransformation = false; - if (mPolicyVisibility != mPolicyVisibilityAfterAnim) { - if (DEBUG_VISIBILITY) { - Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": " - + mPolicyVisibilityAfterAnim); - } - mPolicyVisibility = mPolicyVisibilityAfterAnim; - mService.mLayoutNeeded = true; - if (!mPolicyVisibility) { - if (mService.mCurrentFocus == this) { - mService.mFocusMayChange = true; - } - // Window is no longer visible -- make sure if we were waiting - // for it to be displayed before enabling the display, that - // we allow the display to be enabled now. - mService.enableScreenIfNeededLocked(); - } - } - mTransformation.clear(); - if (mHasDrawn - && mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING - && mAppToken != null - && mAppToken.firstWindowDrawn - && mAppToken.startingData != null) { - if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting " - + mToken + ": first real window done animating"); - mService.mFinishedStarting.add(mAppToken); - mService.mH.sendEmptyMessage(H.FINISHED_STARTING); - } - - finishExit(); - mService.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; - if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats("WindowState"); - - if (mAppToken != null) { - mAppToken.updateReportedVisibilityLocked(); - } - - return false; - } - - void finishExit() { - if (WindowManagerService.DEBUG_ANIM) Slog.v( - WindowManagerService.TAG, "finishExit in " + this - + ": exiting=" + mExiting - + " remove=" + mRemoveOnExit - + " windowAnimating=" + isWindowAnimating()); - - final int N = mChildWindows.size(); - for (int i=0; i<N; i++) { - mChildWindows.get(i).finishExit(); - } - - if (!mExiting) { - return; - } - - if (isWindowAnimating()) { - return; - } - - if (WindowManagerService.localLOGV) Slog.v( - WindowManagerService.TAG, "Exit animation finished in " + this - + ": remove=" + mRemoveOnExit); - if (mSurface != null) { - mService.mDestroySurface.add(this); - mDestroying = true; - if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(this, "HIDE (finishExit)", null); - mSurfaceShown = false; - try { - mSurface.hide(); - } catch (RuntimeException e) { - Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e); - } - mLastHidden = true; - } - mExiting = false; - if (mRemoveOnExit) { - mService.mPendingRemove.add(this); - mRemoveOnExit = false; - } - } - boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { if (dsdx < .99999f || dsdx > 1.00001f) return false; if (dtdy < .99999f || dtdy > 1.00001f) return false; @@ -1199,10 +982,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { } void computeShownFrameLocked() { - final boolean selfTransformation = mHasLocalTransformation; + final boolean selfTransformation = mWinAnimator.mHasLocalTransformation; Transformation attachedTransformation = - (mAttachedWindow != null && mAttachedWindow.mHasLocalTransformation) - ? mAttachedWindow.mTransformation : null; + (mAttachedWindow != null && mAttachedWindow.mWinAnimator.mHasLocalTransformation) + ? mAttachedWindow.mWinAnimator.mTransformation : null; Transformation appTransformation = (mAppToken != null && mAppToken.hasTransformation) ? mAppToken.transformation : null; @@ -1211,10 +994,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { // are currently targeting. if (mAttrs.type == TYPE_WALLPAPER && mService.mLowerWallpaperTarget == null && mService.mWallpaperTarget != null) { - if (mService.mWallpaperTarget.mHasLocalTransformation && - mService.mWallpaperTarget.mAnimation != null && - !mService.mWallpaperTarget.mAnimation.getDetachWallpaper()) { - attachedTransformation = mService.mWallpaperTarget.mTransformation; + if (mService.mWallpaperTarget.mWinAnimator.mHasLocalTransformation && + mService.mWallpaperTarget.mWinAnimator.mAnimation != null && + !mService.mWallpaperTarget.mWinAnimator.mAnimation.getDetachWallpaper()) { + attachedTransformation = mService.mWallpaperTarget.mWinAnimator.mTransformation; if (WindowManagerService.DEBUG_WALLPAPER && attachedTransformation != null) { Slog.v(WindowManagerService.TAG, "WP target attached xform: " + attachedTransformation); } @@ -1260,7 +1043,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } tmpMatrix.postScale(mGlobalScale, mGlobalScale); if (selfTransformation) { - tmpMatrix.postConcat(mTransformation.getMatrix()); + tmpMatrix.postConcat(mWinAnimator.mTransformation.getMatrix()); } tmpMatrix.postTranslate(frame.left + mXOffset, frame.top + mYOffset); if (attachedTransformation != null) { @@ -1304,7 +1087,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { && x == frame.left && y == frame.top))) { //Slog.i(TAG, "Applying alpha transform"); if (selfTransformation) { - mShownAlpha *= mTransformation.getAlpha(); + mShownAlpha *= mWinAnimator.mTransformation.getAlpha(); } if (attachedTransformation != null) { mShownAlpha *= attachedTransformation.getAlpha(); @@ -1323,7 +1106,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (WindowManagerService.localLOGV) Slog.v( WindowManagerService.TAG, "computeShownFrameLocked: Animating " + this + ": " + mShownFrame + - ", alpha=" + mTransformation.getAlpha() + ", mShownAlpha=" + mShownAlpha); + ", alpha=" + mWinAnimator.mTransformation.getAlpha() + ", mShownAlpha=" + mShownAlpha); return; } @@ -1374,7 +1157,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested) && ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden) - || mAnimation != null || animating); + || mWinAnimator.mAnimation != null || animating); } /** @@ -1431,10 +1214,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (atoken != null) { return mSurface != null && mPolicyVisibility && !mDestroying && ((!mAttachedHidden && !atoken.hiddenRequested) - || mAnimation != null || atoken.animation != null); + || mWinAnimator.mAnimation != null || atoken.animation != null); } else { return mSurface != null && mPolicyVisibility && !mDestroying - && (!mAttachedHidden || mAnimation != null); + && (!mAttachedHidden || mWinAnimator.mAnimation != null); } } @@ -1450,26 +1233,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { return mSurface != null && mPolicyVisibility && !mDestroying && ((!mAttachedHidden && mViewVisibility == View.VISIBLE && !mRootToken.hidden) - || mAnimation != null + || mWinAnimator.mAnimation != null || ((mAppToken != null) && (mAppToken.animation != null))); } - /** Is the window or its container currently animating? */ - boolean isAnimating() { - final WindowState attached = mAttachedWindow; - final AppWindowToken atoken = mAppToken; - return mAnimation != null - || (attached != null && attached.mAnimation != null) - || (atoken != null && - (atoken.animation != null - || atoken.inPendingTransaction)); - } - - /** Is this window currently animating? */ - boolean isWindowAnimating() { - return mAnimation != null; - } - /** * Like isOnScreen, but returns false if the surface hasn't yet * been drawn. @@ -1479,7 +1246,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { return isDrawnLw() && mPolicyVisibility && ((!mAttachedHidden && (atoken == null || !atoken.hiddenRequested)) - || mAnimating); + || mWinAnimator.mAnimating); } public boolean isGoneForLayoutLw() { @@ -1508,7 +1275,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean isOpaqueDrawn() { return (mAttrs.format == PixelFormat.OPAQUE || mAttrs.type == TYPE_WALLPAPER) - && isDrawnLw() && mAnimation == null + && isDrawnLw() && mWinAnimator.mAnimation == null && (mAppToken == null || mAppToken.animation == null); } @@ -1607,10 +1374,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "Policy visibility true: " + this); if (doAnimation) { if (DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "doAnimation: mPolicyVisibility=" - + mPolicyVisibility + " mAnimation=" + mAnimation); + + mPolicyVisibility + " mAnimation=" + mWinAnimator.mAnimation); if (!mService.okToDisplay()) { doAnimation = false; - } else if (mPolicyVisibility && mAnimation == null) { + } else if (mPolicyVisibility && mWinAnimator.mAnimation == null) { // Check for the case where we are currently visible and // not animating; we do not want to do animation at such a // point to become visible when we already are. @@ -1646,7 +1413,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } if (doAnimation) { mService.applyAnimationLocked(this, WindowManagerPolicy.TRANSIT_EXIT, false); - if (mAnimation == null) { + if (mWinAnimator.mAnimation == null) { doAnimation = false; } } @@ -1821,20 +1588,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { pw.print(" last="); mLastVisibleInsets.printShortString(pw); pw.println(); } - if (mAnimating || mLocalAnimating || mAnimationIsEntrance - || mAnimation != null) { - pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating); - pw.print(" mLocalAnimating="); pw.print(mLocalAnimating); - pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance); - pw.print(" mAnimation="); pw.println(mAnimation); - } - if (mHasTransformation || mHasLocalTransformation) { - pw.print(prefix); pw.print("XForm: has="); - pw.print(mHasTransformation); - pw.print(" hasLocal="); pw.print(mHasLocalTransformation); - pw.print(" "); mTransformation.printShortString(pw); - pw.println(); - } + mWinAnimator.dump(pw, prefix, dumpAll); if (mShownAlpha != 1 || mAlpha != 1 || mLastAlpha != 1) { pw.print(prefix); pw.print("mShownAlpha="); pw.print(mShownAlpha); pw.print(" mAlpha="); pw.print(mAlpha); diff --git a/services/java/com/android/server/wm/WindowStateAnimator.java b/services/java/com/android/server/wm/WindowStateAnimator.java new file mode 100644 index 0000000..d86d411 --- /dev/null +++ b/services/java/com/android/server/wm/WindowStateAnimator.java @@ -0,0 +1,298 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package com.android.server.wm; + +import android.util.Slog; +import android.view.WindowManager; +import android.view.WindowManagerPolicy; +import android.view.animation.Animation; +import android.view.animation.Transformation; + +import com.android.server.wm.WindowManagerService.H; + +import java.io.PrintWriter; + +/** + * @author cmautner@google.com (Craig Mautner) + * + */ +class WindowStateAnimator { + + final WindowManagerService mService; + final WindowState mWin; + final WindowState mAttachedWindow; + + // Currently running animation. + boolean mAnimating; + boolean mLocalAnimating; + Animation mAnimation; + boolean mAnimationIsEntrance; + boolean mHasTransformation; + boolean mHasLocalTransformation; + final Transformation mTransformation = new Transformation(); + boolean mWasAnimating; // Were we animating going into the most recent animation step? + + public WindowStateAnimator(final WindowManagerService service, final WindowState win, + final WindowState attachedWindow) { + mService = service; + mWin = win; + mAttachedWindow = attachedWindow; + } + + public void setAnimation(Animation anim) { + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Setting animation in " + this + ": " + anim); + mAnimating = false; + mLocalAnimating = false; + mAnimation = anim; + mAnimation.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); + mAnimation.scaleCurrentDuration(mService.mWindowAnimationScale); + // Start out animation gone if window is gone, or visible if window is visible. + mTransformation.clear(); + mTransformation.setAlpha(mWin.mLastHidden ? 0 : 1); + mHasLocalTransformation = true; + } + + public void clearAnimation() { + if (mAnimation != null) { + mAnimating = true; + mLocalAnimating = false; + mAnimation.cancel(); + mAnimation = null; + } + } + + /** Is the window or its container currently animating? */ + boolean isAnimating() { + final WindowState attached = mAttachedWindow; + final AppWindowToken atoken = mWin.mAppToken; + return mAnimation != null + || (attached != null && attached.mWinAnimator.mAnimation != null) + || (atoken != null && + (atoken.animation != null + || atoken.inPendingTransaction)); + } + + /** Is this window currently animating? */ + boolean isWindowAnimating() { + return mAnimation != null; + } + + // TODO: Fix and call finishExit() instead of cancelExitAnimationForNextAnimationLocked() + // for avoiding the code duplication. + void cancelExitAnimationForNextAnimationLocked() { + if (!mWin.mExiting) return; + if (mAnimation != null) { + mAnimation.cancel(); + mAnimation = null; + mWin.destroySurfaceLocked(); + } + mWin.mExiting = false; + } + + private boolean stepAnimation(long currentTime) { + if ((mAnimation == null) || !mLocalAnimating) { + return false; + } + mTransformation.clear(); + final boolean more = mAnimation.getTransformation(currentTime, mTransformation); + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Stepped animation in " + this + + ": more=" + more + ", xform=" + mTransformation); + return more; + } + + // This must be called while inside a transaction. Returns true if + // there is more animation to run. + boolean stepAnimationLocked(long currentTime) { + // Save the animation state as it was before this step so WindowManagerService can tell if + // we just started or just stopped animating by comparing mWasAnimating with isAnimating(). + mWasAnimating = mAnimating; + if (mService.okToDisplay()) { + // We will run animations as long as the display isn't frozen. + + if (mWin.isDrawnLw() && mAnimation != null) { + mHasTransformation = true; + mHasLocalTransformation = true; + if (!mLocalAnimating) { + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Starting animation in " + this + + " @ " + currentTime + ": ww=" + mWin.mFrame.width() + + " wh=" + mWin.mFrame.height() + + " dw=" + mWin.mAnimDw + " dh=" + mWin.mAnimDh + + " scale=" + mService.mWindowAnimationScale); + mAnimation.initialize(mWin.mFrame.width(), mWin.mFrame.height(), mWin.mAnimDw, + mWin.mAnimDh); + mAnimation.setStartTime(currentTime); + mLocalAnimating = true; + mAnimating = true; + } + if ((mAnimation != null) && mLocalAnimating) { + if (stepAnimation(currentTime)) { + return true; + } + } + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Finished animation in " + this + + " @ " + currentTime); + //WindowManagerService.this.dump(); + } + mHasLocalTransformation = false; + if ((!mLocalAnimating || mAnimationIsEntrance) && mWin.mAppToken != null + && mWin.mAppToken.animation != null) { + // When our app token is animating, we kind-of pretend like + // we are as well. Note the mLocalAnimating mAnimationIsEntrance + // part of this check means that we will only do this if + // our window is not currently exiting, or it is not + // locally animating itself. The idea being that one that + // is exiting and doing a local animation should be removed + // once that animation is done. + mAnimating = true; + mHasTransformation = true; + mTransformation.clear(); + return false; + } else if (mHasTransformation) { + // Little trick to get through the path below to act like + // we have finished an animation. + mAnimating = true; + } else if (isAnimating()) { + mAnimating = true; + } + } else if (mAnimation != null) { + // If the display is frozen, and there is a pending animation, + // clear it and make sure we run the cleanup code. + mAnimating = true; + mLocalAnimating = true; + mAnimation.cancel(); + mAnimation = null; + } + + if (!mAnimating && !mLocalAnimating) { + return false; + } + + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "Animation done in " + this + ": exiting=" + mWin.mExiting + + ", reportedVisible=" + + (mWin.mAppToken != null ? mWin.mAppToken.reportedVisible : false)); + + mAnimating = false; + mLocalAnimating = false; + if (mAnimation != null) { + mAnimation.cancel(); + mAnimation = null; + } + if (mService.mWindowDetachedWallpaper == mWin) { + mService.mWindowDetachedWallpaper = null; + } + mWin.mAnimLayer = mWin.mLayer; + if (mWin.mIsImWindow) { + mWin.mAnimLayer += mService.mInputMethodAnimLayerAdjustment; + } else if (mWin.mIsWallpaper) { + mWin.mAnimLayer += mService.mWallpaperAnimLayerAdjustment; + } + if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Stepping win " + this + + " anim layer: " + mWin.mAnimLayer); + mHasTransformation = false; + mHasLocalTransformation = false; + if (mWin.mPolicyVisibility != mWin.mPolicyVisibilityAfterAnim) { + if (WindowState.DEBUG_VISIBILITY) { + Slog.v(WindowManagerService.TAG, "Policy visibility changing after anim in " + this + ": " + + mWin.mPolicyVisibilityAfterAnim); + } + mWin.mPolicyVisibility = mWin.mPolicyVisibilityAfterAnim; + mService.mLayoutNeeded = true; + if (!mWin.mPolicyVisibility) { + if (mService.mCurrentFocus == mWin) { + mService.mFocusMayChange = true; + } + // Window is no longer visible -- make sure if we were waiting + // for it to be displayed before enabling the display, that + // we allow the display to be enabled now. + mService.enableScreenIfNeededLocked(); + } + } + mTransformation.clear(); + if (mWin.mHasDrawn + && mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING + && mWin.mAppToken != null + && mWin.mAppToken.firstWindowDrawn + && mWin.mAppToken.startingData != null) { + if (WindowManagerService.DEBUG_STARTING_WINDOW) Slog.v(WindowManagerService.TAG, "Finish starting " + + mWin.mToken + ": first real window done animating"); + mService.mFinishedStarting.add(mWin.mAppToken); + mService.mH.sendEmptyMessage(H.FINISHED_STARTING); + } + + finishExit(); + mService.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) mService.debugLayoutRepeats("WindowState"); + + if (mWin.mAppToken != null) { + mWin.mAppToken.updateReportedVisibilityLocked(); + } + + return false; + } + + void finishExit() { + if (WindowManagerService.DEBUG_ANIM) Slog.v( + WindowManagerService.TAG, "finishExit in " + this + + ": exiting=" + mWin.mExiting + + " remove=" + mWin.mRemoveOnExit + + " windowAnimating=" + isWindowAnimating()); + + final int N = mWin.mChildWindows.size(); + for (int i=0; i<N; i++) { + mWin.mChildWindows.get(i).mWinAnimator.finishExit(); + } + + if (!mWin.mExiting) { + return; + } + + if (isWindowAnimating()) { + return; + } + + if (WindowManagerService.localLOGV) Slog.v( + WindowManagerService.TAG, "Exit animation finished in " + this + + ": remove=" + mWin.mRemoveOnExit); + if (mWin.mSurface != null) { + mService.mDestroySurface.add(mWin); + mWin.mDestroying = true; + if (WindowState.SHOW_TRANSACTIONS) WindowManagerService.logSurface( + mWin, "HIDE (finishExit)", null); + mWin.mSurfaceShown = false; + try { + mWin.mSurface.hide(); + } catch (RuntimeException e) { + Slog.w(WindowManagerService.TAG, "Error hiding surface in " + this, e); + } + mWin.mLastHidden = true; + } + mWin.mExiting = false; + if (mWin.mRemoveOnExit) { + mService.mPendingRemove.add(mWin); + mWin.mRemoveOnExit = false; + } + } + + public void dump(PrintWriter pw, String prefix, boolean dumpAll) { + if (mAnimating || mLocalAnimating || mAnimationIsEntrance + || mAnimation != null) { + pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating); + pw.print(" mLocalAnimating="); pw.print(mLocalAnimating); + pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance); + pw.print(" mAnimation="); pw.println(mAnimation); + } + if (mHasTransformation || mHasLocalTransformation) { + pw.print(prefix); pw.print("XForm: has="); + pw.print(mHasTransformation); + pw.print(" hasLocal="); pw.print(mHasLocalTransformation); + pw.print(" "); mTransformation.printShortString(pw); + pw.println(); + } + } + +} diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index e8188e7..d736ac1 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -54,7 +54,7 @@ public class UserManagerTest extends AndroidTestCase { public void testAddUser() throws Exception { final UserManager details = mUserManager; - UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null); + UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST); assertTrue(userInfo != null); List<UserInfo> list = details.getUsers(); @@ -73,8 +73,8 @@ public class UserManagerTest extends AndroidTestCase { public void testAdd2Users() throws Exception { final UserManager details = mUserManager; - UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null); - UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN, null); + UserInfo user1 = details.createUser("Guest 1", UserInfo.FLAG_GUEST); + UserInfo user2 = details.createUser("User 2", UserInfo.FLAG_ADMIN); assertTrue(user1 != null); assertTrue(user2 != null); @@ -87,7 +87,7 @@ public class UserManagerTest extends AndroidTestCase { public void testRemoveUser() throws Exception { final UserManager details = mUserManager; - UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST, null); + UserInfo userInfo = details.createUser("Guest 1", UserInfo.FLAG_GUEST); details.removeUser(userInfo.id); |