diff options
Diffstat (limited to 'services/java/com/android')
28 files changed, 3262 insertions, 2063 deletions
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 081f1f4..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() { @@ -325,9 +328,10 @@ class AppWidgetService extends IAppWidgetService.Stub service.onConfigurationChanged(); } } else { - // TODO: Verify that this only needs to be delivered for the related user and not - // all the users - getImplForUser().onBroadcastReceived(intent); + for (int i = 0; i < mAppWidgetServices.size(); i++) { + AppWidgetServiceImpl service = mAppWidgetServices.valueAt(i); + service.onBroadcastReceived(intent); + } } } }; diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java index 9c408c4..b24823e 100644 --- a/services/java/com/android/server/AppWidgetServiceImpl.java +++ b/services/java/com/android/server/AppWidgetServiceImpl.java @@ -17,6 +17,7 @@ package com.android.server; import android.app.AlarmManager; +import android.app.AppGlobals; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProviderInfo; @@ -27,6 +28,7 @@ import android.content.ServiceConnection; import android.content.Intent.FilterComparison; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; +import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; @@ -158,7 +160,7 @@ class AppWidgetServiceImpl { Context mContext; Locale mLocale; - PackageManager mPackageManager; + IPackageManager mPm; AlarmManager mAlarmManager; ArrayList<Provider> mInstalledProviders = new ArrayList<Provider>(); int mNextAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID + 1; @@ -174,7 +176,7 @@ class AppWidgetServiceImpl { AppWidgetServiceImpl(Context context, int userId) { mContext = context; - mPackageManager = context.getPackageManager(); + mPm = AppGlobals.getPackageManager(); mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); mUserId = userId; } @@ -1009,16 +1011,19 @@ class AppWidgetServiceImpl { } void loadAppWidgetList() { - PackageManager pm = mPackageManager; - Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); - List<ResolveInfo> broadcastReceivers = pm.queryBroadcastReceivers(intent, - PackageManager.GET_META_DATA); + try { + List<ResolveInfo> broadcastReceivers = mPm.queryIntentReceivers(intent, + intent.resolveTypeIfNeeded(mContext.getContentResolver()), + PackageManager.GET_META_DATA, mUserId); - final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); - for (int i = 0; i < N; i++) { - ResolveInfo ri = broadcastReceivers.get(i); - addProviderLocked(ri); + final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); + for (int i = 0; i < N; i++) { + ResolveInfo ri = broadcastReceivers.get(i); + addProviderLocked(ri); + } + } catch (RemoteException re) { + // Shouldn't happen, local call } } @@ -1131,7 +1136,7 @@ class AppWidgetServiceImpl { ActivityInfo activityInfo = ri.activityInfo; XmlResourceParser parser = null; try { - parser = activityInfo.loadXmlMetaData(mPackageManager, + parser = activityInfo.loadXmlMetaData(mContext.getPackageManager(), AppWidgetManager.META_DATA_APPWIDGET_PROVIDER); if (parser == null) { Slog.w(TAG, "No " + AppWidgetManager.META_DATA_APPWIDGET_PROVIDER @@ -1159,7 +1164,7 @@ class AppWidgetServiceImpl { info.provider = component; p.uid = activityInfo.applicationInfo.uid; - Resources res = mPackageManager + Resources res = mContext.getPackageManager() .getResourcesForApplication(activityInfo.applicationInfo); TypedArray sa = res.obtainAttributes(attrs, @@ -1188,7 +1193,7 @@ class AppWidgetServiceImpl { if (className != null) { info.configure = new ComponentName(component.getPackageName(), className); } - info.label = activityInfo.loadLabel(mPackageManager).toString(); + info.label = activityInfo.loadLabel(mContext.getPackageManager()).toString(); info.icon = ri.getIconResource(); info.previewImage = sa.getResourceId( com.android.internal.R.styleable.AppWidgetProviderInfo_previewImage, 0); @@ -1213,7 +1218,12 @@ class AppWidgetServiceImpl { } int getUidForPackage(String packageName) throws PackageManager.NameNotFoundException { - PackageInfo pkgInfo = mPackageManager.getPackageInfo(packageName, 0); + PackageInfo pkgInfo = null; + try { + pkgInfo = mPm.getPackageInfo(packageName, 0, mUserId); + } catch (RemoteException re) { + // Shouldn't happen, local call + } if (pkgInfo == null || pkgInfo.applicationInfo == null) { throw new PackageManager.NameNotFoundException(); } @@ -1474,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) { @@ -1490,12 +1504,28 @@ 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); - List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, - PackageManager.GET_META_DATA); - + List<ResolveInfo> broadcastReceivers; + try { + broadcastReceivers = mPm.queryIntentReceivers(intent, + intent.resolveTypeIfNeeded(mContext.getContentResolver()), + PackageManager.GET_META_DATA, mUserId); + } catch (RemoteException re) { + // Shouldn't happen, local call + return; + } final int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); for (int i = 0; i < N; i++) { ResolveInfo ri = broadcastReceivers.get(i); @@ -1513,8 +1543,15 @@ class AppWidgetServiceImpl { HashSet<String> keep = new HashSet<String>(); Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.setPackage(pkgName); - List<ResolveInfo> broadcastReceivers = mPackageManager.queryBroadcastReceivers(intent, - PackageManager.GET_META_DATA); + List<ResolveInfo> broadcastReceivers; + try { + broadcastReceivers = mPm.queryIntentReceivers(intent, + intent.resolveTypeIfNeeded(mContext.getContentResolver()), + PackageManager.GET_META_DATA, mUserId); + } catch (RemoteException re) { + // Shouldn't happen, local call + return; + } // add the missing ones and collect which ones to keep int N = broadcastReceivers == null ? 0 : broadcastReceivers.size(); diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index a7b08f5..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) { @@ -1986,6 +1937,16 @@ class BackupManagerService extends IBackupManager.Stub { try { mCurrentPackage = mPackageManager.getPackageInfo(request.packageName, PackageManager.GET_SIGNATURES); + if (mCurrentPackage.applicationInfo.backupAgentName == null) { + // The manifest has changed but we had a stale backup request pending. + // This won't happen again because the app won't be requesting further + // backups. + Slog.i(TAG, "Package " + request.packageName + + " no longer supports backup; skipping"); + addBackupTrace("skipping - no agent, completion is noop"); + executeNextState(BackupState.RUNNING_QUEUE); + return; + } IBackupAgent agent = null; try { @@ -2547,6 +2508,8 @@ class BackupManagerService extends IBackupManager.Stub { finalizeBackup(out); } catch (RemoteException e) { Slog.e(TAG, "App died during full backup"); + } catch (Exception e) { + Slog.e(TAG, "Internal exception during full backup", e); } finally { tearDown(pkg); try { @@ -4681,6 +4644,8 @@ class BackupManagerService extends IBackupManager.Stub { mTransport.clearBackupData(mPackage); } catch (RemoteException e) { // can't happen; the transport is local + } catch (Exception e) { + Slog.e(TAG, "Transport threw attempting to clear data for " + mPackage); } finally { try { // TODO - need to handle failures @@ -4758,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. @@ -4776,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); } } } @@ -4805,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(), @@ -4817,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); } @@ -4848,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()); @@ -4875,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()); @@ -4883,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); } } } @@ -5824,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/BootReceiver.java b/services/java/com/android/server/BootReceiver.java index da65438..22874e6 100644 --- a/services/java/com/android/server/BootReceiver.java +++ b/services/java/com/android/server/BootReceiver.java @@ -20,13 +20,13 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; -import android.net.Downloads; import android.os.Build; import android.os.DropBoxManager; import android.os.FileObserver; import android.os.FileUtils; import android.os.RecoverySystem; import android.os.SystemProperties; +import android.provider.Downloads; import android.util.Slog; import java.io.File; @@ -78,9 +78,8 @@ public class BootReceiver extends BroadcastReceiver { }.start(); } - private void removeOldUpdatePackages(Context ctx) { - Downloads.ByUri.removeAllDownloadsByPackage( - ctx, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS); + private void removeOldUpdatePackages(Context context) { + Downloads.removeAllDownloadsByPackage(context, OLD_UPDATER_PACKAGE, OLD_UPDATER_CLASS); } private void logBootEvents(Context ctx) throws IOException { 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/IntentResolver.java b/services/java/com/android/server/IntentResolver.java index b3d7220..f7e841e 100644 --- a/services/java/com/android/server/IntentResolver.java +++ b/services/java/com/android/server/IntentResolver.java @@ -201,7 +201,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { } public List<R> queryIntentFromList(Intent intent, String resolvedType, - boolean defaultOnly, ArrayList<ArrayList<F>> listCut) { + boolean defaultOnly, ArrayList<ArrayList<F>> listCut, int userId) { ArrayList<R> resultList = new ArrayList<R>(); final boolean debug = localLOGV || @@ -212,13 +212,14 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { int N = listCut.size(); for (int i = 0; i < N; ++i) { buildResolveList(intent, categories, debug, defaultOnly, - resolvedType, scheme, listCut.get(i), resultList); + resolvedType, scheme, listCut.get(i), resultList, userId); } sortResults(resultList); return resultList; } - public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly) { + public List<R> queryIntent(Intent intent, String resolvedType, boolean defaultOnly, + int userId) { String scheme = intent.getScheme(); ArrayList<R> finalList = new ArrayList<R>(); @@ -290,19 +291,19 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { FastImmutableArraySet<String> categories = getFastIntentCategories(intent); if (firstTypeCut != null) { buildResolveList(intent, categories, debug, defaultOnly, - resolvedType, scheme, firstTypeCut, finalList); + resolvedType, scheme, firstTypeCut, finalList, userId); } if (secondTypeCut != null) { buildResolveList(intent, categories, debug, defaultOnly, - resolvedType, scheme, secondTypeCut, finalList); + resolvedType, scheme, secondTypeCut, finalList, userId); } if (thirdTypeCut != null) { buildResolveList(intent, categories, debug, defaultOnly, - resolvedType, scheme, thirdTypeCut, finalList); + resolvedType, scheme, thirdTypeCut, finalList, userId); } if (schemeCut != null) { buildResolveList(intent, categories, debug, defaultOnly, - resolvedType, scheme, schemeCut, finalList); + resolvedType, scheme, schemeCut, finalList, userId); } sortResults(finalList); @@ -329,7 +330,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { * "stopped," that is whether it should not be included in the result * if the intent requests to excluded stopped objects. */ - protected boolean isFilterStopped(F filter) { + protected boolean isFilterStopped(F filter, int userId) { return false; } @@ -341,7 +342,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { protected abstract String packageForFilter(F filter); @SuppressWarnings("unchecked") - protected R newResult(F filter, int match) { + protected R newResult(F filter, int match, int userId) { return (R)filter; } @@ -504,7 +505,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { private void buildResolveList(Intent intent, FastImmutableArraySet<String> categories, boolean debug, boolean defaultOnly, - String resolvedType, String scheme, List<F> src, List<R> dest) { + String resolvedType, String scheme, List<F> src, List<R> dest, int userId) { final String action = intent.getAction(); final Uri data = intent.getData(); final String packageName = intent.getPackage(); @@ -519,7 +520,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { int match; if (debug) Slog.v(TAG, "Matching against filter " + filter); - if (excludingStopped && isFilterStopped(filter)) { + if (excludingStopped && isFilterStopped(filter, userId)) { if (debug) { Slog.v(TAG, " Filter's target is stopped; skipping"); } @@ -547,7 +548,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { if (debug) Slog.v(TAG, " Filter matched! match=0x" + Integer.toHexString(match)); if (!defaultOnly || filter.hasCategory(Intent.CATEGORY_DEFAULT)) { - final R oneResult = newResult(filter, match); + final R oneResult = newResult(filter, match, userId); if (oneResult != null) { dest.add(oneResult); } diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 366160b..510bdb2 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -48,6 +48,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; +import android.os.UserId; import android.os.storage.IMountService; import android.os.storage.IMountServiceListener; import android.os.storage.IMountShutdownObserver; @@ -1674,7 +1675,7 @@ class MountService extends IMountService.Stub return false; } - final int packageUid = mPms.getPackageUid(packageName); + final int packageUid = mPms.getPackageUid(packageName, UserId.getUserId(callerUid)); if (DEBUG_OBB) { Slog.d(TAG, "packageName = " + packageName + ", packageUid = " + 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 326b940..9b4eddc 100644 --- a/services/java/com/android/server/WiredAccessoryObserver.java +++ b/services/java/com/android/server/WiredAccessoryObserver.java @@ -30,8 +30,11 @@ import android.util.Slog; import android.media.AudioManager; import android.util.Log; +import java.io.File; import java.io.FileReader; import java.io.FileNotFoundException; +import java.util.ArrayList; +import java.util.List; /** * <p>WiredAccessoryObserver monitors for a wired headset on the main board or dock. @@ -39,17 +42,6 @@ import java.io.FileNotFoundException; class WiredAccessoryObserver extends UEventObserver { private static final String TAG = WiredAccessoryObserver.class.getSimpleName(); private static final boolean LOG = true; - private static final int MAX_AUDIO_PORTS = 3; /* h2w, USB Audio & hdmi */ - private static final String uEventInfo[][] = { {"DEVPATH=/devices/virtual/switch/h2w", - "/sys/class/switch/h2w/state", - "/sys/class/switch/h2w/name"}, - {"DEVPATH=/devices/virtual/switch/usb_audio", - "/sys/class/switch/usb_audio/state", - "/sys/class/switch/usb_audio/name"}, - {"DEVPATH=/devices/virtual/switch/hdmi", - "/sys/class/switch/hdmi/state", - "/sys/class/switch/hdmi/name"} }; - private static final int BIT_HEADSET = (1 << 0); private static final int BIT_HEADSET_NO_MIC = (1 << 1); private static final int BIT_USB_HEADSET_ANLG = (1 << 2); @@ -60,10 +52,89 @@ class WiredAccessoryObserver extends UEventObserver { BIT_HDMI_AUDIO); private static final int HEADSETS_WITH_MIC = BIT_HEADSET; + private static class UEventInfo { + private final String mDevName; + private final int mState1Bits; + private final int mState2Bits; + + public UEventInfo(String devName, int state1Bits, int state2Bits) { + mDevName = devName; + mState1Bits = state1Bits; + mState2Bits = state2Bits; + } + + public String getDevName() { return mDevName; } + + public String getDevPath() { + return String.format("/devices/virtual/switch/%s", mDevName); + } + + public String getSwitchStatePath() { + return String.format("/sys/class/switch/%s/state", mDevName); + } + + public boolean checkSwitchExists() { + File f = new File(getSwitchStatePath()); + return ((null != f) && f.exists()); + } + + public int computeNewHeadsetState(int headsetState, int switchState) { + int preserveMask = ~(mState1Bits | mState2Bits); + int setBits = ((switchState == 1) ? mState1Bits : + ((switchState == 2) ? mState2Bits : 0)); + + return ((headsetState & preserveMask) | setBits); + } + } + + private static List<UEventInfo> makeObservedUEventList() { + List<UEventInfo> retVal = new ArrayList<UEventInfo>(); + UEventInfo uei; + + // Monitor h2w + uei = new UEventInfo("h2w", BIT_HEADSET, BIT_HEADSET_NO_MIC); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have wired headset support"); + } + + // Monitor USB + uei = new UEventInfo("usb_audio", BIT_USB_HEADSET_ANLG, BIT_USB_HEADSET_DGTL); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have usb audio support"); + } + + // Monitor HDMI + // + // If the kernel has support for the "hdmi_audio" switch, use that. It will be signalled + // only when the HDMI driver has a video mode configured, and the downstream sink indicates + // support for audio in its EDID. + // + // If the kernel does not have an "hdmi_audio" switch, just fall back on the older "hdmi" + // switch instead. + uei = new UEventInfo("hdmi_audio", BIT_HDMI_AUDIO, 0); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + uei = new UEventInfo("hdmi", BIT_HDMI_AUDIO, 0); + if (uei.checkSwitchExists()) { + retVal.add(uei); + } else { + Slog.w(TAG, "This kernel does not have HDMI audio support"); + } + } + + return retVal; + } + + private static List<UEventInfo> uEventInfo = makeObservedUEventList(); + private int mHeadsetState; private int mPrevHeadsetState; private String mHeadsetName; - private int switchState; private final Context mContext; private final WakeLock mWakeLock; // held while there is a pending route change @@ -85,71 +156,60 @@ class WiredAccessoryObserver extends UEventObserver { // one on the board, one on the dock and one on HDMI: // observe three UEVENTs init(); // set initial status - for (int i = 0; i < MAX_AUDIO_PORTS; i++) { - startObserving(uEventInfo[i][0]); + for (int i = 0; i < uEventInfo.size(); ++i) { + UEventInfo uei = uEventInfo.get(i); + startObserving("DEVPATH="+uei.getDevPath()); } } - } + } @Override public void onUEvent(UEventObserver.UEvent event) { 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) { - if (name.equals("usb_audio")) { - switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC|BIT_HDMI_AUDIO)) | - ((state == 1) ? BIT_USB_HEADSET_ANLG : - ((state == 2) ? BIT_USB_HEADSET_DGTL : 0))); - } else if (name.equals("hdmi")) { - switchState = ((mHeadsetState & (BIT_HEADSET|BIT_HEADSET_NO_MIC| - BIT_USB_HEADSET_DGTL|BIT_USB_HEADSET_ANLG)) | - ((state == 1) ? BIT_HDMI_AUDIO : 0)); - } else { - switchState = ((mHeadsetState & (BIT_HDMI_AUDIO|BIT_USB_HEADSET_ANLG| - BIT_USB_HEADSET_DGTL)) | - ((state == 1) ? BIT_HEADSET : - ((state == 2) ? BIT_HEADSET_NO_MIC : 0))); + for (int i = 0; i < uEventInfo.size(); ++i) { + UEventInfo uei = uEventInfo.get(i); + if (devPath.equals(uei.getDevPath())) { + update(name, uei.computeNewHeadsetState(mHeadsetState, state)); + return; + } } - update(name, switchState); } private synchronized final void init() { char[] buffer = new char[1024]; - - String newName = mHeadsetName; - int newState = mHeadsetState; mPrevHeadsetState = mHeadsetState; if (LOG) Slog.v(TAG, "init()"); - for (int i = 0; i < MAX_AUDIO_PORTS; i++) { + for (int i = 0; i < uEventInfo.size(); ++i) { + UEventInfo uei = uEventInfo.get(i); try { - FileReader file = new FileReader(uEventInfo[i][1]); + int curState; + FileReader file = new FileReader(uei.getSwitchStatePath()); int len = file.read(buffer, 0, 1024); file.close(); - newState = Integer.valueOf((new String(buffer, 0, len)).trim()); - - file = new FileReader(uEventInfo[i][2]); - len = file.read(buffer, 0, 1024); - file.close(); - newName = new String(buffer, 0, len).trim(); + curState = Integer.valueOf((new String(buffer, 0, len)).trim()); - if (newState > 0) { - updateState(newName, newState); + if (curState > 0) { + updateState(uei.getDevPath(), uei.getDevName(), curState); } } catch (FileNotFoundException e) { - Slog.w(TAG, "This kernel does not have wired headset support"); + Slog.w(TAG, uei.getSwitchStatePath() + + " not found while attempting to determine initial switch state"); } catch (Exception e) { Slog.e(TAG, "" , e); } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index d21212f..78f17bc 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -34,6 +34,7 @@ import dalvik.system.Zygote; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerNative; +import android.app.ActivityOptions; import android.app.ActivityThread; import android.app.AlertDialog; import android.app.AppGlobals; @@ -151,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; @@ -1079,7 +1081,8 @@ public final class ActivityManagerService extends ActivityManagerNative int uid = msg.arg1; boolean restart = (msg.arg2 == 1); String pkg = (String) msg.obj; - forceStopPackageLocked(pkg, uid, restart, false, true, false); + forceStopPackageLocked(pkg, uid, restart, false, true, false, + UserId.getUserId(uid)); } } break; case FINALIZE_PENDING_INTENT_MSG: { @@ -1289,7 +1292,7 @@ public final class ActivityManagerService extends ActivityManagerNative ApplicationInfo info = mSelf.mContext.getPackageManager().getApplicationInfo( - "android", STOCK_PM_FLAGS); + "android", STOCK_PM_FLAGS); mSystemThread.installSystemApplicationInfo(info); synchronized (mSelf) { @@ -2352,10 +2355,12 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { ActivityRecord r = mMainStack.isInStackLocked(callingActivity); if (r == null) { + ActivityOptions.abort(options); return false; } if (r.app == null || r.app.thread == null) { // The caller is not running... d'oh! + ActivityOptions.abort(options); return false; } intent = new Intent(intent); @@ -2369,7 +2374,8 @@ public final class ActivityManagerService extends ActivityManagerNative List<ResolveInfo> resolves = AppGlobals.getPackageManager().queryIntentActivities( intent, r.resolvedType, - PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS); + PackageManager.MATCH_DEFAULT_ONLY | STOCK_PM_FLAGS, + UserId.getCallingUserId()); // Look for the original activity in the list... final int N = resolves != null ? resolves.size() : 0; @@ -2391,6 +2397,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (aInfo == null) { // Nobody who is next! + ActivityOptions.abort(options); return false; } @@ -2420,8 +2427,6 @@ public final class ActivityManagerService extends ActivityManagerNative } final long origId = Binder.clearCallingIdentity(); - // XXX we are not dealing with propagating grantedUriPermissions... - // those are not yet exposed to user code, so there is no need. int res = mMainStack.startActivityLocked(r.app.thread, intent, r.resolvedType, aInfo, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1, r.launchedFromUid, 0, @@ -3034,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); @@ -3291,7 +3296,7 @@ public final class ActivityManagerService extends ActivityManagerNative int pkgUid = -1; synchronized(this) { try { - pkgUid = pm.getPackageUid(packageName); + pkgUid = pm.getPackageUid(packageName, userId); } catch (RemoteException e) { } if (pkgUid == -1) { @@ -3312,7 +3317,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { //clear application user data - pm.clearApplicationUserData(packageName, observer); + pm.clearApplicationUserData(packageName, observer, userId); Intent intent = new Intent(Intent.ACTION_PACKAGE_DATA_CLEARED, Uri.fromParts("package", packageName, null)); intent.putExtra(Intent.EXTRA_UID, pkgUid); @@ -3339,13 +3344,14 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException(msg); } + int userId = UserId.getCallingUserId(); long callingId = Binder.clearCallingIdentity(); try { IPackageManager pm = AppGlobals.getPackageManager(); int pkgUid = -1; synchronized(this) { try { - pkgUid = pm.getPackageUid(packageName); + pkgUid = pm.getPackageUid(packageName, userId); } catch (RemoteException e) { } if (pkgUid == -1) { @@ -3412,16 +3418,14 @@ public final class ActivityManagerService extends ActivityManagerNative Slog.w(TAG, msg); throw new SecurityException(msg); } - final int userId = Binder.getOrigCallingUser(); + final int userId = UserId.getCallingUserId(); long callingId = Binder.clearCallingIdentity(); try { IPackageManager pm = AppGlobals.getPackageManager(); int pkgUid = -1; synchronized(this) { try { - pkgUid = pm.getPackageUid(packageName); - // Convert the uid to the one for the calling user - pkgUid = UserId.getUid(userId, pkgUid); + pkgUid = pm.getPackageUid(packageName, userId); } catch (RemoteException e) { } if (pkgUid == -1) { @@ -3430,7 +3434,7 @@ public final class ActivityManagerService extends ActivityManagerNative } forceStopPackageLocked(packageName, pkgUid); try { - pm.setPackageStoppedState(packageName, true); + pm.setPackageStoppedState(packageName, true, userId); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " @@ -3545,7 +3549,7 @@ public final class ActivityManagerService extends ActivityManagerNative } private void forceStopPackageLocked(final String packageName, int uid) { - forceStopPackageLocked(packageName, uid, false, false, true, false); + forceStopPackageLocked(packageName, uid, false, false, true, false, UserId.getUserId(uid)); Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, Uri.fromParts("package", packageName, null)); if (!mProcessesReady) { @@ -3579,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; @@ -3602,13 +3611,13 @@ public final class ActivityManagerService extends ActivityManagerNative private final boolean forceStopPackageLocked(String name, int uid, boolean callerWillRestart, boolean purgeCache, boolean doit, - boolean evenPersistent) { + boolean evenPersistent, int userId) { int i; int N; if (uid < 0) { try { - uid = AppGlobals.getPackageManager().getPackageUid(name); + uid = AppGlobals.getPackageManager().getPackageUid(name, userId); } catch (RemoteException e) { } } @@ -3632,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) { @@ -3652,14 +3662,13 @@ public final class ActivityManagerService extends ActivityManagerNative } lastTask = r.task; if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED, - null, "force-stop")) { + null, "force-stop", true)) { i--; } } } ArrayList<ServiceRecord> services = new ArrayList<ServiceRecord>(); - int userId = UserId.getUserId(uid); for (ServiceRecord service : mServiceMap.getAllServices(userId)) { if (service.packageName.equals(name) && (service.app == null || evenPersistent || !service.app.persistent)) { @@ -3683,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) { @@ -4107,16 +4116,25 @@ public final class ActivityManagerService extends ActivityManagerNative if (pkgs != null) { for (String pkg : pkgs) { synchronized (ActivityManagerService.this) { - if (forceStopPackageLocked(pkg, -1, false, false, false, false)) { - setResultCode(Activity.RESULT_OK); - return; - } - } + if (forceStopPackageLocked(pkg, -1, false, false, false, false, 0)) { + setResultCode(Activity.RESULT_OK); + return; + } + } } } } }, 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. @@ -4290,8 +4308,8 @@ public final class ActivityManagerService extends ActivityManagerNative try { if (callingUid != 0 && callingUid != Process.SYSTEM_UID) { int uid = AppGlobals.getPackageManager() - .getPackageUid(packageName); - if (UserId.getAppId(callingUid) != uid) { + .getPackageUid(packageName, UserId.getUserId(callingUid)); + if (!UserId.isSameApp(callingUid, uid)) { String msg = "Permission Denial: getIntentSender() from pid=" + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid() @@ -4386,7 +4404,7 @@ public final class ActivityManagerService extends ActivityManagerNative PendingIntentRecord rec = (PendingIntentRecord)sender; try { int uid = AppGlobals.getPackageManager() - .getPackageUid(rec.key.packageName); + .getPackageUid(rec.key.packageName, UserId.getCallingUserId()); if (!UserId.isSameApp(uid, Binder.getCallingUid())) { String msg = "Permission Denial: cancelIntentSender() from pid=" + Binder.getCallingPid() @@ -4796,7 +4814,7 @@ public final class ActivityManagerService extends ActivityManagerNative } else { try { pi = pm.resolveContentProvider(name, - PackageManager.GET_URI_PERMISSION_PATTERNS); + PackageManager.GET_URI_PERMISSION_PATTERNS, UserId.getUserId(callingUid)); } catch (RemoteException ex) { } } @@ -4808,7 +4826,7 @@ public final class ActivityManagerService extends ActivityManagerNative int targetUid = lastTargetUid; if (targetUid < 0 && targetPkg != null) { try { - targetUid = pm.getPackageUid(targetPkg); + targetUid = pm.getPackageUid(targetPkg, UserId.getUserId(callingUid)); if (targetUid < 0) { if (DEBUG_URI_PERMISSION) Slog.v(TAG, "Can't grant URI permission no uid for: " + targetPkg); @@ -5100,14 +5118,14 @@ public final class ActivityManagerService extends ActivityManagerNative final String authority = uri.getAuthority(); ProviderInfo pi = null; - ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, - UserId.getUserId(callingUid)); + int userId = UserId.getUserId(callingUid); + ContentProviderRecord cpr = mProviderMap.getProviderByName(authority, userId); if (cpr != null) { pi = cpr.info; } else { try { pi = pm.resolveContentProvider(authority, - PackageManager.GET_URI_PERMISSION_PATTERNS); + PackageManager.GET_URI_PERMISSION_PATTERNS, userId); } catch (RemoteException ex) { } } @@ -5202,7 +5220,7 @@ public final class ActivityManagerService extends ActivityManagerNative } else { try { pi = pm.resolveContentProvider(authority, - PackageManager.GET_URI_PERMISSION_PATTERNS); + PackageManager.GET_URI_PERMISSION_PATTERNS, r.userId); } catch (RemoteException ex) { } } @@ -5480,12 +5498,13 @@ public final class ActivityManagerService extends ActivityManagerNative // Check whether this activity is currently available. try { if (rti.origActivity != null) { - if (pm.getActivityInfo(rti.origActivity, 0) == null) { + if (pm.getActivityInfo(rti.origActivity, 0, callingUserId) + == null) { continue; } } else if (rti.baseIntent != null) { if (pm.queryIntentActivities(rti.baseIntent, - null, 0) == null) { + null, 0, callingUserId) == null) { continue; } } @@ -5685,13 +5704,14 @@ public final class ActivityManagerService extends ActivityManagerNative /** * TODO: Add mController hook */ - public void moveTaskToFront(int task, int flags) { + public void moveTaskToFront(int task, int flags, Bundle options) { enforceCallingPermission(android.Manifest.permission.REORDER_TASKS, "moveTaskToFront()"); synchronized(this) { if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), Binder.getCallingUid(), "Task to front")) { + ActivityOptions.abort(options); return; } final long origId = Binder.clearCallingIdentity(); @@ -5706,7 +5726,7 @@ public final class ActivityManagerService extends ActivityManagerNative // we'll just move the home task to the top first. mMainStack.moveHomeToFrontLocked(); } - mMainStack.moveTaskToFrontLocked(tr, null); + mMainStack.moveTaskToFrontLocked(tr, null, options); return; } for (int i=mMainStack.mHistory.size()-1; i>=0; i--) { @@ -5720,13 +5740,14 @@ public final class ActivityManagerService extends ActivityManagerNative // we'll just move the home task to the top first. mMainStack.moveHomeToFrontLocked(); } - mMainStack.moveTaskToFrontLocked(hr.task, null); + mMainStack.moveTaskToFrontLocked(hr.task, null, options); return; } } } finally { Binder.restoreCallingIdentity(origId); } + ActivityOptions.abort(options); } } @@ -6132,15 +6153,14 @@ public final class ActivityManagerService extends ActivityManagerNative try { cpi = AppGlobals.getPackageManager(). resolveContentProvider(name, - STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS); + STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS, userId); } catch (RemoteException ex) { } if (cpi == null) { return null; } - cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, - Binder.getOrigCallingUser()); + cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId); String msg; if ((msg=checkContentProviderPermissionLocked(cpi, r)) != null) { @@ -6157,7 +6177,7 @@ public final class ActivityManagerService extends ActivityManagerNative } ComponentName comp = new ComponentName(cpi.packageName, cpi.name); - cpr = mProviderMap.getProviderByClass(comp, Binder.getOrigCallingUser()); + cpr = mProviderMap.getProviderByClass(comp, userId); final boolean firstClass = cpr == null; if (firstClass) { try { @@ -6165,13 +6185,13 @@ public final class ActivityManagerService extends ActivityManagerNative AppGlobals.getPackageManager(). getApplicationInfo( cpi.applicationInfo.packageName, - STOCK_PM_FLAGS); + STOCK_PM_FLAGS, userId); if (ai == null) { Slog.w(TAG, "No package info for content provider " + cpi.name); return null; } - ai = getAppInfoForUser(ai, Binder.getOrigCallingUser()); + ai = getAppInfoForUser(ai, userId); cpr = new ContentProviderRecord(this, cpi, ai, comp); } catch (RemoteException ex) { // pm is in same process, this will never happen. @@ -6212,7 +6232,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Content provider is now in use, its package can't be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( - cpr.appInfo.packageName, false); + cpr.appInfo.packageName, false, userId); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " @@ -6546,7 +6566,7 @@ public final class ActivityManagerService extends ActivityManagerNative // This package really, really can not be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( - info.packageName, false); + info.packageName, false, UserId.getUserId(app.uid)); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " @@ -6778,7 +6798,7 @@ public final class ActivityManagerService extends ActivityManagerNative mDebugTransient = !persistent; if (packageName != null) { final long origId = Binder.clearCallingIdentity(); - forceStopPackageLocked(packageName, -1, false, false, true, true); + forceStopPackageLocked(packageName, -1, false, false, true, true, 0); Binder.restoreCallingIdentity(origId); } } @@ -6993,7 +7013,43 @@ public final class ActivityManagerService extends ActivityManagerNative } return killed; } - + + @Override + public boolean killProcessesBelowForeground(String reason) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("killProcessesBelowForeground() only available to system"); + } + + return killProcessesBelowAdj(ProcessList.FOREGROUND_APP_ADJ, reason); + } + + private boolean killProcessesBelowAdj(int belowAdj, String reason) { + if (Binder.getCallingUid() != Process.SYSTEM_UID) { + throw new SecurityException("killProcessesBelowAdj() only available to system"); + } + + boolean killed = false; + synchronized (mPidsSelfLocked) { + final int size = mPidsSelfLocked.size(); + for (int i = 0; i < size; i++) { + final int pid = mPidsSelfLocked.keyAt(i); + final ProcessRecord proc = mPidsSelfLocked.valueAt(i); + if (proc == null) continue; + + final int adj = proc.setAdj; + if (adj > belowAdj && !proc.killedBackground) { + Slog.w(TAG, "Killing " + proc + " (adj " + adj + "): " + reason); + EventLog.writeEvent( + EventLogTags.AM_KILL, proc.pid, proc.processName, adj, reason); + killed = true; + proc.killedBackground = true; + Process.killProcessQuiet(pid); + } + } + } + return killed; + } + public final void startRunning(String pkg, String cls, String action, String data) { synchronized(this) { @@ -7137,7 +7193,7 @@ public final class ActivityManagerService extends ActivityManagerNative List<ResolveInfo> ris = null; try { ris = AppGlobals.getPackageManager().queryIntentReceivers( - intent, null, 0); + intent, null, 0, 0); } catch (RemoteException e) { } if (ris != null) { @@ -7394,6 +7450,10 @@ public final class ActivityManagerService extends ActivityManagerNative } private boolean handleAppCrashLocked(ProcessRecord app) { + if (mHeadless) { + Log.e(TAG, "handleAppCrashLocked: " + app.processName); + return false; + } long now = SystemClock.uptimeMillis(); Long crashTime; @@ -7441,7 +7501,7 @@ public final class ActivityManagerService extends ActivityManagerNative mMainStack.resumeTopActivityLocked(null); } else { ActivityRecord r = mMainStack.topRunningActivityLocked(null); - if (r.app == app) { + if (r != null && r.app == app) { // If the top running activity is from this crashing // process, then terminate it to avoid getting in a loop. Slog.w(TAG, " Force finishing activity " @@ -7803,7 +7863,7 @@ public final class ActivityManagerService extends ActivityManagerNative for (String pkg : process.pkgList) { sb.append("Package: ").append(pkg); try { - PackageInfo pi = pm.getPackageInfo(pkg, 0); + PackageInfo pi = pm.getPackageInfo(pkg, 0, 0); if (pi != null) { sb.append(" v").append(pi.versionCode); if (pi.versionName != null) { @@ -8201,7 +8261,7 @@ public final class ActivityManagerService extends ActivityManagerNative IPackageManager pm = AppGlobals.getPackageManager(); for (String pkg : extList) { try { - ApplicationInfo info = pm.getApplicationInfo(pkg, 0); + ApplicationInfo info = pm.getApplicationInfo(pkg, 0, UserId.getCallingUserId()); if ((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) { retList.add(info); } @@ -10682,21 +10742,21 @@ public final class ActivityManagerService extends ActivityManagerNative }; private ServiceLookupResult findServiceLocked(Intent service, - String resolvedType) { + String resolvedType, int userId) { ServiceRecord r = null; if (service.getComponent() != null) { - r = mServiceMap.getServiceByName(service.getComponent(), Binder.getOrigCallingUser()); + r = mServiceMap.getServiceByName(service.getComponent(), userId); } if (r == null) { Intent.FilterComparison filter = new Intent.FilterComparison(service); - r = mServiceMap.getServiceByIntent(filter, Binder.getOrigCallingUser()); + r = mServiceMap.getServiceByIntent(filter, userId); } if (r == null) { try { ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService( - service, resolvedType, 0); + service, resolvedType, 0, userId); ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; if (sInfo == null) { @@ -10767,7 +10827,7 @@ public final class ActivityManagerService extends ActivityManagerNative try { ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService( - service, resolvedType, STOCK_PM_FLAGS); + service, resolvedType, STOCK_PM_FLAGS, userId); ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; if (sInfo == null) { @@ -11132,7 +11192,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Service is now being launched, its package can't be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( - r.packageName, false); + r.packageName, false, r.userId); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " @@ -11437,7 +11497,8 @@ public final class ActivityManagerService extends ActivityManagerNative } // If this service is active, make sure it is stopped. - ServiceLookupResult r = findServiceLocked(service, resolvedType); + ServiceLookupResult r = findServiceLocked(service, resolvedType, + callerApp == null ? UserId.getCallingUserId() : callerApp.userId); if (r != null) { if (r.record != null) { final long origId = Binder.clearCallingIdentity(); @@ -11465,7 +11526,8 @@ public final class ActivityManagerService extends ActivityManagerNative IBinder ret = null; synchronized(this) { - ServiceLookupResult r = findServiceLocked(service, resolvedType); + ServiceLookupResult r = findServiceLocked(service, resolvedType, + UserId.getCallingUserId()); if (r != null) { // r.record is null if findServiceLocked() failed the caller permission check @@ -12094,7 +12156,7 @@ public final class ActivityManagerService extends ActivityManagerNative // Backup agent is now in use, its package can't be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( - app.packageName, false); + app.packageName, false, UserId.getUserId(app.uid)); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " @@ -12423,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!"); } @@ -12458,7 +12520,7 @@ public final class ActivityManagerService extends ActivityManagerNative String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (list != null && (list.length > 0)) { for (String pkg : list) { - forceStopPackageLocked(pkg, -1, false, true, true, false); + forceStopPackageLocked(pkg, -1, false, true, true, false, userId); } sendPackageBroadcastLocked( IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list); @@ -12469,7 +12531,8 @@ public final class ActivityManagerService extends ActivityManagerNative if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) { forceStopPackageLocked(ssp, - intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true, false); + intent.getIntExtra(Intent.EXTRA_UID, -1), false, true, true, + false, userId); } if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED, @@ -12586,7 +12649,7 @@ public final class ActivityManagerService extends ActivityManagerNative if (intent.getComponent() != null) { // Broadcast is going to one specific receiver class... ActivityInfo ai = AppGlobals.getPackageManager(). - getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS); + getReceiverInfo(intent.getComponent(), STOCK_PM_FLAGS, userId); if (ai != null) { receivers = new ArrayList(); ResolveInfo ri = new ResolveInfo(); @@ -12594,15 +12657,15 @@ public final class ActivityManagerService extends ActivityManagerNative receivers.add(ri); } } else { - // TODO: Apply userId // Need to resolve the intent to interested receivers... if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) { receivers = AppGlobals.getPackageManager().queryIntentReceivers( - intent, resolvedType, STOCK_PM_FLAGS); + intent, resolvedType, STOCK_PM_FLAGS, userId); } - registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false); + registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false, + userId); } } catch (RemoteException ex) { // pm is in same process, this will never happen. @@ -12893,7 +12956,7 @@ public final class ActivityManagerService extends ActivityManagerNative ii = mContext.getPackageManager().getInstrumentationInfo( className, STOCK_PM_FLAGS); ai = mContext.getPackageManager().getApplicationInfo( - ii.targetPackage, STOCK_PM_FLAGS); + ii.targetPackage, STOCK_PM_FLAGS); } catch (PackageManager.NameNotFoundException e) { } if (ii == null) { @@ -12921,9 +12984,10 @@ public final class ActivityManagerService extends ActivityManagerNative throw new SecurityException(msg); } + int userId = UserId.getCallingUserId(); final long origId = Binder.clearCallingIdentity(); // Instrumentation can kill and relaunch even persistent processes - forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true); + forceStopPackageLocked(ii.targetPackage, -1, true, false, true, true, userId); ProcessRecord app = addAppLocked(ai, false); app.instrumentationClass = className; app.instrumentationInfo = ai; @@ -12978,11 +13042,12 @@ public final class ActivityManagerService extends ActivityManagerNative app.instrumentationProfileFile = null; app.instrumentationArguments = null; - forceStopPackageLocked(app.processName, -1, false, false, true, true); + forceStopPackageLocked(app.processName, -1, false, false, true, true, app.userId); } public void finishInstrumentation(IApplicationThread target, int resultCode, Bundle results) { + int userId = UserId.getCallingUserId(); // Refuse possible leaked file descriptors if (results != null && results.hasFileDescriptors()) { throw new IllegalArgumentException("File descriptors passed in Intent"); @@ -14544,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(); @@ -14573,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. @@ -14591,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/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java index 53cb2b0..d60ff2b 100644 --- a/services/java/com/android/server/am/ActivityRecord.java +++ b/services/java/com/android/server/am/ActivityRecord.java @@ -26,7 +26,6 @@ import android.content.Intent; import android.content.pm.ActivityInfo; import android.content.pm.ApplicationInfo; import android.content.res.CompatibilityInfo; -import android.content.pm.PackageManager; import android.content.res.Configuration; import android.graphics.Bitmap; import android.os.Build; @@ -542,24 +541,38 @@ final class ActivityRecord { void updateOptionsLocked(Bundle options) { if (options != null) { + if (pendingOptions != null) { + pendingOptions.abort(); + } pendingOptions = new ActivityOptions(options); } } void applyOptionsLocked() { if (pendingOptions != null) { - if (pendingOptions.isCustomAnimation()) { - service.mWindowManager.overridePendingAppTransition( - pendingOptions.getPackageName(), - pendingOptions.getCustomEnterResId(), - pendingOptions.getCustomExitResId()); + switch (pendingOptions.getAnimationType()) { + case ActivityOptions.ANIM_CUSTOM: + service.mWindowManager.overridePendingAppTransition( + pendingOptions.getPackageName(), + pendingOptions.getCustomEnterResId(), + pendingOptions.getCustomExitResId()); + break; + case ActivityOptions.ANIM_THUMBNAIL: + service.mWindowManager.overridePendingAppTransitionThumb( + pendingOptions.getThumbnail(), + pendingOptions.getStartX(), pendingOptions.getStartY(), + pendingOptions.getOnAnimationStartListener()); + break; } pendingOptions = null; } } void clearOptionsLocked() { - pendingOptions = null; + if (pendingOptions != null) { + pendingOptions.abort(); + pendingOptions = null; + } } void removeUriPermissionsLocked() { diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java index 7e8df35..a01ed25 100644 --- a/services/java/com/android/server/am/ActivityStack.java +++ b/services/java/com/android/server/am/ActivityStack.java @@ -1445,9 +1445,8 @@ final class ActivityStack { // Launching this app's activity, make sure the app is no longer // considered stopped. try { - // TODO: Apply to the correct userId AppGlobals.getPackageManager().setPackageStoppedState( - next.packageName, false); + next.packageName, false, next.userId); /* TODO: Verify if correct userid */ } catch (RemoteException e1) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " @@ -1696,6 +1695,7 @@ final class ActivityStack { if (VALIDATE_TOKENS) { validateAppTokensLocked(); } + ActivityOptions.abort(options); return; } break; @@ -1798,6 +1798,7 @@ final class ActivityStack { // because there is nothing for it to animate on top of. mService.mWindowManager.addAppToken(addPos, r.appToken, r.task.taskId, r.info.screenOrientation, r.fullscreen); + ActivityOptions.abort(options); } if (VALIDATE_TOKENS) { validateAppTokensLocked(); @@ -2345,6 +2346,7 @@ final class ActivityStack { // Transfer the result target from the source activity to the new // one being started, including any failures. if (requestCode >= 0) { + ActivityOptions.abort(options); return ActivityManager.START_FORWARD_AND_REQUEST_CONFLICT; } resultRecord = sourceRecord.resultTo; @@ -2376,6 +2378,7 @@ final class ActivityStack { Activity.RESULT_CANCELED, null); } mDismissKeyguardOnNextActivity = false; + ActivityOptions.abort(options); return err; } @@ -2426,6 +2429,7 @@ final class ActivityStack { // We pretend to the caller that it was really started, but // they will just get a cancel result. mDismissKeyguardOnNextActivity = false; + ActivityOptions.abort(options); return ActivityManager.START_SUCCESS; } } @@ -2448,6 +2452,7 @@ final class ActivityStack { pal.startFlags = startFlags; mService.mPendingActivityLaunches.add(pal); mDismissKeyguardOnNextActivity = false; + ActivityOptions.abort(options); return ActivityManager.START_SWITCHES_CANCELED; } } @@ -2602,8 +2607,7 @@ final class ActivityStack { // We really do want to push this one into the // user's face, right now. moveHomeToFrontFromLaunchLocked(launchFlags); - r.updateOptionsLocked(options); - moveTaskToFrontLocked(taskTop.task, r); + moveTaskToFrontLocked(taskTop.task, r, options); } } // If the caller has requested that the target task be @@ -2619,6 +2623,7 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } + ActivityOptions.abort(options); return ActivityManager.START_RETURN_INTENT_TO_CALLER; } if ((launchFlags & @@ -2706,6 +2711,7 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } + ActivityOptions.abort(options); return ActivityManager.START_TASK_TO_FRONT; } } @@ -2735,6 +2741,7 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } + ActivityOptions.abort(options); if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) { // We don't need to start a new activity, and // the client said not to do anything if that @@ -2754,6 +2761,7 @@ final class ActivityStack { r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); } + ActivityOptions.abort(options); return ActivityManager.START_CLASS_NOT_FOUND; } @@ -2795,6 +2803,7 @@ final class ActivityStack { if (doResume) { resumeTopActivityLocked(null); } + ActivityOptions.abort(options); return ActivityManager.START_DELIVERED_TO_TOP; } } else if (!addingToTask && @@ -2847,7 +2856,7 @@ final class ActivityStack { } ActivityInfo resolveActivity(Intent intent, String resolvedType, int startFlags, - String profileFile, ParcelFileDescriptor profileFd) { + String profileFile, ParcelFileDescriptor profileFd, int userId) { // Collect information about the target of the Intent. ActivityInfo aInfo; try { @@ -2855,7 +2864,7 @@ final class ActivityStack { AppGlobals.getPackageManager().resolveIntent( intent, resolvedType, PackageManager.MATCH_DEFAULT_ONLY - | ActivityManagerService.STOCK_PM_FLAGS); + | ActivityManagerService.STOCK_PM_FLAGS, userId); aInfo = rInfo != null ? rInfo.activityInfo : null; } catch (RemoteException e) { aInfo = null; @@ -2909,7 +2918,7 @@ final class ActivityStack { // Collect information about the target of the Intent. ActivityInfo aInfo = resolveActivity(intent, resolvedType, startFlags, - profileFile, profileFd); + profileFile, profileFd, userId); aInfo = mService.getActivityInfoForUser(aInfo, userId); synchronized (mService) { @@ -2949,6 +2958,7 @@ final class ActivityStack { Slog.w(TAG, "Unable to find app for caller " + caller + " (pid=" + realCallingPid + ") when starting: " + intent.toString()); + ActivityOptions.abort(options); return ActivityManager.START_PERMISSION_DENIED; } } @@ -2989,7 +2999,7 @@ final class ActivityStack { AppGlobals.getPackageManager().resolveIntent( intent, null, PackageManager.MATCH_DEFAULT_ONLY - | ActivityManagerService.STOCK_PM_FLAGS); + | ActivityManagerService.STOCK_PM_FLAGS, userId); aInfo = rInfo != null ? rInfo.activityInfo : null; aInfo = mService.getActivityInfoForUser(aInfo, userId); } catch (RemoteException e) { @@ -3098,7 +3108,7 @@ final class ActivityStack { // Collect information about the target of the Intent. ActivityInfo aInfo = resolveActivity(intent, resolvedTypes[i], - 0, null, null); + 0, null, null, userId); // TODO: New, check if this is correct aInfo = mService.getActivityInfoForUser(aInfo, userId); @@ -3481,6 +3491,15 @@ final class ActivityStack { */ final boolean finishActivityLocked(ActivityRecord r, int index, int resultCode, Intent resultData, String reason) { + return finishActivityLocked(r, index, resultCode, resultData, reason, false); + } + + /** + * @return Returns true if this activity has been removed from the history + * list, or false if it is still in the list and will be removed later. + */ + final boolean finishActivityLocked(ActivityRecord r, int index, + int resultCode, Intent resultData, String reason, boolean immediate) { if (r.finishing) { Slog.w(TAG, "Duplicate finish request for " + r); return false; @@ -3522,7 +3541,10 @@ final class ActivityStack { mService.mCancelledThumbnails.add(r); } - if (mResumedActivity == r) { + if (immediate) { + return finishCurrentActivityLocked(r, index, + FINISH_IMMEDIATELY) == null; + } else if (mResumedActivity == r) { boolean endTask = index <= 0 || (mHistory.get(index-1)).task != r.task; if (DEBUG_TRANSITION) Slog.v(TAG, @@ -3888,12 +3910,12 @@ final class ActivityStack { } } if (homeTask != null) { - moveTaskToFrontLocked(homeTask, null); + moveTaskToFrontLocked(homeTask, null, null); } } - final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason) { + final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) { if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr); final int task = tr.taskId; @@ -3901,6 +3923,7 @@ final class ActivityStack { if (top < 0 || (mHistory.get(top)).task.taskId == task) { // nothing to do! + ActivityOptions.abort(options); return; } @@ -3942,7 +3965,16 @@ final class ActivityStack { if (r != null) { mNoAnimActivities.add(r); } + ActivityOptions.abort(options); } else { + if (options != null) { + ActivityRecord r = topRunningActivityLocked(null); + if (r != null && r.state != ActivityState.RESUMED) { + r.updateOptionsLocked(options); + } else { + ActivityOptions.abort(options); + } + } mService.mWindowManager.prepareAppTransition( WindowManagerPolicy.TRANSIT_TASK_TO_FRONT, false); } diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java index 39b63db..1b83e0b 100644 --- a/services/java/com/android/server/am/BroadcastQueue.java +++ b/services/java/com/android/server/am/BroadcastQueue.java @@ -732,7 +732,7 @@ public class BroadcastQueue { // Broadcast is being executed, its package can't be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( - r.curComponent.getPackageName(), false); + r.curComponent.getPackageName(), false, UserId.getUserId(r.callingUid)); } catch (RemoteException e) { } catch (IllegalArgumentException e) { Slog.w(TAG, "Failed trying to unstop package " diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java index cd72202..3ba3fbb 100644 --- a/services/java/com/android/server/am/CompatModePackages.java +++ b/services/java/com/android/server/am/CompatModePackages.java @@ -121,7 +121,7 @@ public class CompatModePackages { public void handlePackageAddedLocked(String packageName, boolean updated) { ApplicationInfo ai = null; try { - ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0); + ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0); } catch (RemoteException e) { } if (ai == null) { @@ -220,7 +220,7 @@ public class CompatModePackages { public int getPackageScreenCompatModeLocked(String packageName) { ApplicationInfo ai = null; try { - ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0); + ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0); } catch (RemoteException e) { } if (ai == null) { @@ -232,7 +232,7 @@ public class CompatModePackages { public void setPackageScreenCompatModeLocked(String packageName, int mode) { ApplicationInfo ai = null; try { - ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0); + ai = AppGlobals.getPackageManager().getApplicationInfo(packageName, 0, 0); } catch (RemoteException e) { } if (ai == null) { @@ -365,7 +365,7 @@ public class CompatModePackages { } ApplicationInfo ai = null; try { - ai = pm.getApplicationInfo(pkg, 0); + ai = pm.getApplicationInfo(pkg, 0, 0); } catch (RemoteException e) { } if (ai == null) { diff --git a/services/java/com/android/server/net/NetworkPolicyManagerService.java b/services/java/com/android/server/net/NetworkPolicyManagerService.java index 2ad24e2..1f1e720 100644 --- a/services/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/java/com/android/server/net/NetworkPolicyManagerService.java @@ -41,7 +41,6 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_METERED; import static android.net.NetworkPolicyManager.computeLastCycleBoundary; import static android.net.NetworkPolicyManager.dumpPolicy; import static android.net.NetworkPolicyManager.dumpRules; -import static android.net.NetworkPolicyManager.isUidValidForPolicy; import static android.net.NetworkTemplate.MATCH_ETHERNET; import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER; import static android.net.NetworkTemplate.MATCH_MOBILE_4G; @@ -74,6 +73,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.pm.UserInfo; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.IConnectivityManager; @@ -96,6 +96,7 @@ import android.os.Message; import android.os.MessageQueue.IdleHandler; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.os.UserId; import android.provider.Settings; import android.telephony.TelephonyManager; import android.text.format.Formatter; @@ -157,6 +158,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final int VERSION_ADDED_METERED = 4; private static final int VERSION_SPLIT_SNOOZE = 5; private static final int VERSION_ADDED_TIMEZONE = 6; + private static final int VERSION_ADDED_INFERRED = 7; + private static final int VERSION_SWITCH_APP_ID = 8; // @VisibleForTesting public static final int TYPE_WARNING = 0x1; @@ -166,6 +169,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final String TAG_POLICY_LIST = "policy-list"; private static final String TAG_NETWORK_POLICY = "network-policy"; private static final String TAG_UID_POLICY = "uid-policy"; + private static final String TAG_APP_POLICY = "app-policy"; private static final String ATTR_VERSION = "version"; private static final String ATTR_RESTRICT_BACKGROUND = "restrictBackground"; @@ -179,7 +183,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { private static final String ATTR_LAST_WARNING_SNOOZE = "lastWarningSnooze"; private static final String ATTR_LAST_LIMIT_SNOOZE = "lastLimitSnooze"; private static final String ATTR_METERED = "metered"; + private static final String ATTR_INFERRED = "inferred"; private static final String ATTR_UID = "uid"; + private static final String ATTR_APP_ID = "appId"; private static final String ATTR_POLICY = "policy"; private static final String TAG_ALLOW_BACKGROUND = TAG + ":allowBackground"; @@ -221,8 +227,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { /** Currently active network rules for ifaces. */ private HashMap<NetworkPolicy, String[]> mNetworkRules = Maps.newHashMap(); - /** Defined UID policies. */ - private SparseIntArray mUidPolicy = new SparseIntArray(); + /** Defined app policies. */ + private SparseIntArray mAppPolicy = new SparseIntArray(); /** Currently derived rules for each UID. */ private SparseIntArray mUidRules = new SparseIntArray(); @@ -377,18 +383,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final String action = intent.getAction(); final int uid = intent.getIntExtra(EXTRA_UID, 0); + final int appId = UserId.getAppId(uid); synchronized (mRulesLock) { if (ACTION_PACKAGE_ADDED.equals(action)) { + // NOTE: PACKAGE_ADDED is currently only sent once, and is + // not broadcast when users are added. + // update rules for UID, since it might be subject to // global background data policy. if (LOGV) Slog.v(TAG, "ACTION_PACKAGE_ADDED for uid=" + uid); - updateRulesForUidLocked(uid); + updateRulesForAppLocked(appId); } else if (ACTION_UID_REMOVED.equals(action)) { + // NOTE: UID_REMOVED is currently only sent once, and is not + // broadcast when users are removed. + // remove any policy and update rules to clean up. if (LOGV) Slog.v(TAG, "ACTION_UID_REMOVED for uid=" + uid); - mUidPolicy.delete(uid); - updateRulesForUidLocked(uid); + + mAppPolicy.delete(appId); + updateRulesForAppLocked(appId); writePolicyLocked(); } } @@ -522,6 +536,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { case MATCH_MOBILE_3G_LOWER: case MATCH_MOBILE_4G: case MATCH_MOBILE_ALL: + // mobile templates aren't relevant in airplane mode + if (isAirplaneModeOn(mContext)) { + return false; + } + // mobile templates are relevant when subscriberid is active return Objects.equal(getActiveSubscriberId(), template.getSubscriberId()); } @@ -932,7 +951,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final NetworkTemplate template = buildTemplateMobileAll(subscriberId); mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, cycleTimezone, - warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true)); + warningBytes, LIMIT_DISABLED, SNOOZE_NEVER, SNOOZE_NEVER, true, true)); writePolicyLocked(); } } @@ -942,7 +961,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { // clear any existing policy and read from disk mNetworkPolicy.clear(); - mUidPolicy.clear(); + mAppPolicy.clear(); FileInputStream fis = null; try { @@ -1004,22 +1023,38 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } else { lastWarningSnooze = SNOOZE_NEVER; } + final boolean inferred; + if (version >= VERSION_ADDED_INFERRED) { + inferred = readBooleanAttribute(in, ATTR_INFERRED); + } else { + inferred = false; + } final NetworkTemplate template = new NetworkTemplate( networkTemplate, subscriberId); mNetworkPolicy.put(template, new NetworkPolicy(template, cycleDay, cycleTimezone, warningBytes, limitBytes, lastWarningSnooze, - lastLimitSnooze, metered)); + lastLimitSnooze, metered, inferred)); } else if (TAG_UID_POLICY.equals(tag)) { final int uid = readIntAttribute(in, ATTR_UID); final int policy = readIntAttribute(in, ATTR_POLICY); - if (isUidValidForPolicy(mContext, uid)) { - setUidPolicyUnchecked(uid, policy, false); + final int appId = UserId.getAppId(uid); + if (UserId.isApp(appId)) { + setAppPolicyUnchecked(appId, policy, false); } else { Slog.w(TAG, "unable to apply policy to UID " + uid + "; ignoring"); } + } else if (TAG_APP_POLICY.equals(tag)) { + final int appId = readIntAttribute(in, ATTR_APP_ID); + final int policy = readIntAttribute(in, ATTR_POLICY); + + if (UserId.isApp(appId)) { + setAppPolicyUnchecked(appId, policy, false); + } else { + Slog.w(TAG, "unable to apply policy to appId " + appId + "; ignoring"); + } } } } @@ -1064,7 +1099,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { out.startDocument(null, true); out.startTag(null, TAG_POLICY_LIST); - writeIntAttribute(out, ATTR_VERSION, VERSION_ADDED_TIMEZONE); + writeIntAttribute(out, ATTR_VERSION, VERSION_SWITCH_APP_ID); writeBooleanAttribute(out, ATTR_RESTRICT_BACKGROUND, mRestrictBackground); // write all known network policies @@ -1084,21 +1119,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { writeLongAttribute(out, ATTR_LAST_WARNING_SNOOZE, policy.lastWarningSnooze); writeLongAttribute(out, ATTR_LAST_LIMIT_SNOOZE, policy.lastLimitSnooze); writeBooleanAttribute(out, ATTR_METERED, policy.metered); + writeBooleanAttribute(out, ATTR_INFERRED, policy.inferred); out.endTag(null, TAG_NETWORK_POLICY); } // write all known uid policies - for (int i = 0; i < mUidPolicy.size(); i++) { - final int uid = mUidPolicy.keyAt(i); - final int policy = mUidPolicy.valueAt(i); + for (int i = 0; i < mAppPolicy.size(); i++) { + final int appId = mAppPolicy.keyAt(i); + final int policy = mAppPolicy.valueAt(i); // skip writing empty policies if (policy == POLICY_NONE) continue; - out.startTag(null, TAG_UID_POLICY); - writeIntAttribute(out, ATTR_UID, uid); + out.startTag(null, TAG_APP_POLICY); + writeIntAttribute(out, ATTR_APP_ID, appId); writeIntAttribute(out, ATTR_POLICY, policy); - out.endTag(null, TAG_UID_POLICY); + out.endTag(null, TAG_APP_POLICY); } out.endTag(null, TAG_POLICY_LIST); @@ -1113,24 +1149,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public void setUidPolicy(int uid, int policy) { + public void setAppPolicy(int appId, int policy) { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); - if (!isUidValidForPolicy(mContext, uid)) { - throw new IllegalArgumentException("cannot apply policy to UID " + uid); + if (!UserId.isApp(appId)) { + throw new IllegalArgumentException("cannot apply policy to appId " + appId); } - setUidPolicyUnchecked(uid, policy, true); + setAppPolicyUnchecked(appId, policy, true); } - private void setUidPolicyUnchecked(int uid, int policy, boolean persist) { + private void setAppPolicyUnchecked(int appId, int policy, boolean persist) { final int oldPolicy; synchronized (mRulesLock) { - oldPolicy = getUidPolicy(uid); - mUidPolicy.put(uid, policy); + oldPolicy = getAppPolicy(appId); + mAppPolicy.put(appId, policy); // uid policy changed, recompute rules and persist policy. - updateRulesForUidLocked(uid); + updateRulesForAppLocked(appId); if (persist) { writePolicyLocked(); } @@ -1138,11 +1174,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } @Override - public int getUidPolicy(int uid) { + public int getAppPolicy(int appId) { mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG); synchronized (mRulesLock) { - return mUidPolicy.get(uid, POLICY_NONE); + return mAppPolicy.get(appId, POLICY_NONE); } } @@ -1333,27 +1369,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { fout.print(" "); fout.println(policy.toString()); } - fout.println("Policy status for known UIDs:"); + fout.println("Policy for apps:"); + int size = mAppPolicy.size(); + for (int i = 0; i < size; i++) { + final int appId = mAppPolicy.keyAt(i); + final int policy = mAppPolicy.valueAt(i); + fout.print(" appId="); + fout.print(appId); + fout.print(" policy="); + dumpPolicy(fout, policy); + fout.println(); + } final SparseBooleanArray knownUids = new SparseBooleanArray(); - collectKeys(mUidPolicy, knownUids); collectKeys(mUidForeground, knownUids); collectKeys(mUidRules, knownUids); - final int size = knownUids.size(); + fout.println("Status for known UIDs:"); + size = knownUids.size(); for (int i = 0; i < size; i++) { final int uid = knownUids.keyAt(i); fout.print(" UID="); fout.print(uid); - fout.print(" policy="); - final int policyIndex = mUidPolicy.indexOfKey(uid); - if (policyIndex < 0) { - fout.print("UNKNOWN"); - } else { - dumpPolicy(fout, mUidPolicy.valueAt(policyIndex)); - } - fout.print(" foreground="); final int foregroundIndex = mUidPidForeground.indexOfKey(uid); if (foregroundIndex < 0) { @@ -1443,7 +1481,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { final PackageManager pm = mContext.getPackageManager(); final List<ApplicationInfo> apps = pm.getInstalledApplications(0); for (ApplicationInfo app : apps) { - updateRulesForUidLocked(app.uid); + final int appId = UserId.getAppId(app.uid); + updateRulesForAppLocked(appId); } // and catch system UIDs @@ -1462,13 +1501,21 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { } } + private void updateRulesForAppLocked(int appId) { + for (UserInfo user : mContext.getPackageManager().getUsers()) { + final int uid = UserId.getUid(user.id, appId); + updateRulesForUidLocked(uid); + } + } + private void updateRulesForUidLocked(int uid) { - final int uidPolicy = getUidPolicy(uid); + final int appId = UserId.getAppId(uid); + final int appPolicy = getAppPolicy(appId); final boolean uidForeground = isUidForeground(uid); // derive active rules based on policy and active state int uidRules = RULE_ALLOW_ALL; - if (!uidForeground && (uidPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { + if (!uidForeground && (appPolicy & POLICY_REJECT_METERED_BACKGROUND) != 0) { // uid in background, and policy says to block metered data uidRules = RULE_REJECT_METERED; } @@ -1714,6 +1761,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { mHandler.getLooper().getQueue().addIdleHandler(handler); } + public static boolean isAirplaneModeOn(Context context) { + return Settings.System.getInt( + context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) != 0; + } + private static void collectKeys(SparseIntArray source, SparseBooleanArray target) { final int size = source.size(); for (int i = 0; i < size; i++) { diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index bc98f86..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; @@ -395,7 +396,7 @@ public class PackageManagerService extends IPackageManager.Stub { static final int MCS_GIVE_UP = 11; static final int UPDATED_MEDIA_STATUS = 12; static final int WRITE_SETTINGS = 13; - static final int WRITE_STOPPED_PACKAGES = 14; + static final int WRITE_PACKAGE_RESTRICTIONS = 14; static final int PACKAGE_VERIFIED = 15; static final int CHECK_PENDING_VERIFICATION = 16; @@ -404,7 +405,10 @@ 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>(); final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); @@ -629,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.userId : -1; + uids[i] = (ps != null) ? ps.appId : -1; i++; } size = i; @@ -673,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 @@ -735,16 +740,20 @@ public class PackageManagerService extends IPackageManager.Stub { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mPackages) { removeMessages(WRITE_SETTINGS); - removeMessages(WRITE_STOPPED_PACKAGES); + removeMessages(WRITE_PACKAGE_RESTRICTIONS); mSettings.writeLPr(); + mDirtyUsers.clear(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; - case WRITE_STOPPED_PACKAGES: { + case WRITE_PACKAGE_RESTRICTIONS: { Process.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT); synchronized (mPackages) { - removeMessages(WRITE_STOPPED_PACKAGES); - mSettings.writeStoppedLPr(); + removeMessages(WRITE_PACKAGE_RESTRICTIONS); + for (int userId : mDirtyUsers) { + mSettings.writePackageRestrictionsLPr(userId); + } + mDirtyUsers.clear(); } Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); } break; @@ -811,10 +820,12 @@ public class PackageManagerService extends IPackageManager.Stub { mHandler.sendEmptyMessageDelayed(WRITE_SETTINGS, WRITE_SETTINGS_DELAY); } } - - void scheduleWriteStoppedPackagesLocked() { - if (!mHandler.hasMessages(WRITE_STOPPED_PACKAGES)) { - mHandler.sendEmptyMessageDelayed(WRITE_STOPPED_PACKAGES, WRITE_SETTINGS_DELAY); + + 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); } } @@ -912,11 +923,11 @@ 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(); - mRestoredSettings = mSettings.readLPw(); + mRestoredSettings = mSettings.readLPw(getUsers()); long startTime = SystemClock.uptimeMillis(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_SYSTEM_SCAN_START, @@ -1078,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); } } } @@ -1180,7 +1191,7 @@ public class PackageManagerService extends IPackageManager.Stub { private String getRequiredVerifierLPr() { final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, - PackageManager.GET_DISABLED_COMPONENTS); + PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */); String requiredVerifier = null; @@ -1234,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()) { @@ -1498,31 +1509,42 @@ 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; } - public PackageInfo getPackageInfo(String packageName, int flags) { + @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); + return generatePackageInfoFromSettingsLPw(packageName, flags, userId); } } return null; @@ -1551,20 +1573,22 @@ public class PackageManagerService extends IPackageManager.Stub { } return out; } - - public int getPackageUid(String packageName) { + + @Override + public int getPackageUid(String packageName, int userId) { + if (!sUserManager.exists(userId)) return -1; // reader synchronized (mPackages) { PackageParser.Package p = mPackages.get(packageName); if(p != null) { - return p.applicationInfo.uid; + return UserId.getUid(userId, p.applicationInfo.uid); } PackageSetting ps = mSettings.mPackages.get(packageName); if((ps == null) || (ps.pkg == null) || (ps.pkg.applicationInfo == null)) { return -1; } p = ps.pkg; - return p != null ? p.applicationInfo.uid : -1; + return p != null ? UserId.getUid(userId, p.applicationInfo.uid) : -1; } } @@ -1577,7 +1601,16 @@ public class PackageManagerService extends IPackageManager.Stub { if (p != null) { final PackageSetting ps = (PackageSetting)p.mExtras; final SharedUserSetting suid = ps.sharedUser; - return suid != null ? suid.gids : ps.gids; + int[] gids = suid != null ? suid.gids : ps.gids; + + // include GIDs for any unenforced permissions + if (!isPermissionEnforcedLocked(READ_EXTERNAL_STORAGE)) { + final BasePermission basePerm = mSettings.mPermissions.get( + READ_EXTERNAL_STORAGE); + gids = appendInts(gids, basePerm.gids); + } + + return gids; } } // stupid thing to indicate an error. @@ -1652,24 +1685,30 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags) { + 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) { - PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags); + PackageInfo pInfo = generatePackageInfoFromSettingsLPw(packageName, flags, userId); if (pInfo != null) { return pInfo.applicationInfo; } 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) { + 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; @@ -1679,15 +1718,17 @@ public class PackageManagerService extends IPackageManager.Stub { ps.pkg.applicationInfo.dataDir = getDataPathForPackage(ps.pkg.packageName, 0).getPath(); ps.pkg.applicationInfo.nativeLibraryDir = ps.nativeLibraryPathString; - ps.pkg.mSetEnabled = ps.enabled; - ps.pkg.mSetStopped = ps.stopped; } - 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; } - public ApplicationInfo getApplicationInfo(String packageName, int flags) { + @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); @@ -1695,14 +1736,17 @@ 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; } if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - return generateApplicationInfoFromSettingsLPw(packageName, flags); + return generateApplicationInfoFromSettingsLPw(packageName, flags, userId); } } return null; @@ -1758,17 +1802,18 @@ public class PackageManagerService extends IPackageManager.Stub { }); } - public ActivityInfo getActivityInfo(ComponentName component, int flags) { - return getActivityInfo(component, flags, Binder.getOrigCallingUser()); - } - - ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) { + @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)) { - return PackageParser.generateActivityInfo(a, flags, userId); + if (a != null && mSettings.isEnabledLPr(a.info, 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; @@ -1777,49 +1822,52 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } - public ActivityInfo getReceiverInfo(ComponentName component, int flags) { - return getReceiverInfo(component, flags, Binder.getOrigCallingUser()); - } - - ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) { + @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)) { - return PackageParser.generateActivityInfo(a, flags, userId); + if (a != null && mSettings.isEnabledLPr(a.info, 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; } - public ServiceInfo getServiceInfo(ComponentName component, int flags) { - return getServiceInfo(component, flags, Binder.getOrigCallingUser()); - } - - ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) { + @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)) { - return PackageParser.generateServiceInfo(s, flags, userId); + if (s != null && mSettings.isEnabledLPr(s.info, 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; } - public ProviderInfo getProviderInfo(ComponentName component, int flags) { - return getProviderInfo(component, flags, UserId.getUserId(Binder.getCallingUid())); - } - - ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) { + @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)) { - return PackageParser.generateProviderInfo(p, flags, userId); + if (p != null && mSettings.isEnabledLPr(p.info, 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; @@ -1863,6 +1911,14 @@ public class PackageManagerService extends IPackageManager.Stub { } } + private void checkValidCaller(int uid, int userId) { + if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) + return; + + throw new SecurityException("Caller uid=" + uid + + " is not privileged to communicate with user=" + userId); + } + public int checkPermission(String permName, String pkgName) { synchronized (mPackages) { PackageParser.Package p = mPackages.get(pkgName); @@ -1997,7 +2053,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (!async) { mSettings.writeLPr(); } else { - scheduleWriteSettingsLocked(); + scheduleWriteSettingsLocked(); } } return added; @@ -2232,14 +2288,16 @@ public class PackageManagerService extends IPackageManager.Stub { } } + @Override public ResolveInfo resolveIntent(Intent intent, String resolvedType, - int flags) { - List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags); - return chooseBestActivity(intent, resolvedType, flags, query); + 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); } private ResolveInfo chooseBestActivity(Intent intent, String resolvedType, - int flags, List<ResolveInfo> query) { + int flags, List<ResolveInfo> query, int userId) { if (query != null) { final int N = query.size(); if (N == 1) { @@ -2263,7 +2321,7 @@ public class PackageManagerService extends IPackageManager.Stub { // If we have saved a preference for a preferred activity for // this Intent, use that. ResolveInfo ri = findPreferredActivity(intent, resolvedType, - flags, query, r0.priority); + flags, query, r0.priority, userId); if (ri != null) { return ri; } @@ -2274,7 +2332,8 @@ public class PackageManagerService extends IPackageManager.Stub { } ResolveInfo findPreferredActivity(Intent intent, String resolvedType, - int flags, List<ResolveInfo> query, int priority) { + int flags, List<ResolveInfo> query, int priority, int userId) { + if (!sUserManager.exists(userId)) return null; // writer synchronized (mPackages) { if (intent.getSelector() != null) { @@ -2283,7 +2342,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (DEBUG_PREFERRED) intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION); List<PreferredActivity> prefs = mSettings.mPreferredActivities.queryIntent(intent, resolvedType, - (flags&PackageManager.MATCH_DEFAULT_ONLY) != 0); + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId); if (prefs != null && prefs.size() > 0) { // First figure out how good the original match set is. // We will only allow preferred activities that came @@ -2317,7 +2376,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (pa.mPref.mMatch != match) { continue; } - final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags); + final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, flags, userId); if (DEBUG_PREFERRED) { Log.v(TAG, "Got preferred activity:"); if (ai != null) { @@ -2367,8 +2426,10 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } + @Override public List<ResolveInfo> queryIntentActivities(Intent intent, - String resolvedType, int flags) { + String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; ComponentName comp = intent.getComponent(); if (comp == null) { if (intent.getSelector() != null) { @@ -2379,7 +2440,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (comp != null) { final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); - final ActivityInfo ai = getActivityInfo(comp, flags); + final ActivityInfo ai = getActivityInfo(comp, flags, userId); if (ai != null) { final ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; @@ -2392,24 +2453,26 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { final String pkgName = intent.getPackage(); if (pkgName == null) { - return mActivities.queryIntent(intent, resolvedType, flags); + return mActivities.queryIntent(intent, resolvedType, flags, userId); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { return mActivities.queryIntentForPackage(intent, resolvedType, flags, - pkg.activities); + pkg.activities, userId); } return new ArrayList<ResolveInfo>(); } } + @Override public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics, String[] specificTypes, Intent intent, - String resolvedType, int flags) { + String resolvedType, int flags, int userId) { + if (!sUserManager.exists(userId)) return null; final String resultsAction = intent.getAction(); List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags - | PackageManager.GET_RESOLVED_FILTER); + | PackageManager.GET_RESOLVED_FILTER, userId); if (DEBUG_INTENT_MATCHING) { Log.v(TAG, "Query " + intent + ": " + results); @@ -2452,7 +2515,7 @@ public class PackageManagerService extends IPackageManager.Stub { ri = resolveIntent( sintent, specificTypes != null ? specificTypes[i] : null, - flags); + flags, userId); if (ri == null) { continue; } @@ -2463,7 +2526,7 @@ public class PackageManagerService extends IPackageManager.Stub { comp = new ComponentName(ai.applicationInfo.packageName, ai.name); } else { - ai = getActivityInfo(comp, flags); + ai = getActivityInfo(comp, flags, userId); if (ai == null) { continue; } @@ -2572,7 +2635,10 @@ public class PackageManagerService extends IPackageManager.Stub { return results; } - public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags) { + @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) { @@ -2582,7 +2648,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (comp != null) { List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); - ActivityInfo ai = getReceiverInfo(comp, flags); + ActivityInfo ai = getReceiverInfo(comp, flags, userId); if (ai != null) { ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; @@ -2595,18 +2661,21 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { - return mReceivers.queryIntent(intent, resolvedType, flags); + return mReceivers.queryIntent(intent, resolvedType, flags, userId); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { - return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers); + return mReceivers.queryIntentForPackage(intent, resolvedType, flags, pkg.receivers, + userId); } return null; } } - public ResolveInfo resolveService(Intent intent, String resolvedType, int flags) { - List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags); + @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, @@ -2617,7 +2686,10 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } - public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags) { + @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) { @@ -2627,7 +2699,7 @@ public class PackageManagerService extends IPackageManager.Stub { } if (comp != null) { final List<ResolveInfo> list = new ArrayList<ResolveInfo>(1); - final ServiceInfo si = getServiceInfo(comp, flags); + final ServiceInfo si = getServiceInfo(comp, flags, userId); if (si != null) { final ResolveInfo ri = new ResolveInfo(); ri.serviceInfo = si; @@ -2640,11 +2712,12 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { String pkgName = intent.getPackage(); if (pkgName == null) { - return mServices.queryIntent(intent, resolvedType, flags); + return mServices.queryIntent(intent, resolvedType, flags, userId); } final PackageParser.Package pkg = mPackages.get(pkgName); if (pkg != null) { - return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services); + return mServices.queryIntentForPackage(intent, resolvedType, flags, pkg.services, + userId); } return null; } @@ -2669,6 +2742,7 @@ public class PackageManagerService extends IPackageManager.Stub { final ParceledListSlice<PackageInfo> list = new ParceledListSlice<PackageInfo>(); final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; final String[] keys; + int userId = UserId.getCallingUserId(); // writer synchronized (mPackages) { @@ -2689,12 +2763,12 @@ public class PackageManagerService extends IPackageManager.Stub { if (listUninstalled) { final PackageSetting ps = mSettings.mPackages.get(packageName); if (ps != null) { - pi = generatePackageInfoFromSettingsLPw(ps.name, flags); + pi = generatePackageInfoFromSettingsLPw(ps.name, flags, userId); } } else { final PackageParser.Package p = mPackages.get(packageName); if (p != null) { - pi = generatePackageInfo(p, flags); + pi = generatePackageInfo(p, flags, userId); } } @@ -2711,8 +2785,10 @@ public class PackageManagerService extends IPackageManager.Stub { return list; } + @Override public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, - String lastRead) { + 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; @@ -2728,21 +2804,21 @@ public class PackageManagerService extends IPackageManager.Stub { Arrays.sort(keys); int i = getContinuationPoint(keys, lastRead); final int N = keys.length; - final int userId = UserId.getUserId(Binder.getCallingUid()); while (i < N) { 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); + 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); } } @@ -2765,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)); } } } @@ -2779,16 +2859,23 @@ public class PackageManagerService extends IPackageManager.Stub { return finalList; } - public ProviderInfo resolveContentProvider(String name, int flags) { + @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) + && mSettings.isEnabledLPr(provider.info, flags, userId) && (!mSafeMode || (provider.info.applicationInfo.flags &ApplicationInfo.FLAG_SYSTEM) != 0) ? PackageParser.generateProviderInfo(provider, flags, - UserId.getUserId(Binder.getCallingUid())) + ps != null ? ps.getStopped(userId) : false, + ps != null ? ps.getEnabled(userId) : COMPONENT_ENABLED_STATE_DEFAULT, + userId) : null; } } @@ -2802,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)); } } } @@ -2824,21 +2915,25 @@ public class PackageManagerService extends IPackageManager.Stub { // reader synchronized (mPackages) { final Iterator<PackageParser.Provider> i = mProvidersByComponent.values().iterator(); - final int userId = UserId.getUserId(Binder.getCallingUid()); + final int userId = processName != null ? + 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) - && UserId.getAppId(p.info.applicationInfo.uid) - == UserId.getAppId(uid))) - && mSettings.isEnabledLPr(p.info, flags) + && UserId.isSameApp(p.info.applicationInfo.uid, uid))) + && mSettings.isEnabledLPr(p.info, flags, userId) && (!mSafeMode || (p.info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)) { 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)); } } } @@ -3482,7 +3577,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } - pkg.applicationInfo.uid = pkgSetting.userId; + pkg.applicationInfo.uid = pkgSetting.appId; pkg.mExtras = pkgSetting; if (!verifySignaturesLP(pkgSetting, pkg)) { @@ -3589,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: " @@ -3610,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) { @@ -3652,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(); @@ -4480,19 +4575,23 @@ public class PackageManagerService extends IPackageManager.Stub { private final class ActivityIntentResolver extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, - boolean defaultOnly) { + boolean defaultOnly, int userId) { + if (!sUserManager.exists(userId)) return null; mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; - return super.queryIntent(intent, resolvedType, defaultOnly); + return super.queryIntent(intent, resolvedType, defaultOnly, userId); } - public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) { + 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); + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId); } public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, ArrayList<PackageParser.Activity> packageActivities) { + int flags, ArrayList<PackageParser.Activity> packageActivities, int userId) { + if (!sUserManager.exists(userId)) return null; if (packageActivities == null) { return null; } @@ -4509,7 +4608,7 @@ public class PackageManagerService extends IPackageManager.Stub { listCut.add(intentFilters); } } - return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut); + return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } public final void addActivity(PackageParser.Activity a, String type) { @@ -4574,7 +4673,8 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - protected boolean isFilterStopped(PackageParser.ActivityIntentInfo filter) { + 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; @@ -4582,7 +4682,7 @@ public class PackageManagerService extends IPackageManager.Stub { // System apps are never considered stopped for purposes of // filtering, because there may be no way for the user to // actually re-launch them. - return ps.stopped && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0; + return ps.getStopped(userId) && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0; } } return false; @@ -4595,8 +4695,9 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, - int match) { - if (!mSettings.isEnabledLPr(info.activity.info, mFlags)) { + int match, int userId) { + if (!sUserManager.exists(userId)) return null; + if (!mSettings.isEnabledLPr(info.activity.info, mFlags, userId)) { return null; } final PackageParser.Activity activity = info.activity; @@ -4605,8 +4706,11 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final ResolveInfo res = new ResolveInfo(); + PackageSetting ps = (PackageSetting) activity.owner.mExtras; res.activityInfo = PackageParser.generateActivityInfo(activity, mFlags, - Binder.getOrigCallingUser()); + 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; } @@ -4660,19 +4764,22 @@ public class PackageManagerService extends IPackageManager.Stub { private final class ServiceIntentResolver extends IntentResolver<PackageParser.ServiceIntentInfo, ResolveInfo> { public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, - boolean defaultOnly) { + boolean defaultOnly, int userId) { mFlags = defaultOnly ? PackageManager.MATCH_DEFAULT_ONLY : 0; - return super.queryIntent(intent, resolvedType, defaultOnly); + return super.queryIntent(intent, resolvedType, defaultOnly, userId); } - public List<ResolveInfo> queryIntent(Intent intent, String resolvedType, int flags) { + 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); + (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0, userId); } public List<ResolveInfo> queryIntentForPackage(Intent intent, String resolvedType, - int flags, ArrayList<PackageParser.Service> packageServices) { + int flags, ArrayList<PackageParser.Service> packageServices, int userId) { + if (!sUserManager.exists(userId)) return null; if (packageServices == null) { return null; } @@ -4689,7 +4796,7 @@ public class PackageManagerService extends IPackageManager.Stub { listCut.add(intentFilters); } } - return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut); + return super.queryIntentFromList(intent, resolvedType, defaultOnly, listCut, userId); } public final void addService(PackageParser.Service s) { @@ -4749,7 +4856,8 @@ public class PackageManagerService extends IPackageManager.Stub { } @Override - protected boolean isFilterStopped(PackageParser.ServiceIntentInfo filter) { + 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; @@ -4757,7 +4865,8 @@ public class PackageManagerService extends IPackageManager.Stub { // System apps are never considered stopped for purposes of // filtering, because there may be no way for the user to // actually re-launch them. - return ps.stopped && (ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0; + return ps.getStopped(userId) + && (ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0; } } return false; @@ -4770,9 +4879,10 @@ public class PackageManagerService extends IPackageManager.Stub { @Override protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, - int match) { + int match, int userId) { + if (!sUserManager.exists(userId)) return null; final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter; - if (!mSettings.isEnabledLPr(info.service.info, mFlags)) { + if (!mSettings.isEnabledLPr(info.service.info, mFlags, userId)) { return null; } final PackageParser.Service service = info.service; @@ -4781,8 +4891,11 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } final ResolveInfo res = new ResolveInfo(); + PackageSetting ps = (PackageSetting) service.owner.mExtras; res.serviceInfo = PackageParser.generateServiceInfo(service, mFlags, - Binder.getOrigCallingUser()); + 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; } @@ -4873,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) { } } @@ -5032,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); } } @@ -5635,14 +5757,14 @@ public class PackageManagerService extends IPackageManager.Stub { * do, then we'll defer to them to verify the packages. */ final int requiredUid = mRequiredVerifierPackage == null ? -1 - : getPackageUid(mRequiredVerifierPackage); + : getPackageUid(mRequiredVerifierPackage, 0); if (requiredUid != -1 && isVerificationEnabled()) { final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); verification.setDataAndType(packageURI, PACKAGE_MIME_TYPE); verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); final List<ResolveInfo> receivers = queryIntentReceivers(verification, null, - PackageManager.GET_DISABLED_COMPONENTS); + PackageManager.GET_DISABLED_COMPONENTS, 0 /* TODO: Which userId? */); if (DEBUG_VERIFY) { Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent " @@ -7062,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. @@ -7099,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)); } } } @@ -7138,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); } @@ -7316,17 +7439,19 @@ public class PackageManagerService extends IPackageManager.Stub { return ret; } + @Override public void clearApplicationUserData(final String packageName, - final IPackageDataObserver observer) { + final IPackageDataObserver observer, final int userId) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.CLEAR_APP_USER_DATA, null); + checkValidCaller(Binder.getCallingUid(), userId); // Queue up an async operation since the package deletion may take a little while. mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); final boolean succeeded; synchronized (mInstallLock) { - succeeded = clearApplicationUserDataLI(packageName); + succeeded = clearApplicationUserDataLI(packageName, userId); } if (succeeded) { // invoke DeviceStorageMonitor's update method to clear any notifications @@ -7347,7 +7472,7 @@ public class PackageManagerService extends IPackageManager.Stub { }); } - private boolean clearApplicationUserDataLI(String packageName) { + private boolean clearApplicationUserDataLI(String packageName, int userId) { if (packageName == null) { Slog.w(TAG, "Attempt to delete null packageName."); return false; @@ -7379,7 +7504,7 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } } - int retCode = mInstaller.clearUserData(packageName, 0); // TODO - correct userId + int retCode = mInstaller.clearUserData(packageName, userId); if (retCode < 0) { Slog.w(TAG, "Couldn't remove cache files for package: " + packageName); @@ -7393,12 +7518,13 @@ public class PackageManagerService extends IPackageManager.Stub { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.DELETE_CACHE_FILES, null); // Queue up an async operation since the package deletion may take a little while. + final int userId = UserId.getCallingUserId(); mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); final boolean succeded; synchronized (mInstallLock) { - succeded = deleteApplicationCacheFilesLI(packageName); + succeded = deleteApplicationCacheFilesLI(packageName, userId); } if(observer != null) { try { @@ -7411,7 +7537,7 @@ public class PackageManagerService extends IPackageManager.Stub { }); } - private boolean deleteApplicationCacheFilesLI(String packageName) { + private boolean deleteApplicationCacheFilesLI(String packageName, int userId) { if (packageName == null) { Slog.w(TAG, "Attempt to delete null packageName."); return false; @@ -7429,6 +7555,7 @@ public class PackageManagerService extends IPackageManager.Stub { Slog.w(TAG, "Package " + packageName + " has no applicationInfo."); return false; } + // TODO: Pass userId to deleteCacheFiles int retCode = mInstaller.deleteCacheFiles(packageName); if (retCode < 0) { Slog.w(TAG, "Couldn't remove cache files for package: " @@ -7695,19 +7822,23 @@ public class PackageManagerService extends IPackageManager.Stub { return num; } + @Override public void setApplicationEnabledSetting(String appPackageName, - int newState, int flags) { - setEnabledSetting(appPackageName, null, newState, flags); + 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 newState, int flags, int userId) { + if (!sUserManager.exists(userId)) return; setEnabledSetting(componentName.getPackageName(), - componentName.getClassName(), newState, flags); + componentName.getClassName(), newState, flags, userId); } private void setEnabledSetting( - final String packageName, String className, int newState, final int flags) { + final String packageName, String className, int newState, final int flags, int userId) { if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT || newState == COMPONENT_ENABLED_STATE_ENABLED || newState == COMPONENT_ENABLED_STATE_DISABLED @@ -7719,6 +7850,7 @@ public class PackageManagerService extends IPackageManager.Stub { final int uid = Binder.getCallingUid(); final int permission = mContext.checkCallingPermission( android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE); + checkValidCaller(uid, userId); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); boolean sendNow = false; boolean isApp = (className == null); @@ -7738,20 +7870,21 @@ public class PackageManagerService extends IPackageManager.Stub { "Unknown component: " + packageName + "/" + className); } - if (!allowedByPermission && (!UserId.isSameApp(uid, pkgSetting.userId))) { + // Allow root and verify that userId is not being specified by a different user + 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.userId); + + ", uid=" + uid + ", package uid=" + pkgSetting.appId); } if (className == null) { // We're dealing with an application/package level state change - if (pkgSetting.enabled == newState) { + if (pkgSetting.getEnabled(userId) == newState) { // Nothing to do return; } - pkgSetting.enabled = newState; - pkgSetting.pkg.mSetEnabled = newState; + pkgSetting.setEnabled(newState, userId); + // pkgSetting.pkg.mSetEnabled = newState; } else { // We're dealing with a component level state change // First, verify that this is a valid class name. @@ -7767,17 +7900,17 @@ public class PackageManagerService extends IPackageManager.Stub { } switch (newState) { case COMPONENT_ENABLED_STATE_ENABLED: - if (!pkgSetting.enableComponentLPw(className)) { + if (!pkgSetting.enableComponentLPw(className, userId)) { return; } break; case COMPONENT_ENABLED_STATE_DISABLED: - if (!pkgSetting.disableComponentLPw(className)) { + if (!pkgSetting.disableComponentLPw(className, userId)) { return; } break; case COMPONENT_ENABLED_STATE_DEFAULT: - if (!pkgSetting.restoreComponentLPw(className)) { + if (!pkgSetting.restoreComponentLPw(className, userId)) { return; } break; @@ -7786,8 +7919,8 @@ public class PackageManagerService extends IPackageManager.Stub { return; } } - mSettings.writeLPr(); - packageUid = pkgSetting.userId; + mSettings.writePackageRestrictionsLPr(userId); + packageUid = UserId.getUid(userId, pkgSetting.appId); components = mPendingBroadcasts.get(packageName); final boolean newPackage = components == null; if (newPackage) { @@ -7835,19 +7968,22 @@ 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) { + 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); final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED); + checkValidCaller(uid, userId); // writer synchronized (mPackages) { if (mSettings.setPackageStoppedStateLPw(packageName, stopped, allowedByPermission, - uid)) { - scheduleWriteStoppedPackagesLocked(); + uid, userId)) { + scheduleWritePackageRestrictionsLocked(userId); } } } @@ -7859,17 +7995,25 @@ public class PackageManagerService extends IPackageManager.Stub { } } - public int getApplicationEnabledSetting(String packageName) { + @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 synchronized (mPackages) { - return mSettings.getApplicationEnabledSettingLPr(packageName); + return mSettings.getApplicationEnabledSettingLPr(packageName, userId); } } - public int getComponentEnabledSetting(ComponentName componentName) { + @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 synchronized (mPackages) { - return mSettings.getComponentEnabledSettingLPr(componentName); + return mSettings.getComponentEnabledSettingLPr(componentName, userId); } } @@ -8073,7 +8217,7 @@ public class PackageManagerService extends IPackageManager.Stub { pw.print(" Required: "); pw.print(mRequiredVerifierPackage); pw.print(" (uid="); - pw.print(getPackageUid(mRequiredVerifierPackage)); + pw.print(getPackageUid(mRequiredVerifierPackage, 0)); pw.println(")"); } @@ -8338,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.userId; + int uid = ps.appId; if (uid != -1) { uidList[num++] = uid; } @@ -8391,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); } } @@ -8815,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; } @@ -8824,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( @@ -8842,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 @@ -8854,6 +9037,19 @@ public class PackageManagerService extends IPackageManager.Stub { if (mSettings.mReadExternalStorageEnforcement != enforcement) { mSettings.mReadExternalStorageEnforcement = enforcement; mSettings.writeLPr(); + + // kill any non-foreground processes so we restart them and + // grant/revoke the GID. + final IActivityManager am = ActivityManagerNative.getDefault(); + if (am != null) { + final long token = Binder.clearCallingIdentity(); + try { + am.killProcessesBelowForeground("setPermissionEnforcement"); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(token); + } + } } } } else { diff --git a/services/java/com/android/server/pm/PackageSetting.java b/services/java/com/android/server/pm/PackageSetting.java index efdc2b3..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 userId; + int appId; PackageParser.Package pkg; SharedUserSetting sharedUser; @@ -41,7 +41,7 @@ final class PackageSetting extends PackageSettingBase { PackageSetting(PackageSetting orig) { super(orig); - userId = orig.userId; + 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 + "/" + userId + "}"; + + " " + 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 e2f83ad..56f2166 100644 --- a/services/java/com/android/server/pm/PackageSettingBase.java +++ b/services/java/com/android/server/pm/PackageSettingBase.java @@ -20,6 +20,8 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; +import android.util.SparseArray; +import android.util.SparseIntArray; import java.io.File; import java.util.HashSet; @@ -62,20 +64,22 @@ class PackageSettingBase extends GrantedPermissions { // Whether this package is currently stopped, thus can not be // started until explicitly launched by the user. - public boolean stopped; + private SparseArray<Boolean> stopped = new SparseArray<Boolean>(); // Set to true if we have never launched this app. - public boolean notLaunched; + private SparseArray<Boolean> notLaunched = new SparseArray<Boolean>(); /* Explicitly disabled components */ - HashSet<String> disabledComponents = new HashSet<String>(0); + private SparseArray<HashSet<String>> disabledComponents = new SparseArray<HashSet<String>>(); /* Explicitly enabled components */ - HashSet<String> enabledComponents = new HashSet<String>(0); - int enabled = COMPONENT_ENABLED_STATE_DEFAULT; + private SparseArray<HashSet<String>> enabledComponents = new SparseArray<HashSet<String>>(); + /* Enabled state */ + private SparseIntArray enabled = new SparseIntArray(); + int installStatus = PKG_INSTALL_COMPLETE; PackageSettingBase origPackage; - + /* package name of the app that installed this package */ String installerPackageName; PackageSettingBase(String name, String realName, File codePath, File resourcePath, @@ -111,14 +115,12 @@ class PackageSettingBase extends GrantedPermissions { permissionsFixed = base.permissionsFixed; haveGids = base.haveGids; - stopped = base.stopped; notLaunched = base.notLaunched; - disabledComponents = (HashSet<String>) base.disabledComponents.clone(); - - enabledComponents = (HashSet<String>) base.enabledComponents.clone(); - - enabled = base.enabled; + disabledComponents = (SparseArray<HashSet<String>>) base.disabledComponents.clone(); + enabledComponents = (SparseArray<HashSet<String>>) base.enabledComponents.clone(); + enabled = (SparseIntArray) base.enabled.clone(); + stopped = (SparseArray<Boolean>) base.stopped.clone(); installStatus = base.installStatus; origPackage = base.origPackage; @@ -177,31 +179,107 @@ class PackageSettingBase extends GrantedPermissions { installStatus = base.installStatus; } - boolean enableComponentLPw(String componentClassName) { - boolean changed = disabledComponents.remove(componentClassName); - changed |= enabledComponents.add(componentClassName); + void setEnabled(int state, int userId) { + enabled.put(userId, state); + } + + int getEnabled(int userId) { + return enabled.get(userId, COMPONENT_ENABLED_STATE_DEFAULT); + } + + boolean getStopped(int userId) { + return stopped.get(userId, false); + } + + void setStopped(boolean stop, int userId) { + stopped.put(userId, stop); + } + + boolean getNotLaunched(int userId) { + return notLaunched.get(userId, false); + } + + void setNotLaunched(boolean stop, int userId) { + notLaunched.put(userId, stop); + } + + HashSet<String> getEnabledComponents(int userId) { + return getComponentHashSet(enabledComponents, userId); + } + + HashSet<String> getDisabledComponents(int userId) { + return getComponentHashSet(disabledComponents, userId); + } + + void setEnabledComponents(HashSet<String> components, int userId) { + enabledComponents.put(userId, components); + } + + void setDisabledComponents(HashSet<String> components, int userId) { + disabledComponents.put(userId, components); + } + + private HashSet<String> getComponentHashSet(SparseArray<HashSet<String>> setArray, int userId) { + HashSet<String> set = setArray.get(userId); + if (set == null) { + set = new HashSet<String>(1); + setArray.put(userId, set); + } + return set; + } + + void addDisabledComponent(String componentClassName, int userId) { + HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); + disabled.add(componentClassName); + } + + void addEnabledComponent(String componentClassName, int userId) { + HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); + enabled.add(componentClassName); + } + + boolean enableComponentLPw(String componentClassName, int userId) { + HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); + HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); + boolean changed = disabled.remove(componentClassName); + changed |= enabled.add(componentClassName); return changed; } - boolean disableComponentLPw(String componentClassName) { - boolean changed = enabledComponents.remove(componentClassName); - changed |= disabledComponents.add(componentClassName); + boolean disableComponentLPw(String componentClassName, int userId) { + HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); + HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); + boolean changed = enabled.remove(componentClassName); + changed |= disabled.add(componentClassName); return changed; } - boolean restoreComponentLPw(String componentClassName) { - boolean changed = enabledComponents.remove(componentClassName); - changed |= disabledComponents.remove(componentClassName); + boolean restoreComponentLPw(String componentClassName, int userId) { + HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); + HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); + boolean changed = enabled.remove(componentClassName); + changed |= disabled.remove(componentClassName); return changed; } - int getCurrentEnabledStateLPr(String componentName) { - if (enabledComponents.contains(componentName)) { + int getCurrentEnabledStateLPr(String componentName, int userId) { + HashSet<String> disabled = getComponentHashSet(disabledComponents, userId); + HashSet<String> enabled = getComponentHashSet(enabledComponents, userId); + if (enabled.contains(componentName)) { return COMPONENT_ENABLED_STATE_ENABLED; - } else if (disabledComponents.contains(componentName)) { + } else if (disabled.contains(componentName)) { return COMPONENT_ENABLED_STATE_DISABLED; } else { return COMPONENT_ENABLED_STATE_DEFAULT; } } -}
\ No newline at end of file + + 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 363d020..bb7f4fc 100644 --- a/services/java/com/android/server/pm/Settings.java +++ b/services/java/com/android/server/pm/Settings.java @@ -32,6 +32,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; +import android.app.AppGlobals; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ApplicationInfo; @@ -40,11 +41,14 @@ import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PermissionInfo; import android.content.pm.Signature; +import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.os.Binder; import android.os.Environment; import android.os.FileUtils; import android.os.Process; +import android.os.RemoteException; +import android.os.UserId; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -63,6 +67,7 @@ import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Map; import libcore.io.IoUtils; @@ -78,6 +83,17 @@ final class Settings { private static final String TAG_READ_EXTERNAL_STORAGE = "read-external-storage"; private static final String ATTR_ENFORCEMENT = "enforcement"; + private static final String TAG_ITEM = "item"; + private static final String TAG_DISABLED_COMPONENTS = "disabled-components"; + private static final String TAG_ENABLED_COMPONENTS = "enabled-components"; + private static final String TAG_PACKAGE_RESTRICTIONS = "package-restrictions"; + private static final String TAG_PACKAGE = "pkg"; + + private static final String ATTR_NAME = "name"; + private static final String ATTR_NOT_LAUNCHED = "nl"; + private static final String ATTR_ENABLED = "enabled"; + private static final String ATTR_STOPPED = "stopped"; + private final File mSettingsFilename; private final File mBackupSettingsFilename; private final File mPackageListFilename; @@ -153,19 +169,24 @@ final class Settings { */ private final ArrayList<PendingPackage> mPendingPackages = new ArrayList<PendingPackage>(); + private final File mSystemDir; Settings() { - File dataDir = Environment.getDataDirectory(); - File systemDir = new File(dataDir, "system"); - systemDir.mkdirs(); - FileUtils.setPermissions(systemDir.toString(), + this(Environment.getDataDirectory()); + } + + Settings(File dataDir) { + mSystemDir = new File(dataDir, "system"); + mSystemDir.mkdirs(); + FileUtils.setPermissions(mSystemDir.toString(), FileUtils.S_IRWXU|FileUtils.S_IRWXG |FileUtils.S_IROTH|FileUtils.S_IXOTH, -1, -1); - mSettingsFilename = new File(systemDir, "packages.xml"); - mBackupSettingsFilename = new File(systemDir, "packages-backup.xml"); - mPackageListFilename = new File(systemDir, "packages.list"); - mStoppedPackagesFilename = new File(systemDir, "packages-stopped.xml"); - mBackupStoppedPackagesFilename = new File(systemDir, "packages-stopped-backup.xml"); + mSettingsFilename = new File(mSystemDir, "packages.xml"); + mBackupSettingsFilename = new File(mSystemDir, "packages-backup.xml"); + mPackageListFilename = new File(mSystemDir, "packages.list"); + // Deprecated: Needed for migration + mStoppedPackagesFilename = new File(mSystemDir, "packages-stopped.xml"); + mBackupStoppedPackagesFilename = new File(mSystemDir, "packages-stopped-backup.xml"); } PackageSetting getPackageLPw(PackageParser.Package pkg, PackageSetting origPackage, @@ -254,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.userId, p.versionCode, p.pkgFlags); + p.nativeLibraryPathString, p.appId, p.versionCode, p.pkgFlags); mDisabledSysPackages.remove(name); return ret; } @@ -263,7 +284,7 @@ final class Settings { String nativeLibraryPathString, int uid, int vc, int pkgFlags) { PackageSetting p = mPackages.get(name); if (p != null) { - if (p.userId == uid) { + if (p.appId == uid) { return p; } PackageManagerService.reportSettingsProblem(Log.ERROR, @@ -272,7 +293,7 @@ final class Settings { } p = new PackageSetting(name, realName, codePath, resourcePath, nativeLibraryPathString, vc, pkgFlags); - p.userId = uid; + p.appId = uid; if (addUserIdLPw(uid, p, name)) { mPackages.put(name, p); return p; @@ -323,7 +344,7 @@ final class Settings { } } } - + private PackageSetting getPackageLPw(String name, PackageSetting origPackage, String realName, SharedUserSetting sharedUser, File codePath, File resourcePath, String nativeLibraryPathString, int vc, int pkgFlags, boolean create, boolean add) { @@ -335,13 +356,13 @@ final class Settings { // This is an updated system app with versions in both system // and data partition. Just let the most recent version // take precedence. - Slog.w(PackageManagerService.TAG, "Trying to update system app code path from " + - p.codePathString + " to " + codePath.toString()); + Slog.w(PackageManagerService.TAG, "Trying to update system app code path from " + + p.codePathString + " to " + codePath.toString()); } else { // Just a change in the code path is not an issue, but // let's log a message about it. - Slog.i(PackageManagerService.TAG, "Package " + name + " codePath changed from " + p.codePath - + " to " + codePath + "; Retaining data and using new"); + Slog.i(PackageManagerService.TAG, "Package " + name + " codePath changed from " + + p.codePath + " to " + codePath + "; Retaining data and using new"); /* * Since we've changed paths, we need to prefer the new * native library path over the one stored in the @@ -378,15 +399,15 @@ final class Settings { // We are consuming the data from an existing package. p = new PackageSetting(origPackage.name, name, codePath, resourcePath, nativeLibraryPathString, vc, pkgFlags); - if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + name - + " is adopting original package " + origPackage.name); + if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package " + + name + " is adopting original package " + origPackage.name); // Note that we will retain the new package's signature so // that we can keep its data. PackageSignatures s = p.signatures; p.copyFrom(origPackage); p.signatures = s; p.sharedUser = origPackage.sharedUser; - p.userId = origPackage.userId; + p.appId = origPackage.appId; p.origPackage = origPackage; mRenamedPackages.put(name, origPackage.name); name = origPackage.name; @@ -404,11 +425,17 @@ final class Settings { e.fillInStackTrace(); Slog.i(PackageManagerService.TAG, "Stopping package " + name, e); } - p.stopped = true; - p.notLaunched = true; + List<UserInfo> users = getAllUsers(); + if (users != null) { + for (UserInfo user : users) { + p.setStopped(true, user.id); + p.setNotLaunched(true, user.id); + writePackageRestrictionsLPr(user.id); + } + } } if (sharedUser != null) { - p.userId = sharedUser.userId; + p.appId = sharedUser.userId; } else { // Clone the setting here for disabled system packages PackageSetting dis = mDisabledSysPackages.get(name); @@ -420,21 +447,31 @@ final class Settings { if (dis.signatures.mSignatures != null) { p.signatures.mSignatures = dis.signatures.mSignatures.clone(); } - p.userId = dis.userId; + p.appId = dis.appId; // Clone permissions p.grantedPermissions = new HashSet<String>(dis.grantedPermissions); // Clone component info - p.disabledComponents = new HashSet<String>(dis.disabledComponents); - p.enabledComponents = new HashSet<String>(dis.enabledComponents); + List<UserInfo> users = getAllUsers(); + if (users != null) { + for (UserInfo user : users) { + int userId = user.id; + p.setDisabledComponents( + new HashSet<String>(dis.getDisabledComponents(userId)), + userId); + p.setEnabledComponents( + new HashSet<String>(dis.getEnabledComponents(userId)), + userId); + } + } // Add new setting to list of user ids - addUserIdLPw(p.userId, p, name); + addUserIdLPw(p.appId, p, name); } else { // Assign new user id - p.userId = newUserIdLPw(p); + p.appId = newUserIdLPw(p); } } } - if (p.userId < 0) { + if (p.appId < 0) { PackageManagerService.reportSettingsProblem(Log.WARN, "Package " + name + " could not be assigned a valid uid"); return null; @@ -450,8 +487,8 @@ final class Settings { void insertPackageSettingLPw(PackageSetting p, PackageParser.Package pkg) { p.pkg = pkg; - pkg.mSetEnabled = p.enabled; - pkg.mSetStopped = p.stopped; + // pkg.mSetEnabled = p.getEnabled(userId); + // pkg.mSetStopped = p.getStopped(userId); final String codePath = pkg.applicationInfo.sourceDir; final String resourcePath = pkg.applicationInfo.publicSourceDir; // Update code path if needed @@ -475,18 +512,18 @@ final class Settings { p.nativeLibraryPathString = nativeLibraryPath; } // Update version code if needed - if (pkg.mVersionCode != p.versionCode) { + if (pkg.mVersionCode != p.versionCode) { p.versionCode = pkg.mVersionCode; } - // Update signatures if needed. - if (p.signatures.mSignatures == null) { - p.signatures.assignSignatures(pkg.mSignatures); - } - // If this app defines a shared user id initialize - // the shared user signatures as well. - if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) { - p.sharedUser.signatures.assignSignatures(pkg.mSignatures); - } + // Update signatures if needed. + if (p.signatures.mSignatures == null) { + p.signatures.assignSignatures(pkg.mSignatures); + } + // If this app defines a shared user id initialize + // the shared user signatures as well. + if (p.sharedUser != null && p.sharedUser.signatures.mSignatures == null) { + p.sharedUser.signatures.assignSignatures(pkg.mSignatures); + } addPackageSettingLPw(p, pkg.packageName, p.sharedUser); } @@ -502,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.userId != sharedUser.userId) { + } else if (p.appId != sharedUser.userId) { PackageManagerService.reportSettingsProblem(Log.ERROR, - "Package " + p.name + " was user id " + p.userId + "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!"); @@ -512,7 +549,7 @@ final class Settings { sharedUser.packages.add(p); p.sharedUser = sharedUser; - p.userId = sharedUser.userId; + p.appId = sharedUser.userId; } } @@ -577,8 +614,8 @@ final class Settings { return p.sharedUser.userId; } } else { - removeUserIdLPw(p.userId); - return p.userId; + removeUserIdLPw(p.appId); + return p.appId; } } return -1; @@ -591,7 +628,7 @@ final class Settings { p.sharedUser.packages.remove(p); p.sharedUser.packages.add(newp); } else { - replaceUserIdLPw(p.userId, newp); + replaceUserIdLPw(p.appId, newp); } } mPackages.put(name, newp); @@ -658,50 +695,269 @@ final class Settings { } } - void writeStoppedLPr() { + private File getUserPackagesStateFile(int userId) { + return new File(mSystemDir, + "users/" + userId + "/package-restrictions.xml"); + } + + private File getUserPackagesStateBackupFile(int userId) { + return new File(mSystemDir, + "users/" + userId + "/package-restrictions-backup.xml"); + } + + void writeAllUsersPackageRestrictionsLPr() { + List<UserInfo> users = getAllUsers(); + if (users == null) return; + + for (UserInfo user : users) { + writePackageRestrictionsLPr(user.id); + } + } + + void readAllUsersPackageRestrictionsLPr() { + List<UserInfo> users = getAllUsers(); + if (users == null) { + readPackageRestrictionsLPr(0); + return; + } + + for (UserInfo user : users) { + readPackageRestrictionsLPr(user.id); + } + } + + void readPackageRestrictionsLPr(int userId) { + FileInputStream str = null; + File userPackagesStateFile = getUserPackagesStateFile(userId); + File backupFile = getUserPackagesStateBackupFile(userId); + if (backupFile.exists()) { + try { + str = new FileInputStream(backupFile); + mReadMessages.append("Reading from backup stopped packages file\n"); + PackageManagerService.reportSettingsProblem(Log.INFO, + "Need to read from backup stopped packages file"); + if (userPackagesStateFile.exists()) { + // If both the backup and normal file exist, we + // ignore the normal one since it might have been + // corrupted. + Slog.w(PackageManagerService.TAG, "Cleaning up stopped packages file " + + userPackagesStateFile); + userPackagesStateFile.delete(); + } + } catch (java.io.IOException e) { + // We'll try for the normal settings file. + } + } + + try { + if (str == null) { + if (!userPackagesStateFile.exists()) { + mReadMessages.append("No stopped packages file found\n"); + PackageManagerService.reportSettingsProblem(Log.INFO, + "No stopped packages file; " + + "assuming all started"); + // At first boot, make sure no packages are stopped. + // We usually want to have third party apps initialize + // in the stopped state, but not at first boot. + for (PackageSetting pkg : mPackages.values()) { + pkg.setStopped(false, userId); + pkg.setNotLaunched(false, userId); + } + return; + } + str = new FileInputStream(userPackagesStateFile); + } + final XmlPullParser parser = Xml.newPullParser(); + parser.setInput(str, null); + + int type; + while ((type=parser.next()) != XmlPullParser.START_TAG + && type != XmlPullParser.END_DOCUMENT) { + ; + } + + if (type != XmlPullParser.START_TAG) { + mReadMessages.append("No start tag found in package restrictions file\n"); + PackageManagerService.reportSettingsProblem(Log.WARN, + "No start tag found in package manager stopped packages"); + return; + } + + int outerDepth = parser.getDepth(); + PackageSetting ps = null; + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + + String tagName = parser.getName(); + if (tagName.equals(TAG_PACKAGE)) { + String name = parser.getAttributeValue(null, ATTR_NAME); + ps = mPackages.get(name); + if (ps == null) { + Slog.w(PackageManagerService.TAG, "No package known for stopped package: " + + name); + XmlUtils.skipCurrentTag(parser); + continue; + } + String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED); + int enabled = enabledStr == null ? COMPONENT_ENABLED_STATE_DEFAULT + : Integer.parseInt(enabledStr); + ps.setEnabled(enabled, userId); + String stoppedStr = parser.getAttributeValue(null, ATTR_STOPPED); + boolean stopped = stoppedStr == null ? false : Boolean.parseBoolean(stoppedStr); + ps.setStopped(stopped, userId); + String notLaunchedStr = parser.getAttributeValue(null, ATTR_NOT_LAUNCHED); + boolean notLaunched = stoppedStr == null ? false + : Boolean.parseBoolean(notLaunchedStr); + ps.setNotLaunched(notLaunched, userId); + + int packageDepth = parser.getDepth(); + while ((type=parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > packageDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + tagName = parser.getName(); + if (tagName.equals(TAG_ENABLED_COMPONENTS)) { + HashSet<String> components = readComponentsLPr(parser); + ps.setEnabledComponents(components, userId); + } else if (tagName.equals(TAG_DISABLED_COMPONENTS)) { + HashSet<String> components = readComponentsLPr(parser); + ps.setDisabledComponents(components, userId); + } + } + } else { + Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: " + + parser.getName()); + XmlUtils.skipCurrentTag(parser); + } + } + + str.close(); + + } catch (XmlPullParserException e) { + mReadMessages.append("Error reading: " + e.toString()); + PackageManagerService.reportSettingsProblem(Log.ERROR, + "Error reading stopped packages: " + e); + Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e); + + } catch (java.io.IOException e) { + mReadMessages.append("Error reading: " + e.toString()); + PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); + Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e); + } + } + + private HashSet<String> readComponentsLPr(XmlPullParser parser) + throws IOException, XmlPullParserException { + HashSet<String> components = new HashSet<String>(); + int type; + int outerDepth = parser.getDepth(); + String tagName; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && (type != XmlPullParser.END_TAG + || parser.getDepth() > outerDepth)) { + if (type == XmlPullParser.END_TAG + || type == XmlPullParser.TEXT) { + continue; + } + tagName = parser.getName(); + if (tagName.equals(TAG_ITEM)) { + String componentName = parser.getAttributeValue(null, ATTR_NAME); + if (componentName != null) { + components.add(componentName); + } + } + } + return components; + } + + void writePackageRestrictionsLPr(int userId) { // Keep the old stopped packages around until we know the new ones have // been successfully written. - if (mStoppedPackagesFilename.exists()) { + File userPackagesStateFile = getUserPackagesStateFile(userId); + File backupFile = getUserPackagesStateBackupFile(userId); + new File(userPackagesStateFile.getParent()).mkdirs(); + if (userPackagesStateFile.exists()) { // Presence of backup settings file indicates that we failed // to persist packages earlier. So preserve the older // backup for future reference since the current packages // might have been corrupted. - if (!mBackupStoppedPackagesFilename.exists()) { - if (!mStoppedPackagesFilename.renameTo(mBackupStoppedPackagesFilename)) { - Log.wtf(PackageManagerService.TAG, "Unable to backup package manager stopped packages, " + if (!backupFile.exists()) { + if (!userPackagesStateFile.renameTo(backupFile)) { + Log.wtf(PackageManagerService.TAG, "Unable to backup user packages state file, " + "current changes will be lost at reboot"); return; } } else { - mStoppedPackagesFilename.delete(); + userPackagesStateFile.delete(); Slog.w(PackageManagerService.TAG, "Preserving older stopped packages backup"); } } try { - final FileOutputStream fstr = new FileOutputStream(mStoppedPackagesFilename); + final FileOutputStream fstr = new FileOutputStream(userPackagesStateFile); final BufferedOutputStream str = new BufferedOutputStream(fstr); - //XmlSerializer serializer = XmlUtils.serializerInstance(); final XmlSerializer serializer = new FastXmlSerializer(); serializer.setOutput(str, "utf-8"); serializer.startDocument(null, true); serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true); - serializer.startTag(null, "stopped-packages"); + serializer.startTag(null, TAG_PACKAGE_RESTRICTIONS); for (final PackageSetting pkg : mPackages.values()) { - if (pkg.stopped) { - serializer.startTag(null, "pkg"); - serializer.attribute(null, "name", pkg.name); - if (pkg.notLaunched) { - serializer.attribute(null, "nl", "1"); + if (pkg.getStopped(userId) + || pkg.getNotLaunched(userId) + || pkg.getEnabled(userId) != COMPONENT_ENABLED_STATE_DEFAULT + || pkg.getEnabledComponents(userId).size() > 0 + || pkg.getDisabledComponents(userId).size() > 0) { + serializer.startTag(null, TAG_PACKAGE); + serializer.attribute(null, ATTR_NAME, pkg.name); + boolean stopped = pkg.getStopped(userId); + boolean notLaunched = pkg.getNotLaunched(userId); + int enabled = pkg.getEnabled(userId); + HashSet<String> enabledComponents = pkg.getEnabledComponents(userId); + HashSet<String> disabledComponents = pkg.getDisabledComponents(userId); + + if (stopped) { + serializer.attribute(null, ATTR_STOPPED, "true"); + } + if (notLaunched) { + serializer.attribute(null, ATTR_NOT_LAUNCHED, "true"); + } + if (enabled != COMPONENT_ENABLED_STATE_DEFAULT) { + serializer.attribute(null, ATTR_ENABLED, Integer.toString(enabled)); } - serializer.endTag(null, "pkg"); + if (enabledComponents.size() > 0) { + serializer.startTag(null, TAG_ENABLED_COMPONENTS); + for (final String name : enabledComponents) { + serializer.startTag(null, TAG_ITEM); + serializer.attribute(null, ATTR_NAME, name); + serializer.endTag(null, TAG_ITEM); + } + serializer.endTag(null, TAG_ENABLED_COMPONENTS); + } + if (disabledComponents.size() > 0) { + serializer.startTag(null, TAG_DISABLED_COMPONENTS); + for (final String name : disabledComponents) { + serializer.startTag(null, TAG_ITEM); + serializer.attribute(null, ATTR_NAME, name); + serializer.endTag(null, TAG_ITEM); + } + serializer.endTag(null, TAG_DISABLED_COMPONENTS); + } + serializer.endTag(null, TAG_PACKAGE); } } - serializer.endTag(null, "stopped-packages"); + serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS); serializer.endDocument(); @@ -711,8 +967,8 @@ final class Settings { // New settings successfully written, old ones are no longer // needed. - mBackupStoppedPackagesFilename.delete(); - FileUtils.setPermissions(mStoppedPackagesFilename.toString(), + backupFile.delete(); + FileUtils.setPermissions(userPackagesStateFile.toString(), FileUtils.S_IRUSR|FileUtils.S_IWUSR |FileUtils.S_IRGRP|FileUtils.S_IWGRP, -1, -1); @@ -720,26 +976,30 @@ final class Settings { // Done, all is good! return; } catch(java.io.IOException e) { - Log.wtf(PackageManagerService.TAG, "Unable to write package manager stopped packages, " + Log.wtf(PackageManagerService.TAG, + "Unable to write package manager user packages state, " + " current changes will be lost at reboot", e); } // Clean up partially written files - if (mStoppedPackagesFilename.exists()) { - if (!mStoppedPackagesFilename.delete()) { - Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: " + mStoppedPackagesFilename); + if (userPackagesStateFile.exists()) { + if (!userPackagesStateFile.delete()) { + Log.i(PackageManagerService.TAG, "Failed to clean up mangled file: " + + mStoppedPackagesFilename); } } } // Note: assumed "stopped" field is already cleared in all packages. + // Legacy reader, used to read in the old file format after an upgrade. Not used after that. void readStoppedLPw() { FileInputStream str = null; if (mBackupStoppedPackagesFilename.exists()) { try { str = new FileInputStream(mBackupStoppedPackagesFilename); mReadMessages.append("Reading from backup stopped packages file\n"); - PackageManagerService.reportSettingsProblem(Log.INFO, "Need to read from backup stopped packages file"); + PackageManagerService.reportSettingsProblem(Log.INFO, + "Need to read from backup stopped packages file"); if (mSettingsFilename.exists()) { // If both the backup and normal file exist, we // ignore the normal one since it might have been @@ -757,14 +1017,14 @@ final class Settings { if (str == null) { if (!mStoppedPackagesFilename.exists()) { mReadMessages.append("No stopped packages file found\n"); - PackageManagerService.reportSettingsProblem(Log.INFO, "No stopped packages file file; " - + "assuming all started"); + PackageManagerService.reportSettingsProblem(Log.INFO, + "No stopped packages file file; assuming all started"); // At first boot, make sure no packages are stopped. // We usually want to have third party apps initialize // in the stopped state, but not at first boot. for (PackageSetting pkg : mPackages.values()) { - pkg.stopped = false; - pkg.notLaunched = false; + pkg.setStopped(false, 0); + pkg.setNotLaunched(false, 0); } return; } @@ -796,16 +1056,17 @@ final class Settings { } String tagName = parser.getName(); - if (tagName.equals("pkg")) { - String name = parser.getAttributeValue(null, "name"); + if (tagName.equals(TAG_PACKAGE)) { + String name = parser.getAttributeValue(null, ATTR_NAME); PackageSetting ps = mPackages.get(name); if (ps != null) { - ps.stopped = true; - if ("1".equals(parser.getAttributeValue(null, "nl"))) { - ps.notLaunched = true; + ps.setStopped(true, 0); + if ("1".equals(parser.getAttributeValue(null, ATTR_NOT_LAUNCHED))) { + ps.setNotLaunched(true, 0); } } else { - Slog.w(PackageManagerService.TAG, "No package known for stopped package: " + name); + Slog.w(PackageManagerService.TAG, + "No package known for stopped package: " + name); } XmlUtils.skipCurrentTag(parser); } else { @@ -817,12 +1078,13 @@ final class Settings { str.close(); - } catch(XmlPullParserException e) { + } catch (XmlPullParserException e) { mReadMessages.append("Error reading: " + e.toString()); - PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading stopped packages: " + e); + PackageManagerService.reportSettingsProblem(Log.ERROR, + "Error reading stopped packages: " + e); Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e); - } catch(java.io.IOException e) { + } catch (java.io.IOException e) { mReadMessages.append("Error reading: " + e.toString()); PackageManagerService.reportSettingsProblem(Log.ERROR, "Error reading settings: " + e); Log.wtf(PackageManagerService.TAG, "Error reading package manager stopped packages", e); @@ -906,23 +1168,23 @@ final class Settings { serializer.startTag(null, "preferred-activities"); for (final PreferredActivity pa : mPreferredActivities.filterSet()) { - serializer.startTag(null, "item"); + serializer.startTag(null, TAG_ITEM); pa.writeToXml(serializer); - serializer.endTag(null, "item"); + serializer.endTag(null, TAG_ITEM); } serializer.endTag(null, "preferred-activities"); for (final SharedUserSetting usr : mSharedUsers.values()) { serializer.startTag(null, "shared-user"); - serializer.attribute(null, "name", usr.name); + serializer.attribute(null, ATTR_NAME, usr.name); serializer.attribute(null, "userId", Integer.toString(usr.userId)); usr.signatures.writeXml(serializer, "sigs", mPastSignatures); serializer.startTag(null, "perms"); for (String name : usr.grantedPermissions) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); + serializer.startTag(null, TAG_ITEM); + serializer.attribute(null, ATTR_NAME, name); + serializer.endTag(null, TAG_ITEM); } serializer.endTag(null, "perms"); serializer.endTag(null, "shared-user"); @@ -931,7 +1193,7 @@ final class Settings { if (mPackagesToBeCleaned.size() > 0) { for (int i=0; i<mPackagesToBeCleaned.size(); i++) { serializer.startTag(null, "cleaning-package"); - serializer.attribute(null, "name", mPackagesToBeCleaned.get(i)); + serializer.attribute(null, ATTR_NAME, mPackagesToBeCleaned.get(i)); serializer.endTag(null, "cleaning-package"); } } @@ -1016,8 +1278,7 @@ final class Settings { |FileUtils.S_IRGRP|FileUtils.S_IWGRP, -1, -1); - writeStoppedLPr(); - + writeAllUsersPackageRestrictionsLPr(); return; } catch(XmlPullParserException e) { @@ -1030,7 +1291,8 @@ final class Settings { // Clean up partially written files if (mSettingsFilename.exists()) { if (!mSettingsFilename.delete()) { - Log.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: " + mSettingsFilename); + Log.wtf(PackageManagerService.TAG, "Failed to clean up mangled file: " + + mSettingsFilename); } } //Debug.stopMethodTracing(); @@ -1039,7 +1301,7 @@ final class Settings { void writeDisabledSysPackageLPr(XmlSerializer serializer, final PackageSetting pkg) throws java.io.IOException { serializer.startTag(null, "updated-package"); - serializer.attribute(null, "name", pkg.name); + serializer.attribute(null, ATTR_NAME, pkg.name); if (pkg.realName != null) { serializer.attribute(null, "realName", pkg.realName); } @@ -1055,9 +1317,9 @@ final class Settings { serializer.attribute(null, "nativeLibraryPath", pkg.nativeLibraryPathString); } if (pkg.sharedUser == null) { - serializer.attribute(null, "userId", Integer.toString(pkg.userId)); + serializer.attribute(null, "userId", Integer.toString(pkg.appId)); } else { - serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId)); + serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId)); } serializer.startTag(null, "perms"); if (pkg.sharedUser == null) { @@ -1072,9 +1334,9 @@ final class Settings { // this wont // match the semantics of grantedPermissions. So write all // permissions. - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); + serializer.startTag(null, TAG_ITEM); + serializer.attribute(null, ATTR_NAME, name); + serializer.endTag(null, TAG_ITEM); } } } @@ -1085,7 +1347,7 @@ final class Settings { void writePackageLPr(XmlSerializer serializer, final PackageSetting pkg) throws java.io.IOException { serializer.startTag(null, "package"); - serializer.attribute(null, "name", pkg.name); + serializer.attribute(null, ATTR_NAME, pkg.name); if (pkg.realName != null) { serializer.attribute(null, "realName", pkg.realName); } @@ -1102,16 +1364,13 @@ 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.userId)); + serializer.attribute(null, "userId", Integer.toString(pkg.appId)); } else { - serializer.attribute(null, "sharedUserId", Integer.toString(pkg.userId)); + serializer.attribute(null, "sharedUserId", Integer.toString(pkg.appId)); } if (pkg.uidError) { serializer.attribute(null, "uidError", "true"); } - if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) { - serializer.attribute(null, "enabled", Integer.toString(pkg.enabled)); - } if (pkg.installStatus == PackageSettingBase.PKG_INSTALL_INCOMPLETE) { serializer.attribute(null, "installStatus", "false"); } @@ -1127,31 +1386,13 @@ final class Settings { // empty permissions list so permissionsFixed will // be set. for (final String name : pkg.grantedPermissions) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); + serializer.startTag(null, TAG_ITEM); + serializer.attribute(null, ATTR_NAME, name); + serializer.endTag(null, TAG_ITEM); } } serializer.endTag(null, "perms"); } - if (pkg.disabledComponents.size() > 0) { - serializer.startTag(null, "disabled-components"); - for (final String name : pkg.disabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "disabled-components"); - } - if (pkg.enabledComponents.size() > 0) { - serializer.startTag(null, "enabled-components"); - for (final String name : pkg.enabledComponents) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", name); - serializer.endTag(null, "item"); - } - serializer.endTag(null, "enabled-components"); - } serializer.endTag(null, "package"); } @@ -1159,8 +1400,8 @@ final class Settings { void writePermissionLPr(XmlSerializer serializer, BasePermission bp) throws XmlPullParserException, java.io.IOException { if (bp.type != BasePermission.TYPE_BUILTIN && bp.sourcePackage != null) { - serializer.startTag(null, "item"); - serializer.attribute(null, "name", bp.name); + serializer.startTag(null, TAG_ITEM); + serializer.attribute(null, ATTR_NAME, bp.name); serializer.attribute(null, "package", bp.sourcePackage); if (bp.protectionLevel != PermissionInfo.PROTECTION_NORMAL) { serializer.attribute(null, "protection", Integer.toString(bp.protectionLevel)); @@ -1180,7 +1421,7 @@ final class Settings { } } } - serializer.endTag(null, "item"); + serializer.endTag(null, TAG_ITEM); } } @@ -1198,7 +1439,7 @@ final class Settings { return ret; } - boolean readLPw() { + boolean readLPw(List<UserInfo> users) { FileInputStream str = null; if (mBackupSettingsFilename.exists()) { try { @@ -1273,7 +1514,7 @@ final class Settings { } else if (tagName.equals("updated-package")) { readDisabledSysPackageLPw(parser); } else if (tagName.equals("cleaning-package")) { - String name = parser.getAttributeValue(null, "name"); + String name = parser.getAttributeValue(null, ATTR_NAME); if (name != null) { mPackagesToBeCleaned.add(name); } @@ -1366,14 +1607,29 @@ final class Settings { final Iterator<PackageSetting> disabledIt = mDisabledSysPackages.values().iterator(); while (disabledIt.hasNext()) { final PackageSetting disabledPs = disabledIt.next(); - final Object id = getUserIdLPr(disabledPs.userId); + final Object id = getUserIdLPr(disabledPs.appId); if (id != null && id instanceof SharedUserSetting) { disabledPs.sharedUser = (SharedUserSetting) id; } } - readStoppedLPw(); - + if (mBackupStoppedPackagesFilename.exists() + || mStoppedPackagesFilename.exists()) { + // Read old file + readStoppedLPw(); + mBackupStoppedPackagesFilename.delete(); + mStoppedPackagesFilename.delete(); + // Migrate to new file format + writePackageRestrictionsLPr(0); + } else { + if (users == null) { + readPackageRestrictionsLPr(0); + } else { + for (UserInfo user : users) { + readPackageRestrictionsLPr(user.id); + } + } + } mReadMessages.append("Read completed successfully: " + mPackages.size() + " packages, " + mSharedUsers.size() + " shared uids\n"); @@ -1407,8 +1663,8 @@ final class Settings { } final String tagName = parser.getName(); - if (tagName.equals("item")) { - final String name = parser.getAttributeValue(null, "name"); + if (tagName.equals(TAG_ITEM)) { + final String name = parser.getAttributeValue(null, ATTR_NAME); final String sourcePackage = parser.getAttributeValue(null, "package"); final String ptype = parser.getAttributeValue(null, "type"); if (name != null && sourcePackage != null) { @@ -1444,7 +1700,7 @@ final class Settings { private void readDisabledSysPackageLPw(XmlPullParser parser) throws XmlPullParserException, IOException { - String name = parser.getAttributeValue(null, "name"); + String name = parser.getAttributeValue(null, ATTR_NAME); String realName = parser.getAttributeValue(null, "realName"); String codePathStr = parser.getAttributeValue(null, "codePath"); String resourcePathStr = parser.getAttributeValue(null, "resourcePath"); @@ -1497,10 +1753,10 @@ final class Settings { } } String idStr = parser.getAttributeValue(null, "userId"); - ps.userId = idStr != null ? Integer.parseInt(idStr) : 0; - if (ps.userId <= 0) { + ps.appId = idStr != null ? Integer.parseInt(idStr) : 0; + if (ps.appId <= 0) { String sharedIdStr = parser.getAttributeValue(null, "sharedUserId"); - ps.userId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; + ps.appId = sharedIdStr != null ? Integer.parseInt(sharedIdStr) : 0; } int outerDepth = parser.getDepth(); int type; @@ -1541,7 +1797,7 @@ final class Settings { String version = null; int versionCode = 0; try { - name = parser.getAttributeValue(null, "name"); + name = parser.getAttributeValue(null, ATTR_NAME); realName = parser.getAttributeValue(null, "realName"); idStr = parser.getAttributeValue(null, "userId"); uidError = parser.getAttributeValue(null, "uidError"); @@ -1672,17 +1928,18 @@ final class Settings { packageSetting.uidError = "true".equals(uidError); packageSetting.installerPackageName = installerPackageName; packageSetting.nativeLibraryPathString = nativeLibraryPathStr; - final String enabledStr = parser.getAttributeValue(null, "enabled"); + // Handle legacy string here for single-user mode + final String enabledStr = parser.getAttributeValue(null, ATTR_ENABLED); if (enabledStr != null) { try { - packageSetting.enabled = Integer.parseInt(enabledStr); + packageSetting.setEnabled(Integer.parseInt(enabledStr), 0 /* userId */); } catch (NumberFormatException e) { if (enabledStr.equalsIgnoreCase("true")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_ENABLED; + packageSetting.setEnabled(COMPONENT_ENABLED_STATE_ENABLED, 0); } else if (enabledStr.equalsIgnoreCase("false")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DISABLED; + packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DISABLED, 0); } else if (enabledStr.equalsIgnoreCase("default")) { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; + packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0); } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: package " + name @@ -1691,8 +1948,9 @@ final class Settings { } } } else { - packageSetting.enabled = COMPONENT_ENABLED_STATE_DEFAULT; + packageSetting.setEnabled(COMPONENT_ENABLED_STATE_DEFAULT, 0); } + final String installStatusStr = parser.getAttributeValue(null, "installStatus"); if (installStatusStr != null) { if (installStatusStr.equalsIgnoreCase("false")) { @@ -1711,10 +1969,11 @@ final class Settings { } String tagName = parser.getName(); - if (tagName.equals("disabled-components")) { - readDisabledComponentsLPw(packageSetting, parser); - } else if (tagName.equals("enabled-components")) { - readEnabledComponentsLPw(packageSetting, parser); + // Legacy + if (tagName.equals(TAG_DISABLED_COMPONENTS)) { + readDisabledComponentsLPw(packageSetting, parser, 0); + } else if (tagName.equals(TAG_ENABLED_COMPONENTS)) { + readEnabledComponentsLPw(packageSetting, parser, 0); } else if (tagName.equals("sigs")) { packageSetting.signatures.readXml(parser, mPastSignatures); } else if (tagName.equals("perms")) { @@ -1731,8 +1990,8 @@ final class Settings { } } - private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser) - throws IOException, XmlPullParserException { + private void readDisabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser, + int userId) throws IOException, XmlPullParserException { int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -1742,10 +2001,10 @@ final class Settings { } String tagName = parser.getName(); - if (tagName.equals("item")) { - String name = parser.getAttributeValue(null, "name"); + if (tagName.equals(TAG_ITEM)) { + String name = parser.getAttributeValue(null, ATTR_NAME); if (name != null) { - packageSetting.disabledComponents.add(name.intern()); + packageSetting.addDisabledComponent(name.intern(), userId); } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <disabled-components> has" @@ -1759,8 +2018,8 @@ final class Settings { } } - private void readEnabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser) - throws IOException, XmlPullParserException { + private void readEnabledComponentsLPw(PackageSettingBase packageSetting, XmlPullParser parser, + int userId) throws IOException, XmlPullParserException { int outerDepth = parser.getDepth(); int type; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -1770,10 +2029,10 @@ final class Settings { } String tagName = parser.getName(); - if (tagName.equals("item")) { - String name = parser.getAttributeValue(null, "name"); + if (tagName.equals(TAG_ITEM)) { + String name = parser.getAttributeValue(null, ATTR_NAME); if (name != null) { - packageSetting.enabledComponents.add(name.intern()); + packageSetting.addEnabledComponent(name.intern(), userId); } else { PackageManagerService.reportSettingsProblem(Log.WARN, "Error in package manager settings: <enabled-components> has" @@ -1787,13 +2046,13 @@ final class Settings { } } - private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException, IOException { + private void readSharedUserLPw(XmlPullParser parser) throws XmlPullParserException,IOException { String name = null; String idStr = null; int pkgFlags = 0; SharedUserSetting su = null; try { - name = parser.getAttributeValue(null, "name"); + name = parser.getAttributeValue(null, ATTR_NAME); idStr = parser.getAttributeValue(null, "userId"); int userId = idStr != null ? Integer.parseInt(idStr) : 0; if ("true".equals(parser.getAttributeValue(null, "system"))) { @@ -1859,8 +2118,8 @@ final class Settings { } String tagName = parser.getName(); - if (tagName.equals("item")) { - String name = parser.getAttributeValue(null, "name"); + if (tagName.equals(TAG_ITEM)) { + String name = parser.getAttributeValue(null, ATTR_NAME); if (name != null) { outPerms.add(name.intern()); } else { @@ -1887,7 +2146,7 @@ final class Settings { } String tagName = parser.getName(); - if (tagName.equals("item")) { + if (tagName.equals(TAG_ITEM)) { PreferredActivity pa = new PreferredActivity(parser); if (pa.mPref.getParseError() == null) { mPreferredActivities.addFilter(pa); @@ -1905,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... @@ -1940,32 +2206,34 @@ final class Settings { return ps; } - boolean isEnabledLPr(ComponentInfo componentInfo, int flags) { + boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) { if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { return true; } - final PackageSetting packageSettings = mPackages.get(componentInfo.packageName); + final String pkgName = componentInfo.packageName; + final PackageSetting packageSettings = mPackages.get(pkgName); if (PackageManagerService.DEBUG_SETTINGS) { - Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = " + componentInfo.packageName - + " componentName = " + componentInfo.name); + Log.v(PackageManagerService.TAG, "isEnabledLock - packageName = " + + componentInfo.packageName + " componentName = " + componentInfo.name); Log.v(PackageManagerService.TAG, "enabledComponents: " - + Arrays.toString(packageSettings.enabledComponents.toArray())); + + Arrays.toString(packageSettings.getEnabledComponents(userId).toArray())); Log.v(PackageManagerService.TAG, "disabledComponents: " - + Arrays.toString(packageSettings.disabledComponents.toArray())); + + Arrays.toString(packageSettings.getDisabledComponents(userId).toArray())); } if (packageSettings == null) { return false; } - if (packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED - || packageSettings.enabled == COMPONENT_ENABLED_STATE_DISABLED_USER + final int enabled = packageSettings.getEnabled(userId); + if (enabled == COMPONENT_ENABLED_STATE_DISABLED + || enabled == COMPONENT_ENABLED_STATE_DISABLED_USER || (packageSettings.pkg != null && !packageSettings.pkg.applicationInfo.enabled - && packageSettings.enabled == COMPONENT_ENABLED_STATE_DEFAULT)) { + && enabled == COMPONENT_ENABLED_STATE_DEFAULT)) { return false; } - if (packageSettings.enabledComponents.contains(componentInfo.name)) { + if (packageSettings.getEnabledComponents(userId).contains(componentInfo.name)) { return true; } - if (packageSettings.disabledComponents.contains(componentInfo.name)) { + if (packageSettings.getDisabledComponents(userId).contains(componentInfo.name)) { return false; } return componentInfo.enabled; @@ -1979,35 +2247,36 @@ final class Settings { return pkg.installerPackageName; } - int getApplicationEnabledSettingLPr(String packageName) { + int getApplicationEnabledSettingLPr(String packageName, int userId) { final PackageSetting pkg = mPackages.get(packageName); if (pkg == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } - return pkg.enabled; + return pkg.getEnabled(userId); } - int getComponentEnabledSettingLPr(ComponentName componentName) { + int getComponentEnabledSettingLPr(ComponentName componentName, int userId) { final String packageName = componentName.getPackageName(); final PackageSetting pkg = mPackages.get(packageName); if (pkg == null) { throw new IllegalArgumentException("Unknown component: " + componentName); } final String classNameStr = componentName.getClassName(); - return pkg.getCurrentEnabledStateLPr(classNameStr); + return pkg.getCurrentEnabledStateLPr(classNameStr, userId); } - + boolean setPackageStoppedStateLPw(String packageName, boolean stopped, - boolean allowedByPermission, int uid) { + boolean allowedByPermission, int uid, int userId) { + int appId = UserId.getAppId(uid); final PackageSetting pkgSetting = mPackages.get(packageName); if (pkgSetting == null) { throw new IllegalArgumentException("Unknown package: " + packageName); } - if (!allowedByPermission && (uid != pkgSetting.userId)) { + if (!allowedByPermission && (appId != pkgSetting.appId)) { throw new SecurityException( "Permission Denial: attempt to change stopped state from pid=" + Binder.getCallingPid() - + ", uid=" + uid + ", package uid=" + pkgSetting.userId); + + ", uid=" + uid + ", package uid=" + pkgSetting.appId); } if (DEBUG_STOPPED) { if (stopped) { @@ -2016,22 +2285,33 @@ final class Settings { Slog.i(TAG, "Stopping package " + packageName, e); } } - if (pkgSetting.stopped != stopped) { - pkgSetting.stopped = stopped; - pkgSetting.pkg.mSetStopped = stopped; - if (pkgSetting.notLaunched) { + if (pkgSetting.getStopped(userId) != stopped) { + pkgSetting.setStopped(stopped, userId); + // pkgSetting.pkg.mSetStopped = stopped; + if (pkgSetting.getNotLaunched(userId)) { if (pkgSetting.installerPackageName != null) { PackageManagerService.sendPackageBroadcast(Intent.ACTION_PACKAGE_FIRST_LAUNCH, pkgSetting.name, null, - pkgSetting.installerPackageName, null); + pkgSetting.installerPackageName, null, userId); } - pkgSetting.notLaunched = false; + pkgSetting.setNotLaunched(false, userId); } return true; } return false; } + private List<UserInfo> getAllUsers() { + try { + return AppGlobals.getPackageManager().getUsers(); + } catch (RemoteException re) { + // Local to system process, shouldn't happen + } catch (NullPointerException npe) { + // packagemanager not yet initialized + } + return null; + } + static final void printFlags(PrintWriter pw, int val, Object[] spec) { pw.print("[ "); for (int i=0; i<spec.length; i+=2) { @@ -2096,7 +2376,7 @@ final class Settings { pw.println(ps.name); } - pw.print(" userId="); pw.print(ps.userId); + 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); @@ -2169,18 +2449,24 @@ final class Settings { pw.print(" haveGids="); pw.println(ps.haveGids); pw.print(" pkgFlags=0x"); pw.print(Integer.toHexString(ps.pkgFlags)); pw.print(" installStatus="); pw.print(ps.installStatus); - pw.print(" stopped="); pw.print(ps.stopped); - pw.print(" enabled="); pw.println(ps.enabled); - if (ps.disabledComponents.size() > 0) { - pw.println(" disabledComponents:"); - for (String s : ps.disabledComponents) { - pw.print(" "); pw.println(s); + List<UserInfo> users = getAllUsers(); + for (UserInfo user : users) { + pw.print(" User "); pw.print(user.id); pw.print(": "); + pw.print(" stopped="); + pw.print(ps.getStopped(user.id)); + pw.print(" enabled="); + pw.println(ps.getEnabled(user.id)); + if (ps.getDisabledComponents(user.id).size() > 0) { + pw.println(" disabledComponents:"); + for (String s : ps.getDisabledComponents(user.id)) { + pw.print(" "); pw.println(s); + } } - } - if (ps.enabledComponents.size() > 0) { - pw.println(" enabledComponents:"); - for (String s : ps.enabledComponents) { - pw.print(" "); pw.println(s); + if (ps.getEnabledComponents(user.id).size() > 0) { + pw.println(" enabledComponents:"); + for (String s : ps.getEnabledComponents(user.id)) { + pw.print(" "); pw.println(s); + } } } if (ps.grantedPermissions.size() > 0) { @@ -2234,7 +2520,7 @@ final class Settings { pw.println(ps.name); } pw.print(" userId="); - pw.println(ps.userId); + pw.println(ps.appId); pw.print(" sharedUser="); pw.println(ps.sharedUser); pw.print(" codePath="); @@ -2244,7 +2530,7 @@ final class Settings { } } } - + void dumpPermissionsLPr(PrintWriter pw, String packageName, DumpState dumpState) { boolean printedSomething = false; for (BasePermission p : mPermissions.values()) { diff --git a/services/java/com/android/server/pm/UserManager.java b/services/java/com/android/server/pm/UserManager.java index 5eacf4a..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; @@ -73,6 +74,9 @@ public class UserManager { UserManager(File dataDir, File baseUserPath) { mUsersDir = new File(dataDir, USER_INFO_DIR); mUsersDir.mkdirs(); + // Make zeroth user directory, for services to migrate their files to that location + File userZeroDir = new File(mUsersDir, "0"); + userZeroDir.mkdirs(); mBaseUserPath = baseUserPath; FileUtils.setPermissions(mUsersDir.toString(), FileUtils.S_IRWXU|FileUtils.S_IRWXG @@ -88,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; } /** @@ -105,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; @@ -123,7 +157,7 @@ public class UserManager { if (type != XmlPullParser.START_TAG) { Slog.e(LOG_TAG, "Unable to read user list"); - fallbackToSingleUser(); + fallbackToSingleUserLocked(); return; } @@ -136,11 +170,11 @@ public class UserManager { } } } - updateUserIds(); + updateUserIdsLocked(); } catch (IOException ioe) { - fallbackToSingleUser(); + fallbackToSingleUserLocked(); } catch (XmlPullParserException pe) { - fallbackToSingleUser(); + fallbackToSingleUserLocked(); } finally { if (fis != null) { try { @@ -151,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); } /* @@ -169,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"); @@ -213,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); @@ -306,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; } @@ -325,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) { @@ -335,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) { @@ -373,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()]; } @@ -399,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 @@ -411,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/usb/UsbDeviceManager.java b/services/java/com/android/server/usb/UsbDeviceManager.java index ed83fbe..c2ded8a 100644 --- a/services/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/java/com/android/server/usb/UsbDeviceManager.java @@ -43,6 +43,7 @@ import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.storage.StorageManager; import android.os.storage.StorageVolume; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.UEventObserver; import android.provider.Settings; @@ -206,6 +207,9 @@ public class UsbDeviceManager { } private static String addFunction(String functions, String function) { + if ("none".equals(functions)) { + return function; + } if (!containsFunction(functions, function)) { if (functions.length() > 0) { functions += ","; @@ -222,6 +226,9 @@ public class UsbDeviceManager { split[i] = null; } } + if (split.length == 1 && split[0] == null) { + return "none"; + } StringBuilder builder = new StringBuilder(); for (int i = 0; i < split.length; i++) { String s = split[i]; @@ -365,11 +372,7 @@ public class UsbDeviceManager { for (int i = 0; i < 20; i++) { // State transition is done when sys.usb.state is set to the new configuration if (state.equals(SystemProperties.get("sys.usb.state"))) return true; - try { - // try again in 50ms - Thread.sleep(50); - } catch (InterruptedException e) { - } + SystemClock.sleep(50); } Slog.e(TAG, "waitForState(" + state + ") FAILED"); return false; diff --git a/services/java/com/android/server/wm/AppWindowToken.java b/services/java/com/android/server/wm/AppWindowToken.java index 67b667a..6269420 100644 --- a/services/java/com/android/server/wm/AppWindowToken.java +++ b/services/java/com/android/server/wm/AppWindowToken.java @@ -21,10 +21,12 @@ import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING; import com.android.server.wm.WindowManagerService.H; import android.content.pm.ActivityInfo; +import android.graphics.Matrix; import android.os.Message; import android.os.RemoteException; import android.util.Slog; import android.view.IApplicationToken; +import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.view.WindowManagerPolicy; @@ -49,14 +51,15 @@ 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; // These are used for determining when all windows associated with // an activity have been drawn, so they can be made visible together // at the same time. - int lastTransactionSequence; + // initialize so that it doesn't match mTransactionSequence which is an int. + long lastTransactionSequence = Long.MIN_VALUE; int numInterestingWindows; int numDrawnWindows; boolean inPendingTransaction; @@ -89,6 +92,7 @@ class AppWindowToken extends WindowToken { boolean animating; Animation animation; + boolean animInitialized; boolean hasTransformation; final Transformation transformation = new Transformation(); @@ -104,6 +108,15 @@ class AppWindowToken extends WindowToken { boolean startingMoved; boolean firstWindowDrawn; + // Special surface for thumbnail animation. + Surface thumbnail; + int thumbnailTransactionSeq; + int thumbnailX; + int thumbnailY; + int thumbnailLayer; + Animation thumbnailAnimation; + final Transformation thumbnailTransformation = new Transformation(); + // Input application handle used by the input dispatcher. final InputApplicationHandle mInputApplicationHandle; @@ -113,14 +126,14 @@ class AppWindowToken extends WindowToken { appWindowToken = this; appToken = _token; mInputApplicationHandle = new InputApplicationHandle(this); - lastTransactionSequence = service.mTransactionSequence-1; } - public void setAnimation(Animation anim) { + public void setAnimation(Animation anim, boolean initialized) { if (WindowManagerService.localLOGV) Slog.v( WindowManagerService.TAG, "Setting animation in " + this + ": " + anim); animation = anim; animating = false; + animInitialized = initialized; anim.restrictDuration(WindowManagerService.MAX_ANIMATION_DURATION); anim.scaleCurrentDuration(service.mTransitionAnimationScale); int zorder = anim.getZAdjustment(); @@ -135,6 +148,10 @@ class AppWindowToken extends WindowToken { animLayerAdjustment = adj; updateLayers(); } + // Start out animation gone if window is gone, or visible if window is visible. + transformation.clear(); + transformation.setAlpha(reportedVisible ? 1 : 0); + hasTransformation = true; } public void setDummyAnimation() { @@ -142,6 +159,7 @@ class AppWindowToken extends WindowToken { if (WindowManagerService.localLOGV) Slog.v( WindowManagerService.TAG, "Setting dummy animation in " + this); animation = WindowManagerService.sDummyAnimation; + animInitialized = false; } } @@ -149,15 +167,28 @@ class AppWindowToken extends WindowToken { if (animation != null) { animation = null; animating = true; + animInitialized = false; + } + clearThumbnail(); + } + + public void clearThumbnail() { + if (thumbnail != null) { + thumbnail.destroy(); + thumbnail = null; } } void updateLayers() { final int N = allAppWindows.size(); final int adj = animLayerAdjustment; + thumbnailLayer = -1; for (int i=0; i<N; i++) { WindowState w = allAppWindows.get(i); w.mAnimLayer = w.mLayer + adj; + if (w.mAnimLayer > thumbnailLayer) { + thumbnailLayer = w.mAnimLayer; + } if (WindowManagerService.DEBUG_LAYERS) Slog.v(WindowManagerService.TAG, "Updating layer " + w + ": " + w.mAnimLayer); if (w == service.mInputMethodTarget && !service.mInputMethodTargetWaitingAnim) { @@ -186,16 +217,51 @@ class AppWindowToken extends WindowToken { } } - void showAllWindowsLocked() { + boolean showAllWindowsLocked() { + boolean isAnimating = false; final int NW = allAppWindows.size(); for (int i=0; i<NW; i++) { WindowState w = allAppWindows.get(i); if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(WindowManagerService.TAG, "performing show on: " + w); w.performShowLocked(); + isAnimating |= w.mWinAnimator.isAnimating(); } + return isAnimating; } + private void stepThumbnailAnimation(long currentTime) { + thumbnailTransformation.clear(); + thumbnailAnimation.getTransformation(currentTime, thumbnailTransformation); + thumbnailTransformation.getMatrix().preTranslate(thumbnailX, thumbnailY); + final boolean screenAnimation = service.mAnimator.mScreenRotationAnimation != null + && service.mAnimator.mScreenRotationAnimation.isAnimating(); + if (screenAnimation) { + thumbnailTransformation.postCompose( + service.mAnimator.mScreenRotationAnimation.getEnterTransformation()); + } + // cache often used attributes locally + final float tmpFloats[] = service.mTmpFloats; + thumbnailTransformation.getMatrix().getValues(tmpFloats); + 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) WindowManagerService.logSurface(thumbnail, + "thumbnail", "alpha=" + thumbnailTransformation.getAlpha() + + " layer=" + thumbnailLayer + + " matrix=[" + tmpFloats[Matrix.MSCALE_X] + + "," + tmpFloats[Matrix.MSKEW_Y] + + "][" + tmpFloats[Matrix.MSKEW_X] + + "," + tmpFloats[Matrix.MSCALE_Y] + "]", null); + thumbnail.setAlpha(thumbnailTransformation.getAlpha()); + // The thumbnail is layered below the window immediately above this + // token's anim layer. + thumbnail.setLayer(thumbnailLayer + WindowManagerService.WINDOW_LAYER_MULTIPLIER + - WindowManagerService.LAYER_OFFSET_THUMBNAIL); + thumbnail.setMatrix(tmpFloats[Matrix.MSCALE_X], tmpFloats[Matrix.MSKEW_Y], + tmpFloats[Matrix.MSKEW_X], tmpFloats[Matrix.MSCALE_Y]); + } private boolean stepAnimation(long currentTime) { if (animation == null) { @@ -208,6 +274,7 @@ class AppWindowToken extends WindowToken { ": more=" + more + ", xform=" + transformation); if (!more) { animation = null; + clearThumbnail(); if (WindowManagerService.DEBUG_ANIM) Slog.v( WindowManagerService.TAG, "Finished animation in " + this + " @ " + currentTime); @@ -218,7 +285,7 @@ class AppWindowToken extends WindowToken { // This must be called while inside a transaction. boolean stepAnimationLocked(long currentTime, int dw, int dh) { - if (!service.mDisplayFrozen && service.mPolicy.isScreenOnFully()) { + if (service.okToDisplay()) { // We will run animations as long as the display isn't frozen. if (animation == WindowManagerService.sDummyAnimation) { @@ -236,12 +303,22 @@ class AppWindowToken extends WindowToken { " @ " + currentTime + ": dw=" + dw + " dh=" + dh + " scale=" + service.mTransitionAnimationScale + " allDrawn=" + allDrawn + " animating=" + animating); - animation.initialize(dw, dh, dw, dh); + if (!animInitialized) { + animation.initialize(dw, dh, dw, dh); + } animation.setStartTime(currentTime); animating = true; + if (thumbnail != null) { + thumbnail.show(); + thumbnailAnimation.setStartTime(currentTime); + } } if (stepAnimation(currentTime)) { - // we're done! + // animation isn't over, step any thumbnail and that's + // it for now. + if (thumbnail != null) { + stepThumbnailAnimation(currentTime); + } return true; } } @@ -259,6 +336,10 @@ class AppWindowToken extends WindowToken { } service.mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + service.debugLayoutRepeats("AppWindowToken"); + } + clearAnimation(); animating = false; if (animLayerAdjustment != 0) { @@ -277,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(); @@ -307,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 @@ -317,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; } } @@ -433,6 +514,15 @@ class AppWindowToken extends WindowToken { pw.print(" startingDisplayed="); pw.print(startingDisplayed); pw.print(" startingMoved"); pw.println(startingMoved); } + if (thumbnail != null) { + pw.print(prefix); pw.print("thumbnail="); pw.print(thumbnail); + pw.print(" x="); pw.print(thumbnailX); + pw.print(" y="); pw.print(thumbnailY); + pw.print(" layer="); pw.println(thumbnailLayer); + pw.print(prefix); pw.print("thumbnailAnimation="); pw.println(thumbnailAnimation); + pw.print(prefix); pw.print("thumbnailTransformation="); + pw.println(thumbnailTransformation.toShortString()); + } } @Override diff --git a/services/java/com/android/server/wm/BlackFrame.java b/services/java/com/android/server/wm/BlackFrame.java index 40e452a..c915932 100644 --- a/services/java/com/android/server/wm/BlackFrame.java +++ b/services/java/com/android/server/wm/BlackFrame.java @@ -32,12 +32,14 @@ public class BlackFrame { class BlackSurface { final int left; final int top; + final int layer; final Surface surface; BlackSurface(SurfaceSession session, int layer, int l, int t, int r, int b) throws Surface.OutOfResourcesException { left = l; top = t; + this.layer = layer; int w = r-l; int h = b-t; surface = new Surface(session, 0, "BlackSurface", @@ -45,8 +47,6 @@ public class BlackFrame { if (WindowManagerService.SHOW_TRANSACTIONS || WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG, " BLACK " + surface + ": CREATE layer=" + layer); - surface.setAlpha(1.0f); - surface.setLayer(layer); } void setMatrix(Matrix matrix) { @@ -58,6 +58,8 @@ public class BlackFrame { surface.setMatrix( mTmpFloats[Matrix.MSCALE_X], mTmpFloats[Matrix.MSKEW_Y], mTmpFloats[Matrix.MSKEW_X], mTmpFloats[Matrix.MSCALE_Y]); + surface.setAlpha(1.0f); + surface.setLayer(layer); if (false) { Slog.i(WindowManagerService.TAG, "Black Surface @ (" + left + "," + top + "): (" + mTmpFloats[Matrix.MTRANS_X] + "," diff --git a/services/java/com/android/server/wm/DimAnimator.java b/services/java/com/android/server/wm/DimAnimator.java index a9d4e01..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; @@ -130,33 +130,31 @@ class DimAnimator { } } - boolean animating = false; - if (mLastDimAnimTime != 0) { + boolean animating = mLastDimAnimTime != 0; + if (animating) { mDimCurrentAlpha += mDimDeltaPerMs * (currentTime-mLastDimAnimTime); - boolean more = true; if (displayFrozen) { // If the display is frozen, there is no reason to animate. - more = false; + animating = false; } else if (mDimDeltaPerMs > 0) { if (mDimCurrentAlpha > mDimTargetAlpha) { - more = false; + animating = false; } } else if (mDimDeltaPerMs < 0) { if (mDimCurrentAlpha < mDimTargetAlpha) { - more = false; + animating = false; } } else { - more = false; + animating = false; } // Do we need to continue animating? - if (more) { + if (animating) { if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface + ": alpha=" + mDimCurrentAlpha); mLastDimAnimTime = currentTime; mDimSurface.setAlpha(mDimCurrentAlpha); - animating = true; } else { mDimCurrentAlpha = mDimTargetAlpha; mLastDimAnimTime = 0; diff --git a/services/java/com/android/server/wm/WindowAnimator.java b/services/java/com/android/server/wm/WindowAnimator.java new file mode 100644 index 0000000..81e0a17 --- /dev/null +++ b/services/java/com/android/server/wm/WindowAnimator.java @@ -0,0 +1,629 @@ +// Copyright 2012 Google Inc. All Rights Reserved. + +package com.android.server.wm; + +import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER; + +import android.content.Context; +import android.os.SystemClock; +import android.util.Log; +import android.util.Slog; +import android.view.Surface; +import android.view.WindowManager; +import android.view.WindowManager.LayoutParams; +import android.view.WindowManagerPolicy; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; + +import com.android.internal.policy.impl.PhoneWindowManager; + +/** + * @author cmautner@google.com (Craig Mautner) + * Singleton class that carries out the animations and Surface operations in a separate task + * on behalf of WindowManagerService. + */ +public class WindowAnimator { + private static final String TAG = "WindowAnimator"; + + final WindowManagerService mService; + final Context mContext; + final WindowManagerPolicy mPolicy; + + boolean mAnimating; + boolean mUpdateRotation; + boolean mTokenMayBeDrawn; + boolean mForceHiding; + WindowState mWindowAnimationBackground; + int mWindowAnimationBackgroundColor; + int mAdjResult; + + int mPendingLayoutChanges; + + /** Overall window dimensions */ + int mDw, mDh; + + /** Interior window dimensions */ + int mInnerDw, mInnerDh; + + /** Time of current animation step. Reset on each iteration */ + long mCurrentTime; + + /** Skip repeated AppWindowTokens initialization. Note that AppWindowsToken's version of this + * is a long initialized to Long.MIN_VALUE so that it doesn't match this value on startup. */ + private int mTransactionSequence; + + /** The one and only screen rotation if one is happening */ + ScreenRotationAnimation mScreenRotationAnimation = null; + + WindowAnimator(final WindowManagerService service, final Context context, + final WindowManagerPolicy policy) { + mService = service; + mContext = context; + mPolicy = policy; + } + + private void updateWindowsAppsAndRotationAnimationsLocked() { + int i; + final int NAT = mService.mAppTokens.size(); + for (i=0; i<NAT; i++) { + final AppWindowToken appToken = mService.mAppTokens.get(i); + final boolean wasAnimating = appToken.animation != null + && appToken.animation != WindowManagerService.sDummyAnimation; + if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) { + mAnimating = true; + } else if (wasAnimating) { + // stopped animating, do one more pass through the layout + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("appToken " + appToken + " done"); + } + } + } + + final int NEAT = mService.mExitingAppTokens.size(); + for (i=0; i<NEAT; i++) { + final AppWindowToken appToken = mService.mExitingAppTokens.get(i); + final boolean wasAnimating = appToken.animation != null + && appToken.animation != WindowManagerService.sDummyAnimation; + if (appToken.stepAnimationLocked(mCurrentTime, mInnerDw, mInnerDh)) { + mAnimating = true; + } else if (wasAnimating) { + // stopped animating, do one more pass through the layout + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("exiting appToken " + appToken + " done"); + } + } + } + + if (mScreenRotationAnimation != null && + (mScreenRotationAnimation.isAnimating() || + mScreenRotationAnimation.mFinishAnimReady)) { + if (mScreenRotationAnimation.stepAnimationLocked(mCurrentTime)) { + mUpdateRotation = false; + mAnimating = true; + } else { + mUpdateRotation = true; + mScreenRotationAnimation.kill(); + mScreenRotationAnimation = null; + } + } + } + + private void updateWindowsAndWallpaperLocked() { + ++mTransactionSequence; + + 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; + + if (w.mSurface != null) { + // Take care of the window being ready to display. + if (w.commitFinishDrawingLocked(mCurrentTime)) { + if ((w.mAttrs.flags + & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { + if (WindowManagerService.DEBUG_WALLPAPER) Slog.v(TAG, + "First draw done in potential wallpaper target " + w); + mService.mInnerFields.mWallpaperMayChange = true; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 1"); + } + } + } + + // If the window has moved due to its containing + // content frame changing, then we'd like to animate + // it. The checks here are ordered by what is least + // likely to be true first. + if (w.shouldAnimateMove()) { + // Frame has moved, containing content frame + // has also moved, and we're not currently animating... + // let's do something. + Animation a = AnimationUtils.loadAnimation(mContext, + com.android.internal.R.anim.window_move_from_decor); + winAnimator.setAnimation(a); + w.mAnimDw = w.mLastFrame.left - w.mFrame.left; + w.mAnimDh = w.mLastFrame.top - w.mFrame.top; + } else { + w.mAnimDw = mInnerDw; + w.mAnimDh = mInnerDh; + } + + final boolean wasAnimating = winAnimator.mWasAnimating; + final boolean nowAnimating = winAnimator.stepAnimationLocked(mCurrentTime); + + if (WindowManagerService.DEBUG_WALLPAPER) { + Slog.v(TAG, w + ": wasAnimating=" + wasAnimating + + ", nowAnimating=" + nowAnimating); + } + + // If this window is animating, make a note that we have + // an animating window and take care of a request to run + // a detached wallpaper animation. + if (nowAnimating) { + if (winAnimator.mAnimation != null) { + if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 + && winAnimator.mAnimation.getDetachWallpaper()) { + mService.mInnerFields.mDetachedWallpaper = w; + } + if (winAnimator.mAnimation.getBackgroundColor() != 0) { + if (mWindowAnimationBackground == null + || (w.mAnimLayer < mWindowAnimationBackground.mAnimLayer)) { + mWindowAnimationBackground = w; + mWindowAnimationBackgroundColor = + winAnimator.mAnimation.getBackgroundColor(); + } + } + } + mAnimating = true; + } + + // If this window's app token is running a detached wallpaper + // animation, make a note so we can ensure the wallpaper is + // displayed behind it. + if (w.mAppToken != null && w.mAppToken.animation != null + && w.mAppToken.animating) { + if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 + && w.mAppToken.animation.getDetachWallpaper()) { + mService.mInnerFields.mDetachedWallpaper = w; + } + if (w.mAppToken.animation.getBackgroundColor() != 0) { + if (mWindowAnimationBackground == null + || (w.mAnimLayer < + mWindowAnimationBackground.mAnimLayer)) { + mWindowAnimationBackground = w; + mWindowAnimationBackgroundColor = + w.mAppToken.animation.getBackgroundColor(); + } + } + } + + if (wasAnimating && !winAnimator.mAnimating && mService.mWallpaperTarget == w) { + mService.mInnerFields.mWallpaperMayChange = true; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 2"); + } + } + + if (mPolicy.doesForceHide(w, attrs)) { + if (!wasAnimating && nowAnimating) { + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, + "Animation started that could impact force hide: " + + w); + mService.mInnerFields.mWallpaperForceHidingChanged = true; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 3"); + } + mService.mFocusMayChange = true; + } else if (w.isReadyForDisplay() && winAnimator.mAnimation == null) { + mForceHiding = true; + } + } else if (mPolicy.canBeForceHidden(w, attrs)) { + boolean changed; + if (mForceHiding) { + changed = w.hideLw(false, false); + if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG, + "Now policy hidden: " + w); + } else { + changed = w.showLw(false, false); + if (WindowManagerService.DEBUG_VISIBILITY && changed) Slog.v(TAG, + "Now policy shown: " + w); + if (changed) { + if (mService.mInnerFields.mWallpaperForceHidingChanged + && w.isVisibleNow() /*w.isReadyForDisplay()*/) { + // Assume we will need to animate. If + // we don't (because the wallpaper will + // stay with the lock screen), then we will + // clean up later. + Animation a = mPolicy.createForceHideEnterAnimation(); + if (a != null) { + winAnimator.setAnimation(a); + } + } + if (mCurrentFocus == null || mCurrentFocus.mLayer < w.mLayer) { + // We are showing on to of the current + // focus, so re-evaluate focus to make + // sure it is correct. + mService.mFocusMayChange = true; + } + } + } + if (changed && (attrs.flags + & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { + mService.mInnerFields.mWallpaperMayChange = true; + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 4"); + } + } + } + } + + final AppWindowToken atoken = w.mAppToken; + if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) { + if (atoken.lastTransactionSequence != mTransactionSequence) { + atoken.lastTransactionSequence = mTransactionSequence; + atoken.numInterestingWindows = atoken.numDrawnWindows = 0; + atoken.startingDisplayed = false; + } + if ((w.isOnScreen() || w.mAttrs.type + == WindowManager.LayoutParams.TYPE_BASE_APPLICATION) + && !w.mExiting && !w.mDestroying) { + if (WindowManagerService.DEBUG_VISIBILITY || + WindowManagerService.DEBUG_ORIENTATION) { + Slog.v(TAG, "Eval win " + w + ": isDrawn=" + + w.isDrawnLw() + + ", isAnimating=" + winAnimator.isAnimating()); + if (!w.isDrawnLw()) { + Slog.v(TAG, "Not displayed: s=" + w.mSurface + + " pv=" + w.mPolicyVisibility + + " dp=" + w.mDrawPending + + " cdp=" + w.mCommitDrawPending + + " ah=" + w.mAttachedHidden + + " th=" + atoken.hiddenRequested + + " a=" + winAnimator.mAnimating); + } + } + if (w != atoken.startingWindow) { + if (!atoken.freezingScreen || !w.mAppFreezing) { + atoken.numInterestingWindows++; + if (w.isDrawnLw()) { + atoken.numDrawnWindows++; + if (WindowManagerService.DEBUG_VISIBILITY || + WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG, + "tokenMayBeDrawn: " + atoken + + " freezingScreen=" + atoken.freezingScreen + + " mAppFreezing=" + w.mAppFreezing); + mTokenMayBeDrawn = true; + } + } + } else if (w.isDrawnLw()) { + atoken.startingDisplayed = true; + } + } + } else if (w.mReadyToShow) { + if (w.performShowLocked()) { + mPendingLayoutChanges |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("updateWindowsAndWallpaperLocked 5"); + } + } + } + if (atoken != null && atoken.thumbnail != null) { + if (atoken.thumbnailTransactionSeq != mTransactionSequence) { + atoken.thumbnailTransactionSeq = mTransactionSequence; + atoken.thumbnailLayer = 0; + } + if (atoken.thumbnailLayer < w.mAnimLayer) { + atoken.thumbnailLayer = w.mAnimLayer; + } + } + } // end forall windows + } + + private void testTokenMayBeDrawnLocked() { + // See if any windows have been drawn, so they (and others + // associated with them) can now be shown. + final int NT = mService.mAppTokens.size(); + for (int i=0; i<NT; i++) { + AppWindowToken wtoken = mService.mAppTokens.get(i); + if (wtoken.freezingScreen) { + int numInteresting = wtoken.numInterestingWindows; + if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, + "allDrawn: " + wtoken + + " interesting=" + numInteresting + + " drawn=" + wtoken.numDrawnWindows); + wtoken.showAllWindowsLocked(); + mService.unsetAppFreezingScreenLocked(wtoken, false, true); + if (WindowManagerService.DEBUG_ORIENTATION) Slog.i(TAG, + "Setting mOrientationChangeComplete=true because wtoken " + + wtoken + " numInteresting=" + numInteresting + + " numDrawn=" + wtoken.numDrawnWindows); + mService.mInnerFields.mOrientationChangeComplete = true; + } + } else if (!wtoken.allDrawn) { + int numInteresting = wtoken.numInterestingWindows; + if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, + "allDrawn: " + wtoken + + " interesting=" + numInteresting + + " drawn=" + wtoken.numDrawnWindows); + wtoken.allDrawn = true; + mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; + if (WindowManagerService.DEBUG_LAYOUT_REPEATS) { + mService.debugLayoutRepeats("testTokenMayBeDrawnLocked"); + } + + // We can now show all of the drawn windows! + if (!mService.mOpeningApps.contains(wtoken)) { + mAnimating |= wtoken.showAllWindowsLocked(); + } + } + } + } + } + + private void performAnimationsLocked() { + if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq=" + + mTransactionSequence + " mAnimating=" + + mAnimating); + + mTokenMayBeDrawn = false; + mService.mInnerFields.mWallpaperMayChange = false; + mForceHiding = false; + mService.mInnerFields.mDetachedWallpaper = null; + mWindowAnimationBackground = null; + mWindowAnimationBackgroundColor = 0; + + updateWindowsAndWallpaperLocked(); + + if (mTokenMayBeDrawn) { + testTokenMayBeDrawnLocked(); + } + + if (WindowManagerService.DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x" + + Integer.toHexString(mPendingLayoutChanges)); + } + + public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) { + if (w.mSurface == null) { + if (w.mOrientationChanging) { + if (WindowManagerService.DEBUG_ORIENTATION) { + Slog.v(TAG, "Orientation change skips hidden " + w); + } + w.mOrientationChanging = false; + } + return; + } + + boolean displayed = false; + + w.computeShownFrameLocked(); + + int width, height; + if ((w.mAttrs.flags & LayoutParams.FLAG_SCALED) != 0) { + // for a scaled surface, we just want to use + // the requested size. + width = w.mRequestedWidth; + height = w.mRequestedHeight; + } else { + width = w.mCompatFrame.width(); + height = w.mCompatFrame.height(); + } + + if (width < 1) { + width = 1; + } + if (height < 1) { + height = 1; + } + final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height; + if (surfaceResized) { + w.mSurfaceW = width; + w.mSurfaceH = height; + } + + if (w.mSurfaceX != w.mShownFrame.left + || w.mSurfaceY != w.mShownFrame.top) { + try { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "POS " + w.mShownFrame.left + + ", " + w.mShownFrame.top, null); + w.mSurfaceX = w.mShownFrame.left; + w.mSurfaceY = w.mShownFrame.top; + w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top); + } catch (RuntimeException e) { + Slog.w(TAG, "Error positioning surface of " + w + + " pos=(" + w.mShownFrame.left + + "," + w.mShownFrame.top + ")", e); + if (!recoveringMemory) { + mService.reclaimSomeSurfaceMemoryLocked(w, "position", true); + } + } + } + + if (surfaceResized) { + try { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "SIZE " + width + "x" + height, null); + w.mSurfaceResized = true; + w.mSurface.setSize(width, height); + } catch (RuntimeException e) { + // If something goes wrong with the surface (such + // as running out of memory), don't take down the + // entire system. + Slog.e(TAG, "Error resizing surface of " + w + + " size=(" + width + "x" + height + ")", e); + if (!recoveringMemory) { + mService.reclaimSomeSurfaceMemoryLocked(w, "size", true); + } + } + } + + if (w.mAttachedHidden || !w.isReadyForDisplay()) { + if (!w.mLastHidden) { + //dump(); + w.mLastHidden = true; + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "HIDE (performLayout)", null); + if (w.mSurface != null) { + w.mSurfaceShown = false; + try { + w.mSurface.hide(); + } catch (RuntimeException e) { + Slog.w(TAG, "Exception hiding surface in " + w); + } + } + } + // If we are waiting for this window to handle an + // orientation change, well, it is hidden, so + // doesn't really matter. Note that this does + // introduce a potential glitch if the window + // becomes unhidden before it has drawn for the + // new orientation. + if (w.mOrientationChanging) { + w.mOrientationChanging = false; + if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG, + "Orientation change skips hidden " + w); + } + } else if (w.mLastLayer != w.mAnimLayer + || w.mLastAlpha != w.mShownAlpha + || w.mLastDsDx != w.mDsDx + || w.mLastDtDx != w.mDtDx + || w.mLastDsDy != w.mDsDy + || w.mLastDtDy != w.mDtDy + || w.mLastHScale != w.mHScale + || w.mLastVScale != w.mVScale + || w.mLastHidden) { + displayed = true; + w.mLastAlpha = w.mShownAlpha; + w.mLastLayer = w.mAnimLayer; + w.mLastDsDx = w.mDsDx; + w.mLastDtDx = w.mDtDx; + w.mLastDsDy = w.mDsDy; + w.mLastDtDy = w.mDtDy; + w.mLastHScale = w.mHScale; + w.mLastVScale = w.mVScale; + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer + + " matrix=[" + (w.mDsDx*w.mHScale) + + "," + (w.mDtDx*w.mVScale) + + "][" + (w.mDsDy*w.mHScale) + + "," + (w.mDtDy*w.mVScale) + "]", null); + if (w.mSurface != null) { + try { + w.mSurfaceAlpha = w.mShownAlpha; + w.mSurface.setAlpha(w.mShownAlpha); + w.mSurfaceLayer = w.mAnimLayer; + w.mSurface.setLayer(w.mAnimLayer); + w.mSurface.setMatrix( + w.mDsDx*w.mHScale, w.mDtDx*w.mVScale, + w.mDsDy*w.mHScale, w.mDtDy*w.mVScale); + } catch (RuntimeException e) { + Slog.w(TAG, "Error updating surface in " + w, e); + if (!recoveringMemory) { + mService.reclaimSomeSurfaceMemoryLocked(w, "update", true); + } + } + } + + if (w.mLastHidden && w.isDrawnLw() + && !w.mReadyToShow) { + if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w, + "SHOW (performLayout)", null); + if (WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w + + " during relayout"); + if (mService.showSurfaceRobustlyLocked(w)) { + w.mHasDrawn = true; + w.mLastHidden = false; + } else { + w.mOrientationChanging = false; + } + } + if (w.mSurface != null) { + w.mToken.hasVisible = true; + } + } else { + displayed = true; + } + + if (displayed) { + if (w.mOrientationChanging) { + if (!w.isDrawnLw()) { + mService.mInnerFields.mOrientationChangeComplete = false; + if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG, + "Orientation continue waiting for draw in " + w); + } else { + w.mOrientationChanging = false; + if (WindowManagerService.DEBUG_ORIENTATION) Slog.v(TAG, + "Orientation change complete in " + w); + } + } + w.mToken.hasVisible = true; + } + } + + void animate() { + mPendingLayoutChanges = 0; + mCurrentTime = SystemClock.uptimeMillis(); + + // Update animations of all applications, including those + // associated with exiting/removed apps + Surface.openTransaction(); + + try { + updateWindowsAppsAndRotationAnimationsLocked(); + performAnimationsLocked(); + + // THIRD LOOP: Update the surfaces of all windows. + + if (mScreenRotationAnimation != null) { + mScreenRotationAnimation.updateSurfaces(); + } + + final int N = mService.mWindows.size(); + for (int i=N-1; i>=0; i--) { + WindowState w = mService.mWindows.get(i); + prepareSurfaceLocked(w, true); + } + + if (mService.mDimAnimator != null && mService.mDimAnimator.mDimShown) { + mAnimating |= mService.mDimAnimator.updateSurface(mService.mInnerFields.mDimming, + mCurrentTime, !mService.okToDisplay()); + } + + if (mService.mBlackFrame != null) { + if (mScreenRotationAnimation != null) { + mService.mBlackFrame.setMatrix( + mScreenRotationAnimation.getEnterTransformation().getMatrix()); + } else { + mService.mBlackFrame.clearMatrix(); + } + } + } catch (RuntimeException e) { + Log.wtf(TAG, "Unhandled exception in Window Manager", e); + } finally { + Surface.closeTransaction(); + } + } + + WindowState mCurrentFocus; + void setCurrentFocus(WindowState currentFocus) { + mCurrentFocus = currentFocus; + } + + void setDisplayDimensions(final int curWidth, final int curHeight, + final int appWidth, final int appHeight) { + mDw = curWidth; + mDh = curHeight; + mInnerDw = appWidth; + mInnerDh = appHeight; + } + +} diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java index 6993657..9635b33 100644 --- a/services/java/com/android/server/wm/WindowManagerService.java +++ b/services/java/com/android/server/wm/WindowManagerService.java @@ -18,7 +18,6 @@ package com.android.server.wm; import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW; import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW; -import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_COMPATIBLE_WINDOW; import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; @@ -90,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; @@ -118,8 +118,12 @@ import android.view.WindowManagerImpl; import android.view.WindowManagerPolicy; import android.view.WindowManager.LayoutParams; import android.view.WindowManagerPolicy.FakeWindow; +import android.view.animation.AlphaAnimation; import android.view.animation.Animation; +import android.view.animation.AnimationSet; import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import android.view.animation.ScaleAnimation; import android.view.animation.Transformation; import java.io.BufferedWriter; @@ -167,13 +171,14 @@ public class WindowManagerService extends IWindowManager.Stub static final boolean DEBUG_SCREEN_ON = false; static final boolean DEBUG_SCREENSHOT = false; static final boolean DEBUG_BOOT = false; + static final boolean DEBUG_LAYOUT_REPEATS = false; static final boolean SHOW_SURFACE_ALLOC = false; static final boolean SHOW_TRANSACTIONS = false; static final boolean SHOW_LIGHT_TRANSACTIONS = false || SHOW_TRANSACTIONS; static final boolean HIDE_STACK_CRAWLS = true; + static final int LAYOUT_REPEAT_THRESHOLD = 4; static final boolean PROFILE_ORIENTATION = false; - static final boolean BLUR = true; static final boolean localLOGV = DEBUG; /** How much to multiply the policy's type layer, to reserve room @@ -201,6 +206,13 @@ public class WindowManagerService extends IWindowManager.Stub static final int LAYER_OFFSET_BLUR = 2; /** + * Animation thumbnail is as far as possible below the window above + * the thumbnail (or in other words as far as possible above the window + * below it). + */ + static final int LAYER_OFFSET_THUMBNAIL = WINDOW_LAYER_MULTIPLIER-1; + + /** * Layer at which to put the rotation freeze snapshot. */ static final int FREEZE_LAYER = (TYPE_LAYER_MULTIPLIER * 200) + 1; @@ -415,17 +427,12 @@ public class WindowManagerService extends IWindowManager.Stub IInputMethodManager mInputMethodManager; SurfaceSession mFxSession; - private DimAnimator mDimAnimator = null; - Surface mBlurSurface; - boolean mBlurShown; + DimAnimator mDimAnimator = null; Watermark mWatermark; StrictModeFlash mStrictModeFlash; - ScreenRotationAnimation mScreenRotationAnimation; BlackFrame mBlackFrame; - int mTransactionSequence = 0; - final float[] mTmpFloats = new float[9]; boolean mSafeMode; @@ -491,8 +498,12 @@ public class WindowManagerService extends IWindowManager.Stub // made visible or hidden at the next transition. int mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; String mNextAppTransitionPackage; + Bitmap mNextAppTransitionThumbnail; + IRemoteCallback mNextAppTransitionCallback; int mNextAppTransitionEnter; int mNextAppTransitionExit; + int mNextAppTransitionStartX; + int mNextAppTransitionStartY; boolean mAppTransitionReady = false; boolean mAppTransitionRunning = false; boolean mAppTransitionTimeout = false; @@ -584,27 +595,24 @@ public class WindowManagerService extends IWindowManager.Stub /** Pulled out of performLayoutAndPlaceSurfacesLockedInner in order to refactor into multiple * methods. */ - private class LayoutAndSurfaceFields { - private boolean mAnimating = false; - private boolean mWallpaperForceHidingChanged = false; - private boolean mTokenMayBeDrawn = false; - private boolean mWallpaperMayChange = false; - private boolean mForceHiding = false; - private WindowState mDetachedWallpaper = null; - private WindowState mWindowAnimationBackground = null; - private int mWindowAnimationBackgroundColor = 0; - private boolean mOrientationChangeComplete = true; + class LayoutAndSurfaceFields { + boolean mWallpaperForceHidingChanged = false; + boolean mWallpaperMayChange = false; + WindowState mDetachedWallpaper = null; + boolean mOrientationChangeComplete = true; private int mAdjResult = 0; private Session mHoldScreen = null; private boolean mObscured = false; - private boolean mBlurring = false; - private boolean mDimming = false; + boolean mDimming = false; private boolean mSyswin = false; private float mScreenBrightness = -1; private float mButtonBrightness = -1; private boolean mUpdateRotation = false; } - private LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields(); + LayoutAndSurfaceFields mInnerFields = new LayoutAndSurfaceFields(); + + /** Only do a maximum of 6 repeated layouts. After that quit */ + private int mLayoutRepeatCount; private final class AnimationRunnable implements Runnable { @Override @@ -617,6 +625,8 @@ public class WindowManagerService extends IWindowManager.Stub } final AnimationRunnable mAnimationRunnable = new AnimationRunnable(); boolean mAnimationScheduled; + + final WindowAnimator mAnimator; final class DragInputEventReceiver extends InputEventReceiver { public DragInputEventReceiver(InputChannel inputChannel, Looper looper) { @@ -735,6 +745,7 @@ public class WindowManagerService extends IWindowManager.Stub mAllowBootMessages = allowBootMsgs; } + @Override public void run() { Looper.prepare(); WindowManagerService s = new WindowManagerService(mContext, mPM, @@ -774,6 +785,7 @@ public class WindowManagerService extends IWindowManager.Stub mPM = pm; } + @Override public void run() { Looper.prepare(); WindowManagerPolicyThread.set(this, Looper.myLooper()); @@ -836,6 +848,7 @@ public class WindowManagerService extends IWindowManager.Stub mHoldingScreenWakeLock.setReferenceCounted(false); mInputManager = new InputManager(context, this); + mAnimator = new WindowAnimator(this, context, mPolicy); PolicyThread thr = new PolicyThread(mPolicy, this, context, pm); thr.start(); @@ -1225,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); @@ -1235,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 @@ -1588,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. @@ -1645,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 @@ -1699,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) { @@ -1910,7 +1923,7 @@ public class WindowManagerService extends IWindowManager.Stub rawChanged = true; } - if (rawChanged && (wallpaperWin.getAttrs().privateFlags & + if (rawChanged && (wallpaperWin.mAttrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { try { if (DEBUG_WALLPAPER) Slog.v(TAG, "Report new wp offset " @@ -2217,7 +2230,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mInTouchMode) { res |= WindowManagerImpl.ADD_FLAG_IN_TOUCH_MODE; } - if (win == null || win.mAppToken == null || !win.mAppToken.clientHidden) { + if (win.mAppToken == null || !win.mAppToken.clientHidden) { res |= WindowManagerImpl.ADD_FLAG_APP_VISIBLE; } @@ -2284,13 +2297,13 @@ public class WindowManagerService extends IWindowManager.Stub + ", surface=" + win.mSurface); final long origId = Binder.clearCallingIdentity(); - + win.disposeInputChannel(); 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=" @@ -2302,14 +2315,14 @@ public class WindowManagerService extends IWindowManager.Stub // to hold off on removing the window until the animation is done. // If the display is frozen, just remove immediately, since the // animation wouldn't be seen. - if (win.mSurface != null && !mDisplayFrozen && mDisplayEnabled - && mPolicy.isScreenOnFully()) { + if (win.mSurface != null && okToDisplay()) { // If we are not currently running the exit animation, we // need to see about starting one. - if (wasVisible=win.isWinVisibleLw()) { + wasVisible = win.isWinVisibleLw(); + if (wasVisible) { int transit = WindowManagerPolicy.TRANSIT_EXIT; - if (win.getAttrs().type == TYPE_APPLICATION_STARTING) { + if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; } // Try starting an animation. @@ -2317,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; @@ -2454,6 +2467,15 @@ public class WindowManagerService extends IWindowManager.Stub Slog.i(TAG, str); } } + + static void logSurface(Surface s, String title, String msg, RuntimeException where) { + String str = " SURFACE " + s + ": " + msg + " / " + title; + if (where != null) { + Slog.i(TAG, str, where); + } else { + Slog.i(TAG, str); + } + } void setTransparentRegionWindow(Session session, IWindow client, Region region) { long origId = Binder.clearCallingIdentity(); @@ -2677,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; @@ -2687,8 +2709,7 @@ public class WindowManagerService extends IWindowManager.Stub win.mEnterAnimationPending = true; } if (displayed) { - if (win.isDrawnLw() && !mDisplayFrozen - && mDisplayEnabled && mPolicy.isScreenOnFully()) { + if (win.isDrawnLw() && okToDisplay()) { applyEnterAnimationLocked(win); } if ((win.mAttrs.flags @@ -2775,14 +2796,14 @@ public class WindowManagerService extends IWindowManager.Stub // Try starting an animation; if there isn't one, we // can destroy the surface right away. int transit = WindowManagerPolicy.TRANSIT_EXIT; - if (win.getAttrs().type == TYPE_APPLICATION_STARTING) { + if (win.mAttrs.type == TYPE_APPLICATION_STARTING) { transit = WindowManagerPolicy.TRANSIT_PREVIEW_DONE; } if (!win.mSurfacePendingDestroy && win.isWinVisibleLw() && 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; @@ -2791,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; @@ -3005,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; @@ -3015,7 +3037,7 @@ public class WindowManagerService extends IWindowManager.Stub // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { + if (okToDisplay()) { int anim = mPolicy.selectAnimationLw(win, transit); int attr = -1; Animation a = null; @@ -3042,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) { @@ -3053,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) { @@ -3095,15 +3117,76 @@ public class WindowManagerService extends IWindowManager.Stub return null; } + private Animation createThumbnailAnimationLocked(int transit, + boolean enter, boolean thumb) { + Animation a; + final float thumbWidth = mNextAppTransitionThumbnail.getWidth(); + final float thumbHeight = mNextAppTransitionThumbnail.getHeight(); + // Pick the desired duration. If this is an inter-activity transition, + // it is the standard duration for that. Otherwise we use the longer + // task transition duration. + int duration; + switch (transit) { + case WindowManagerPolicy.TRANSIT_ACTIVITY_OPEN: + case WindowManagerPolicy.TRANSIT_ACTIVITY_CLOSE: + duration = mContext.getResources().getInteger( + com.android.internal.R.integer.config_shortAnimTime); + break; + default: + duration = 500; + break; + + } + if (thumb) { + // Animation for zooming thumbnail from its initial size to + // filling the screen. + Animation scale = new ScaleAnimation( + 1, mAppDisplayWidth/thumbWidth, + 1, mAppDisplayHeight/thumbHeight, + mNextAppTransitionStartX + thumbWidth/2, + mNextAppTransitionStartY + thumbHeight/2); + AnimationSet set = new AnimationSet(true); + Animation alpha = new AlphaAnimation(1, 0); + scale.setDuration(duration); + set.addAnimation(scale); + alpha.setDuration(duration); + set.addAnimation(alpha); + a = set; + } else if (enter) { + // Entering app zooms out from the center of the thumbnail. + a = new ScaleAnimation( + thumbWidth/mAppDisplayWidth, 1, + thumbHeight/mAppDisplayHeight, 1, + mNextAppTransitionStartX + thumbWidth/2, + mNextAppTransitionStartY + thumbHeight/2); + a.setDuration(duration); + } else { + // Exiting app just holds in place. + a = new AlphaAnimation(1, 1); + a.setDuration(duration); + } + a.setFillAfter(true); + final Interpolator interpolator = AnimationUtils.loadInterpolator(mContext, + com.android.internal.R.interpolator.decelerate_quint); + a.setInterpolator(interpolator); + a.initialize(mAppDisplayWidth, mAppDisplayHeight, + mAppDisplayWidth, mAppDisplayHeight); + return a; + } + private boolean applyAnimationLocked(AppWindowToken wtoken, WindowManager.LayoutParams lp, int transit, boolean enter) { // Only apply an animation if the display isn't frozen. If it is // frozen, there is no reason to animate and it can cause strange // artifacts when we unfreeze the display if some different animation // is running. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { + if (okToDisplay()) { Animation a; - if (mNextAppTransitionPackage != null) { + boolean initialized = false; + if (mNextAppTransitionThumbnail != null) { + a = createThumbnailAnimationLocked(transit, enter, false); + initialized = true; + } else if (mNextAppTransitionPackage != null) { a = loadAnimation(mNextAppTransitionPackage, enter ? mNextAppTransitionEnter : mNextAppTransitionExit); } else { @@ -3175,7 +3258,7 @@ public class WindowManagerService extends IWindowManager.Stub } Slog.v(TAG, "Loaded animation " + a + " for " + wtoken, e); } - wtoken.setAnimation(a); + wtoken.setAnimation(a, initialized); } } else { wtoken.clearAnimation(); @@ -3234,6 +3317,10 @@ public class WindowManagerService extends IWindowManager.Stub Slog.w(TAG, msg); return false; } + + boolean okToDisplay() { + return !mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully(); + } AppWindowToken findAppWindowToken(IBinder token) { WindowToken wtoken = mTokenMap.get(token); @@ -3243,6 +3330,7 @@ public class WindowManagerService extends IWindowManager.Stub return wtoken.appWindowToken; } + @Override public void addWindowToken(IBinder token, int type) { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "addWindowToken()")) { @@ -3283,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; } @@ -3665,7 +3753,7 @@ public class WindowManagerService extends IWindowManager.Stub if (DEBUG_APP_TRANSITIONS) Slog.v( TAG, "Prepare app transition: transit=" + transit + " mNextAppTransition=" + mNextAppTransition); - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully()) { + if (okToDisplay()) { if (mNextAppTransition == WindowManagerPolicy.TRANSIT_UNSET || mNextAppTransition == WindowManagerPolicy.TRANSIT_NONE) { mNextAppTransition = transit; @@ -3699,11 +3787,23 @@ public class WindowManagerService extends IWindowManager.Stub int enterAnim, int exitAnim) { if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { mNextAppTransitionPackage = packageName; + mNextAppTransitionThumbnail = null; mNextAppTransitionEnter = enterAnim; mNextAppTransitionExit = exitAnim; } } + public void overridePendingAppTransitionThumb(Bitmap srcThumb, int startX, + int startY, IRemoteCallback startedCallback) { + if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + mNextAppTransitionPackage = null; + mNextAppTransitionThumbnail = srcThumb; + mNextAppTransitionStartX = startX; + mNextAppTransitionStartY = startY; + mNextAppTransitionCallback = startedCallback; + } + } + public void executeAppTransition() { if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS, "executeAppTransition()")) { @@ -3749,7 +3849,7 @@ public class WindowManagerService extends IWindowManager.Stub // If the display is frozen, we won't do anything until the // actual window is displayed so there is no reason to put in // the starting window. - if (mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()) { + if (!okToDisplay()) { return; } @@ -3847,6 +3947,19 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendMessageAtFrontOfQueue(m); return; } + if (ttoken.thumbnail != null) { + // The old token is animating with a thumbnail, transfer + // that to the new token. + if (wtoken.thumbnail != null) { + wtoken.thumbnail.destroy(); + } + wtoken.thumbnail = ttoken.thumbnail; + wtoken.thumbnailX = ttoken.thumbnailX; + wtoken.thumbnailY = ttoken.thumbnailY; + wtoken.thumbnailLayer = ttoken.thumbnailLayer; + wtoken.thumbnailAnimation = ttoken.thumbnailAnimation; + ttoken.thumbnail = null; + } } } @@ -3951,7 +4064,7 @@ public class WindowManagerService extends IWindowManager.Stub continue; } - if (win.isAnimating()) { + if (win.mWinAnimator.isAnimating()) { delayed = true; } @@ -4039,8 +4152,7 @@ public class WindowManagerService extends IWindowManager.Stub // If we are preparing an app transition, then delay changing // the visibility of this token until we execute that transition. - if (!mDisplayFrozen && mDisplayEnabled && mPolicy.isScreenOnFully() - && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { + if (okToDisplay() && mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { // Already in requested state, don't do anything more. if (wtoken.hiddenRequested != visible) { return; @@ -4168,7 +4280,7 @@ public class WindowManagerService extends IWindowManager.Stub } synchronized(mWindowMap) { - if (configChanges == 0 && !mDisplayFrozen && mPolicy.isScreenOnFully()) { + if (configChanges == 0 && okToDisplay()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping set freeze of " + token); return; } @@ -4243,6 +4355,7 @@ public class WindowManagerService extends IWindowManager.Stub // Make sure there is no animation running on this token, // so any windows associated with it will be removed as // soon as their animations are complete + wtoken.clearAnimation(); wtoken.animation = null; wtoken.animating = false; } @@ -5150,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 @@ -5271,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); @@ -5389,7 +5502,8 @@ public class WindowManagerService extends IWindowManager.Stub return false; } - if (mScreenRotationAnimation != null && mScreenRotationAnimation.isAnimating()) { + if (mAnimator.mScreenRotationAnimation != null && + mAnimator.mScreenRotationAnimation.isAnimating()) { // Rotation updates cannot be performed while the previous rotation change // animation is still in progress. Skip this update. We will try updating // again after the animation is finished and the display is unfrozen. @@ -5459,9 +5573,9 @@ public class WindowManagerService extends IWindowManager.Stub try { // NOTE: We disable the rotation in the emulator because // it doesn't support hardware OpenGL emulation yet. - if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null - && mScreenRotationAnimation.hasScreenshot()) { - if (mScreenRotationAnimation.setRotation(rotation, mFxSession, + if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null + && mAnimator.mScreenRotationAnimation.hasScreenshot()) { + if (mAnimator.mScreenRotationAnimation.setRotation(rotation, mFxSession, MAX_ANIMATION_DURATION, mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) { scheduleAnimationLocked(); @@ -5476,7 +5590,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - rebuildBlackFrame(inTransaction); + rebuildBlackFrame(); for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = mWindows.get(i); @@ -6163,6 +6277,8 @@ public class WindowManagerService extends IWindowManager.Stub synchronized(mDisplaySizeLock) { mAppDisplayWidth = appWidth; mAppDisplayHeight = appHeight; + mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight, + mAppDisplayWidth, mAppDisplayHeight); } if (false) { Slog.i(TAG, "Set app display size: " + mAppDisplayWidth @@ -6549,6 +6665,8 @@ public class WindowManagerService extends IWindowManager.Stub } mBaseDisplayWidth = mCurDisplayWidth = mAppDisplayWidth = mInitialDisplayWidth; mBaseDisplayHeight = mCurDisplayHeight = mAppDisplayHeight = mInitialDisplayHeight; + mAnimator.setDisplayDimensions(mCurDisplayWidth, mCurDisplayHeight, + mAppDisplayWidth, mAppDisplayHeight); } mInputManager.setDisplaySize(Display.DEFAULT_DISPLAY, mDisplay.getRawWidth(), mDisplay.getRawHeight(), @@ -7151,45 +7269,32 @@ public class WindowManagerService extends IWindowManager.Stub } } - private void rebuildBlackFrame(boolean inTransaction) { - if (!inTransaction) { - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, - ">>> OPEN TRANSACTION rebuildBlackFrame"); - Surface.openTransaction(); + private void rebuildBlackFrame() { + if (mBlackFrame != null) { + mBlackFrame.kill(); + mBlackFrame = null; } - try { - if (mBlackFrame != null) { - mBlackFrame.kill(); - mBlackFrame = null; - } - if (mBaseDisplayWidth < mInitialDisplayWidth - || mBaseDisplayHeight < mInitialDisplayHeight) { - int initW, initH, baseW, baseH; - final boolean rotated = (mRotation == Surface.ROTATION_90 - || mRotation == Surface.ROTATION_270); - if (rotated) { - initW = mInitialDisplayHeight; - initH = mInitialDisplayWidth; - baseW = mBaseDisplayHeight; - baseH = mBaseDisplayWidth; - } else { - initW = mInitialDisplayWidth; - initH = mInitialDisplayHeight; - baseW = mBaseDisplayWidth; - baseH = mBaseDisplayHeight; - } - Rect outer = new Rect(0, 0, initW, initH); - Rect inner = new Rect(0, 0, baseW, baseH); - try { - mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER); - } catch (Surface.OutOfResourcesException e) { - } + if (mBaseDisplayWidth < mInitialDisplayWidth + || mBaseDisplayHeight < mInitialDisplayHeight) { + int initW, initH, baseW, baseH; + final boolean rotated = (mRotation == Surface.ROTATION_90 + || mRotation == Surface.ROTATION_270); + if (rotated) { + initW = mInitialDisplayHeight; + initH = mInitialDisplayWidth; + baseW = mBaseDisplayHeight; + baseH = mBaseDisplayWidth; + } else { + initW = mInitialDisplayWidth; + initH = mInitialDisplayHeight; + baseW = mBaseDisplayWidth; + baseH = mBaseDisplayHeight; } - } finally { - if (!inTransaction) { - Surface.closeTransaction(); - if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, - "<<< CLOSE TRANSACTION rebuildBlackFrame"); + Rect outer = new Rect(0, 0, initW, initH); + Rect inner = new Rect(0, 0, baseW, baseH); + try { + mBlackFrame = new BlackFrame(mFxSession, outer, inner, MASK_LAYER); + } catch (Surface.OutOfResourcesException e) { } } } @@ -7240,7 +7345,7 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } - rebuildBlackFrame(false); + rebuildBlackFrame(); performLayoutAndPlaceSurfacesLocked(); } @@ -7478,10 +7583,25 @@ public class WindowManagerService extends IWindowManager.Stub } else { mInLayout = false; - if (mLayoutNeeded) { + } + + if (mLayoutNeeded) { + if (++mLayoutRepeatCount < 6) { requestTraversalLocked(); + } else { + Slog.e(TAG, "Performed 6 layouts in a row. Skipping"); + mLayoutRepeatCount = 0; } + } else { + mLayoutRepeatCount = 0; } + + if (mAnimator.mAnimating) { + // Do this even if requestTraversalLocked was called above so we get a frame drawn + // at the proper time as well as the one drawn early. + scheduleAnimationLocked(); + } + if (mWindowsChanged && !mWindowChangeListeners.isEmpty()) { mH.removeMessages(H.REPORT_WINDOWS_CHANGE); mH.sendMessage(mH.obtainMessage(H.REPORT_WINDOWS_CHANGE)); @@ -7625,7 +7745,7 @@ public class WindowManagerService extends IWindowManager.Stub // If the screen is currently frozen or off, then keep // it frozen/off until this window draws at its new // orientation. - if (mDisplayFrozen || !mPolicy.isScreenOnFully()) { + if (!okToDisplay()) { if (DEBUG_ORIENTATION) Slog.v(TAG, "Changing surface while display frozen: " + w); w.mOrientationChanging = true; @@ -7642,351 +7762,6 @@ public class WindowManagerService extends IWindowManager.Stub /** * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. - * Update animations of all applications, including those associated with exiting/removed apps. - * - * @param currentTime The time which animations use for calculating transitions. - * @param innerDw Width of app window. - * @param innerDh Height of app window. - */ - private void updateWindowsAppsAndRotationAnimationsLocked(long currentTime, - int innerDw, int innerDh) { - int i; - final int NAT = mAppTokens.size(); - for (i=0; i<NAT; i++) { - final AppWindowToken appToken = mAppTokens.get(i); - if (appToken.stepAnimationLocked(currentTime, innerDw, innerDh)) { - mInnerFields.mAnimating = true; - } - } - final int NEAT = mExitingAppTokens.size(); - for (i=0; i<NEAT; i++) { - final AppWindowToken appToken = mExitingAppTokens.get(i); - if (appToken.stepAnimationLocked(currentTime, innerDw, innerDh)) { - mInnerFields.mAnimating = true; - } - } - - if (mScreenRotationAnimation != null && - (mScreenRotationAnimation.isAnimating() || - mScreenRotationAnimation.mFinishAnimReady)) { - if (mScreenRotationAnimation.stepAnimationLocked(currentTime)) { - mInnerFields.mUpdateRotation = false; - mInnerFields.mAnimating = true; - } else { - mInnerFields.mUpdateRotation = true; - mScreenRotationAnimation.kill(); - mScreenRotationAnimation = null; - } - } - } - - private void animateAndUpdateSurfaces(final long currentTime, final int dw, final int dh, - final int innerDw, final int innerDh, - final boolean recoveringMemory) { - // Update animations of all applications, including those - // associated with exiting/removed apps - Surface.openTransaction(); - - try { - updateWindowsAppsAndRotationAnimationsLocked(currentTime, innerDw, innerDh); - mPendingLayoutChanges = performAnimationsLocked(currentTime, dw, dh, - innerDw, innerDh); - - // THIRD LOOP: Update the surfaces of all windows. - - if (mScreenRotationAnimation != null) { - mScreenRotationAnimation.updateSurfaces(); - } - - final int N = mWindows.size(); - for (int i=N-1; i>=0; i--) { - WindowState w = mWindows.get(i); - prepareSurfaceLocked(w, recoveringMemory); - } - - if (mDimAnimator != null && mDimAnimator.mDimShown) { - mInnerFields.mAnimating |= - mDimAnimator.updateSurface(mInnerFields.mDimming, currentTime, - mDisplayFrozen || !mDisplayEnabled || !mPolicy.isScreenOnFully()); - } - - if (!mInnerFields.mBlurring && mBlurShown) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " + mBlurSurface - + ": HIDE"); - try { - mBlurSurface.hide(); - } catch (IllegalArgumentException e) { - Slog.w(TAG, "Illegal argument exception hiding blur surface"); - } - mBlurShown = false; - } - - if (mBlackFrame != null) { - if (mScreenRotationAnimation != null) { - mBlackFrame.setMatrix( - mScreenRotationAnimation.getEnterTransformation().getMatrix()); - } else { - mBlackFrame.clearMatrix(); - } - } - } catch (RuntimeException e) { - Log.wtf(TAG, "Unhandled exception in Window Manager", e); - } finally { - Surface.closeTransaction(); - } - } - - /** - * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. - * - * @param currentTime The time which animations use for calculating transitions. - * @param dw Width of app window. - * @param dh Height of app window. - * @param innerDw Width of app window. - * @param innerDh Height of app window. - */ - private int updateWindowsAndWallpaperLocked(final long currentTime, final int dw, final int dh, - final int innerDw, final int innerDh) { - int changes = 0; - for (int i = mWindows.size() - 1; i >= 0; i--) { - WindowState w = mWindows.get(i); - - final WindowManager.LayoutParams attrs = w.mAttrs; - - if (w.mSurface != null) { - // Take care of the window being ready to display. - if (w.commitFinishDrawingLocked(currentTime)) { - if ((w.mAttrs.flags - & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { - if (DEBUG_WALLPAPER) Slog.v(TAG, - "First draw done in potential wallpaper target " + w); - mInnerFields.mWallpaperMayChange = true; - changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; - } - } - - // If the window has moved due to its containing - // content frame changing, then we'd like to animate - // it. The checks here are ordered by what is least - // likely to be true first. - if (w.shouldAnimateMove()) { - // Frame has moved, containing content frame - // has also moved, and we're not currently animating... - // let's do something. - Animation a = AnimationUtils.loadAnimation(mContext, - com.android.internal.R.anim.window_move_from_decor); - w.setAnimation(a); - w.mAnimDw = w.mLastFrame.left - w.mFrame.left; - w.mAnimDh = w.mLastFrame.top - w.mFrame.top; - } else { - w.mAnimDw = innerDw; - w.mAnimDh = innerDh; - } - - final boolean wasAnimating = w.mWasAnimating; - final boolean nowAnimating = w.stepAnimationLocked(currentTime); - - if (DEBUG_WALLPAPER) { - Slog.v(TAG, w + ": wasAnimating=" + wasAnimating + - ", nowAnimating=" + nowAnimating); - } - - // If this window is animating, make a note that we have - // an animating window and take care of a request to run - // a detached wallpaper animation. - if (nowAnimating) { - if (w.mAnimation != null) { - if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 - && w.mAnimation.getDetachWallpaper()) { - mInnerFields.mDetachedWallpaper = w; - } - if (w.mAnimation.getBackgroundColor() != 0) { - if (mInnerFields.mWindowAnimationBackground == null - || (w.mAnimLayer < - mInnerFields.mWindowAnimationBackground.mAnimLayer)) { - mInnerFields.mWindowAnimationBackground = w; - mInnerFields.mWindowAnimationBackgroundColor = - w.mAnimation.getBackgroundColor(); - } - } - } - mInnerFields.mAnimating = true; - } - - // If this window's app token is running a detached wallpaper - // animation, make a note so we can ensure the wallpaper is - // displayed behind it. - if (w.mAppToken != null && w.mAppToken.animation != null - && w.mAppToken.animating) { - if ((w.mAttrs.flags&FLAG_SHOW_WALLPAPER) != 0 - && w.mAppToken.animation.getDetachWallpaper()) { - mInnerFields.mDetachedWallpaper = w; - } - if (w.mAppToken.animation.getBackgroundColor() != 0) { - if (mInnerFields.mWindowAnimationBackground == null - || (w.mAnimLayer < - mInnerFields.mWindowAnimationBackground.mAnimLayer)) { - mInnerFields.mWindowAnimationBackground = w; - mInnerFields.mWindowAnimationBackgroundColor = - w.mAppToken.animation.getBackgroundColor(); - } - } - } - - if (wasAnimating && !w.mAnimating && mWallpaperTarget == w) { - mInnerFields.mWallpaperMayChange = true; - changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; - } - - if (mPolicy.doesForceHide(w, attrs)) { - if (!wasAnimating && nowAnimating) { - if (DEBUG_VISIBILITY) Slog.v(TAG, - "Animation started that could impact force hide: " - + w); - mInnerFields.mWallpaperForceHidingChanged = true; - changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; - mFocusMayChange = true; - } else if (w.isReadyForDisplay() && w.mAnimation == null) { - mInnerFields.mForceHiding = true; - } - } else if (mPolicy.canBeForceHidden(w, attrs)) { - boolean changed; - if (mInnerFields.mForceHiding) { - changed = w.hideLw(false, false); - if (DEBUG_VISIBILITY && changed) Slog.v(TAG, - "Now policy hidden: " + w); - } else { - changed = w.showLw(false, false); - if (DEBUG_VISIBILITY && changed) Slog.v(TAG, - "Now policy shown: " + w); - if (changed) { - if (mInnerFields.mWallpaperForceHidingChanged - && w.isVisibleNow() /*w.isReadyForDisplay()*/) { - // Assume we will need to animate. If - // we don't (because the wallpaper will - // stay with the lock screen), then we will - // clean up later. - Animation a = mPolicy.createForceHideEnterAnimation(); - if (a != null) { - w.setAnimation(a); - } - } - if (mCurrentFocus == null || - mCurrentFocus.mLayer < w.mLayer) { - // We are showing on to of the current - // focus, so re-evaluate focus to make - // sure it is correct. - mFocusMayChange = true; - } - } - } - if (changed && (attrs.flags - & WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER) != 0) { - mInnerFields.mWallpaperMayChange = true; - changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER; - } - } - } - - final AppWindowToken atoken = w.mAppToken; - if (atoken != null && (!atoken.allDrawn || atoken.freezingScreen)) { - if (atoken.lastTransactionSequence != mTransactionSequence) { - atoken.lastTransactionSequence = mTransactionSequence; - atoken.numInterestingWindows = atoken.numDrawnWindows = 0; - atoken.startingDisplayed = false; - } - if ((w.isOnScreen() || w.mAttrs.type - == WindowManager.LayoutParams.TYPE_BASE_APPLICATION) - && !w.mExiting && !w.mDestroying) { - if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) { - Slog.v(TAG, "Eval win " + w + ": isDrawn=" - + w.isDrawnLw() - + ", isAnimating=" + w.isAnimating()); - if (!w.isDrawnLw()) { - Slog.v(TAG, "Not displayed: s=" + w.mSurface - + " pv=" + w.mPolicyVisibility - + " dp=" + w.mDrawPending - + " cdp=" + w.mCommitDrawPending - + " ah=" + w.mAttachedHidden - + " th=" + atoken.hiddenRequested - + " a=" + w.mAnimating); - } - } - if (w != atoken.startingWindow) { - if (!atoken.freezingScreen || !w.mAppFreezing) { - atoken.numInterestingWindows++; - if (w.isDrawnLw()) { - atoken.numDrawnWindows++; - if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG, - "tokenMayBeDrawn: " + atoken - + " freezingScreen=" + atoken.freezingScreen - + " mAppFreezing=" + w.mAppFreezing); - mInnerFields.mTokenMayBeDrawn = true; - } - } - } else if (w.isDrawnLw()) { - atoken.startingDisplayed = true; - } - } - } else if (w.mReadyToShow) { - w.performShowLocked(); - changes |= WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM; - } - } // end forall windows - - return changes; - } - - /** - * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. - * - * @return bitmap indicating if another pass through layout must be made. - */ - private int testTokenMayBeDrawnLocked() { - int changes = 0; - // See if any windows have been drawn, so they (and others - // associated with them) can now be shown. - final int NT = mAppTokens.size(); - for (int i=0; i<NT; i++) { - AppWindowToken wtoken = mAppTokens.get(i); - if (wtoken.freezingScreen) { - int numInteresting = wtoken.numInterestingWindows; - if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { - if (DEBUG_VISIBILITY) Slog.v(TAG, - "allDrawn: " + wtoken - + " interesting=" + numInteresting - + " drawn=" + wtoken.numDrawnWindows); - wtoken.showAllWindowsLocked(); - unsetAppFreezingScreenLocked(wtoken, false, true); - if (DEBUG_ORIENTATION) Slog.i(TAG, - "Setting mOrientationChangeComplete=true because wtoken " - + wtoken + " numInteresting=" + numInteresting - + " numDrawn=" + wtoken.numDrawnWindows); - mInnerFields.mOrientationChangeComplete = true; - } - } else if (!wtoken.allDrawn) { - int numInteresting = wtoken.numInterestingWindows; - if (numInteresting > 0 && wtoken.numDrawnWindows >= numInteresting) { - if (DEBUG_VISIBILITY) Slog.v(TAG, - "allDrawn: " + wtoken - + " interesting=" + numInteresting - + " drawn=" + wtoken.numDrawnWindows); - wtoken.allDrawn = true; - changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM; - - // We can now show all of the drawn windows! - if (!mOpeningApps.contains(wtoken)) { - wtoken.showAllWindowsLocked(); - } - } - } - } - - return changes; - } - - /** - * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. * * @return bitmap indicating if another pass through layout must be made. */ @@ -8148,11 +7923,15 @@ public class WindowManagerService extends IWindowManager.Stub animLp = null; } + AppWindowToken topOpeningApp = null; + int topOpeningLayer = 0; + NN = mOpeningApps.size(); for (i=0; i<NN; i++) { AppWindowToken wtoken = mOpeningApps.get(i); if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now opening app" + wtoken); + wtoken.clearThumbnail(); wtoken.reportedVisible = false; wtoken.inPendingTransaction = false; wtoken.animation = null; @@ -8160,13 +7939,27 @@ public class WindowManagerService extends IWindowManager.Stub transit, false); wtoken.updateReportedVisibilityLocked(); wtoken.waitingToShow = false; - wtoken.showAllWindowsLocked(); + mAnimator.mAnimating |= wtoken.showAllWindowsLocked(); + if (animLp != null) { + int layer = -1; + for (int j=0; j<wtoken.windows.size(); j++) { + WindowState win = wtoken.windows.get(j); + if (win.mAnimLayer > layer) { + layer = win.mAnimLayer; + } + } + if (topOpeningApp == null || layer > topOpeningLayer) { + topOpeningApp = wtoken; + topOpeningLayer = layer; + } + } } NN = mClosingApps.size(); for (i=0; i<NN; i++) { AppWindowToken wtoken = mClosingApps.get(i); if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "Now closing app" + wtoken); + wtoken.clearThumbnail(); wtoken.inPendingTransaction = false; wtoken.animation = null; setTokenVisibilityLocked(wtoken, animLp, false, @@ -8179,7 +7972,47 @@ public class WindowManagerService extends IWindowManager.Stub wtoken.allDrawn = true; } + if (mNextAppTransitionThumbnail != null && topOpeningApp != null + && topOpeningApp.animation != null) { + // This thumbnail animation is very special, we need to have + // an extra surface with the thumbnail included with the animation. + Rect dirty = new Rect(0, 0, mNextAppTransitionThumbnail.getWidth(), + mNextAppTransitionThumbnail.getHeight()); + try { + Surface surface = new Surface(mFxSession, Process.myPid(), + "thumbnail anim", 0, dirty.width(), dirty.height(), + PixelFormat.TRANSLUCENT, Surface.HIDDEN); + topOpeningApp.thumbnail = surface; + if (SHOW_TRANSACTIONS) Slog.i(TAG, " THUMBNAIL " + + surface + ": CREATE"); + Surface drawSurface = new Surface(); + drawSurface.copyFrom(surface); + Canvas c = drawSurface.lockCanvas(dirty); + c.drawBitmap(mNextAppTransitionThumbnail, 0, 0, null); + drawSurface.unlockCanvasAndPost(c); + drawSurface.release(); + topOpeningApp.thumbnailLayer = topOpeningLayer; + Animation anim = createThumbnailAnimationLocked(transit, true, true); + topOpeningApp.thumbnailAnimation = anim; + anim.restrictDuration(MAX_ANIMATION_DURATION); + anim.scaleCurrentDuration(mTransitionAnimationScale); + topOpeningApp.thumbnailX = mNextAppTransitionStartX; + topOpeningApp.thumbnailY = mNextAppTransitionStartY; + } catch (Surface.OutOfResourcesException e) { + Slog.e(TAG, "Can't allocate thumbnail surface w=" + dirty.width() + + " h=" + dirty.height(), e); + topOpeningApp.clearThumbnail(); + } + } + mNextAppTransitionPackage = null; + mNextAppTransitionThumbnail = null; + if (mNextAppTransitionCallback != null) { + try { + mNextAppTransitionCallback.sendResult(null); + } catch (RemoteException e) { + } + } mOpeningApps.clear(); mClosingApps.clear(); @@ -8258,20 +8091,20 @@ public class WindowManagerService extends IWindowManager.Stub if (mLowerWallpaperTarget == null) { // Whoops, we don't need a special wallpaper animation. // Clear them out. - mInnerFields.mForceHiding = false; + mAnimator.mForceHiding = false; for (int i=mWindows.size()-1; i>=0; i--) { WindowState w = mWindows.get(i); if (w.mSurface != null) { final WindowManager.LayoutParams attrs = w.mAttrs; if (mPolicy.doesForceHide(w, attrs) && w.isVisibleLw()) { if (DEBUG_FOCUS) Slog.i(TAG, "win=" + w + " force hides other windows"); - mInnerFields.mForceHiding = true; + 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(); } } } @@ -8296,14 +8129,14 @@ public class WindowManagerService extends IWindowManager.Stub mInnerFields.mWallpaperMayChange = true; } - if (mInnerFields.mWindowAnimationBackgroundColor != 0) { + if (mAnimator.mWindowAnimationBackgroundColor != 0) { // If the window that wants black is the current wallpaper // target, then the black goes *below* the wallpaper so we // don't cause the wallpaper to suddenly disappear. - WindowState target = mInnerFields.mWindowAnimationBackground; - if (mWallpaperTarget == mInnerFields.mWindowAnimationBackground - || mLowerWallpaperTarget == mInnerFields.mWindowAnimationBackground - || mUpperWallpaperTarget == mInnerFields.mWindowAnimationBackground) { + WindowState target = mAnimator.mWindowAnimationBackground; + if (mWallpaperTarget == target + || mLowerWallpaperTarget == target + || mUpperWallpaperTarget == target) { for (int i=0; i<mWindows.size(); i++) { WindowState w = mWindows.get(i); if (w.mIsWallpaper) { @@ -8319,7 +8152,7 @@ public class WindowManagerService extends IWindowManager.Stub final int dh = mCurDisplayHeight; mWindowAnimationBackgroundSurface.show(dw, dh, target.mAnimLayer - LAYER_OFFSET_DIM, - mInnerFields.mWindowAnimationBackgroundColor); + mAnimator.mWindowAnimationBackgroundColor); } else if (mWindowAnimationBackgroundSurface != null) { mWindowAnimationBackgroundSurface.hide(); } @@ -8422,206 +8255,6 @@ public class WindowManagerService extends IWindowManager.Stub /** * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. * - * @param w WindowState whos Surface is being prepared. - * @param recoveringMemory true if the caller will reclaim surface memory on error. - */ - public void prepareSurfaceLocked(final WindowState w, final boolean recoveringMemory) { - // XXX NOTE: The logic here could be improved. We have - // the decision about whether to resize a window separated - // from whether to hide the surface. This can cause us to - // resize a surface even if we are going to hide it. You - // can see this by (1) holding device in landscape mode on - // home screen; (2) tapping browser icon (device will rotate - // to landscape; (3) tap home. The wallpaper will be resized - // in step 2 but then immediately hidden, causing us to - // have to resize and then redraw it again in step 3. It - // would be nice to figure out how to avoid this, but it is - // difficult because we do need to resize surfaces in some - // cases while they are hidden such as when first showing a - // window. - - if (w.mSurface == null) { - if (w.mOrientationChanging) { - if (DEBUG_ORIENTATION) { - Slog.v(TAG, "Orientation change skips hidden " + w); - } - w.mOrientationChanging = false; - } - return; - } - - boolean displayed = false; - - w.computeShownFrameLocked(); - - int width, height; - if ((w.mAttrs.flags & w.mAttrs.FLAG_SCALED) != 0) { - // for a scaled surface, we just want to use - // the requested size. - width = w.mRequestedWidth; - height = w.mRequestedHeight; - } else { - width = w.mCompatFrame.width(); - height = w.mCompatFrame.height(); - } - - if (width < 1) { - width = 1; - } - if (height < 1) { - height = 1; - } - final boolean surfaceResized = w.mSurfaceW != width || w.mSurfaceH != height; - if (surfaceResized) { - w.mSurfaceW = width; - w.mSurfaceH = height; - } - - if (w.mSurfaceX != w.mShownFrame.left - || w.mSurfaceY != w.mShownFrame.top) { - try { - if (SHOW_TRANSACTIONS) logSurface(w, - "POS " + w.mShownFrame.left - + ", " + w.mShownFrame.top, null); - w.mSurfaceX = w.mShownFrame.left; - w.mSurfaceY = w.mShownFrame.top; - w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top); - } catch (RuntimeException e) { - Slog.w(TAG, "Error positioning surface of " + w - + " pos=(" + w.mShownFrame.left - + "," + w.mShownFrame.top + ")", e); - if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "position", true); - } - } - } - - if (surfaceResized) { - try { - if (SHOW_TRANSACTIONS) logSurface(w, - "SIZE " + width + "x" + height, null); - w.mSurfaceResized = true; - w.mSurface.setSize(width, height); - } catch (RuntimeException e) { - // If something goes wrong with the surface (such - // as running out of memory), don't take down the - // entire system. - Slog.e(TAG, "Error resizing surface of " + w - + " size=(" + width + "x" + height + ")", e); - if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "size", true); - } - } - } - - updateResizingWindows(w); - - if (w.mAttachedHidden || !w.isReadyForDisplay()) { - if (!w.mLastHidden) { - //dump(); - w.mLastHidden = true; - if (SHOW_TRANSACTIONS) logSurface(w, - "HIDE (performLayout)", null); - if (w.mSurface != null) { - w.mSurfaceShown = false; - try { - w.mSurface.hide(); - } catch (RuntimeException e) { - Slog.w(TAG, "Exception hiding surface in " + w); - } - } - } - // If we are waiting for this window to handle an - // orientation change, well, it is hidden, so - // doesn't really matter. Note that this does - // introduce a potential glitch if the window - // becomes unhidden before it has drawn for the - // new orientation. - if (w.mOrientationChanging) { - w.mOrientationChanging = false; - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Orientation change skips hidden " + w); - } - } else if (w.mLastLayer != w.mAnimLayer - || w.mLastAlpha != w.mShownAlpha - || w.mLastDsDx != w.mDsDx - || w.mLastDtDx != w.mDtDx - || w.mLastDsDy != w.mDsDy - || w.mLastDtDy != w.mDtDy - || w.mLastHScale != w.mHScale - || w.mLastVScale != w.mVScale - || w.mLastHidden) { - displayed = true; - w.mLastAlpha = w.mShownAlpha; - w.mLastLayer = w.mAnimLayer; - w.mLastDsDx = w.mDsDx; - w.mLastDtDx = w.mDtDx; - w.mLastDsDy = w.mDsDy; - w.mLastDtDy = w.mDtDy; - w.mLastHScale = w.mHScale; - w.mLastVScale = w.mVScale; - if (SHOW_TRANSACTIONS) logSurface(w, - "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer - + " matrix=[" + (w.mDsDx*w.mHScale) - + "," + (w.mDtDx*w.mVScale) - + "][" + (w.mDsDy*w.mHScale) - + "," + (w.mDtDy*w.mVScale) + "]", null); - if (w.mSurface != null) { - try { - w.mSurfaceAlpha = w.mShownAlpha; - w.mSurface.setAlpha(w.mShownAlpha); - w.mSurfaceLayer = w.mAnimLayer; - w.mSurface.setLayer(w.mAnimLayer); - w.mSurface.setMatrix( - w.mDsDx*w.mHScale, w.mDtDx*w.mVScale, - w.mDsDy*w.mHScale, w.mDtDy*w.mVScale); - } catch (RuntimeException e) { - Slog.w(TAG, "Error updating surface in " + w, e); - if (!recoveringMemory) { - reclaimSomeSurfaceMemoryLocked(w, "update", true); - } - } - } - - if (w.mLastHidden && w.isDrawnLw() - && !w.mReadyToShow) { - if (SHOW_TRANSACTIONS) logSurface(w, - "SHOW (performLayout)", null); - if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w - + " during relayout"); - if (showSurfaceRobustlyLocked(w)) { - w.mHasDrawn = true; - w.mLastHidden = false; - } else { - w.mOrientationChanging = false; - } - } - if (w.mSurface != null) { - w.mToken.hasVisible = true; - } - } else { - displayed = true; - } - - if (displayed) { - if (w.mOrientationChanging) { - if (!w.isDrawnLw()) { - mInnerFields.mOrientationChangeComplete = false; - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Orientation continue waiting for draw in " + w); - } else { - w.mOrientationChanging = false; - if (DEBUG_ORIENTATION) Slog.v(TAG, - "Orientation change complete in " + w); - } - } - w.mToken.hasVisible = true; - } - } - - /** - * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. - * * @param w WindowState this method is applied to. * @param currentTime The time which animations use for calculating transitions. * @param innerDw Width of app window. @@ -8656,131 +8289,26 @@ public class WindowManagerService extends IWindowManager.Stub boolean opaqueDrawn = canBeSeen && w.isOpaqueDrawn(); if (opaqueDrawn && w.isFullscreen(innerDw, innerDh)) { // This window completely covers everything behind it, - // so we want to leave all of them as unblurred (for + // so we want to leave all of them as undimmed (for // performance reasons). mInnerFields.mObscured = true; - } else if (canBeSeen && (attrFlags & (FLAG_BLUR_BEHIND | FLAG_DIM_BEHIND)) != 0) { - if (localLOGV) Slog.v(TAG, "Win " + w - + ": blurring=" + mInnerFields.mBlurring - + " obscured=" + mInnerFields.mObscured); - if ((attrFlags&FLAG_DIM_BEHIND) != 0) { - if (!mInnerFields.mDimming) { - //Slog.i(TAG, "DIM BEHIND: " + w); - mInnerFields.mDimming = true; - if (mDimAnimator == null) { - mDimAnimator = new DimAnimator(mFxSession); - } - if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { - mDimAnimator.show(mCurDisplayWidth, mCurDisplayHeight); - } else { - mDimAnimator.show(innerDw, innerDh); - } + } else if (canBeSeen && (attrFlags & FLAG_DIM_BEHIND) != 0) { + if (localLOGV) Slog.v(TAG, "Win " + w + " obscured=" + mInnerFields.mObscured); + if (!mInnerFields.mDimming) { + //Slog.i(TAG, "DIM BEHIND: " + w); + mInnerFields.mDimming = true; + if (mDimAnimator == null) { + mDimAnimator = new DimAnimator(mFxSession); + } + if (attrs.type == WindowManager.LayoutParams.TYPE_BOOT_PROGRESS) { + mDimAnimator.show(mCurDisplayWidth, mCurDisplayHeight); + } else { mDimAnimator.show(innerDw, innerDh); - mDimAnimator.updateParameters(mContext.getResources(), - w, currentTime); } + mDimAnimator.updateParameters(mContext.getResources(), + w, currentTime); } - if ((attrFlags & FLAG_BLUR_BEHIND) != 0) { - if (!mInnerFields.mBlurring) { - //Slog.i(TAG, "BLUR BEHIND: " + w); - mInnerFields.mBlurring = true; - if (mBlurSurface == null) { - try { - mBlurSurface = new Surface(mFxSession, 0, - "BlurSurface", - -1, 16, 16, - PixelFormat.OPAQUE, - Surface.FX_SURFACE_BLUR); - } catch (Exception e) { - Slog.e(TAG, "Exception creating Blur surface", e); - } - if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " - + mBlurSurface + ": CREATE"); - } - final int dw = mCurDisplayWidth; - final int dh = mCurDisplayHeight; - if (mBlurSurface != null) { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " - + mBlurSurface + ": pos=(0,0) (" + - dw + "x" + dh + "), layer=" + (w.mAnimLayer-1)); - mBlurSurface.setPosition(0, 0); - mBlurSurface.setSize(dw, dh); - mBlurSurface.setLayer(w.mAnimLayer-LAYER_OFFSET_BLUR); - if (!mBlurShown) { - try { - if (SHOW_TRANSACTIONS) Slog.i(TAG, " BLUR " - + mBlurSurface + ": SHOW"); - mBlurSurface.show(); - } catch (RuntimeException e) { - Slog.w(TAG, "Failure showing blur surface", e); - } - mBlurShown = true; - } - } - } - } - } - } - - private final int performAnimationsLocked(long currentTime, int dw, int dh, - int innerDw, int innerDh) { - ++mTransactionSequence; - - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq=" - + mTransactionSequence + " mAnimating=" - + mInnerFields.mAnimating); - - mInnerFields.mTokenMayBeDrawn = false; - mInnerFields.mWallpaperMayChange = false; - mInnerFields.mForceHiding = false; - mInnerFields.mDetachedWallpaper = null; - mInnerFields.mWindowAnimationBackground = null; - mInnerFields.mWindowAnimationBackgroundColor = 0; - - int changes = updateWindowsAndWallpaperLocked(currentTime, dw, dh, innerDw, innerDh); - - if (mInnerFields.mTokenMayBeDrawn) { - changes |= testTokenMayBeDrawnLocked(); - } - - // If we are ready to perform an app transition, check through - // all of the app tokens to be shown and see if they are ready - // to go. - if (mAppTransitionReady) { - changes |= handleAppTransitionReadyLocked(); - } - - mInnerFields.mAdjResult = 0; - - if (!mInnerFields.mAnimating && mAppTransitionRunning) { - // We have finished the animation of an app transition. To do - // this, we have delayed a lot of operations like showing and - // hiding apps, moving apps in Z-order, etc. The app token list - // reflects the correct Z-order, but the window list may now - // be out of sync with it. So here we will just rebuild the - // entire app window list. Fun! - changes |= handleAnimatingStoppedAndTransitionLocked(); - } - - if (mInnerFields.mWallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) { - // At this point, there was a window with a wallpaper that - // was force hiding other windows behind it, but now it - // is going away. This may be simple -- just animate - // away the wallpaper and its window -- or it may be - // hard -- the wallpaper now needs to be shown behind - // something that was hidden. - changes |= animateAwayWallpaperLocked(); } - - changes |= testWallpaperAndBackgroundLocked(); - - if (mLayoutNeeded) { - changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; - } - - if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x" - + Integer.toHexString(changes)); - return changes; } // "Something has changed! Let's make it correct now." @@ -8820,7 +8348,7 @@ public class WindowManagerService extends IWindowManager.Stub mInnerFields.mScreenBrightness = -1; mInnerFields.mButtonBrightness = -1; boolean focusDisplayed = false; - mInnerFields.mAnimating = false; + mAnimator.mAnimating = false; boolean createWatermark = false; if (mFxSession == null) { @@ -8855,12 +8383,15 @@ public class WindowManagerService extends IWindowManager.Stub break; } + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("On entry to LockedInner"); + if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) { if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) { assignLayersLocked(); mLayoutNeeded = true; } } + if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) { if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout"); if (updateOrientationFromAppTokensLocked(true)) { @@ -8868,6 +8399,7 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); } } + if ((mPendingLayoutChanges & WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) { mLayoutNeeded = true; } @@ -8882,6 +8414,7 @@ public class WindowManagerService extends IWindowManager.Stub // FIRST AND ONE HALF LOOP: Make WindowManagerPolicy think // it is animating. mPendingLayoutChanges = 0; + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("loop number " + mLayoutRepeatCount); mPolicy.beginAnimationLw(dw, dh); for (i = mWindows.size() - 1; i >= 0; i--) { WindowState w = mWindows.get(i); @@ -8890,13 +8423,12 @@ public class WindowManagerService extends IWindowManager.Stub } } mPendingLayoutChanges |= mPolicy.finishAnimationLw(); - + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after finishAnimationLw"); } while (mPendingLayoutChanges != 0); final boolean someoneLosingFocus = !mLosingFocus.isEmpty(); mInnerFields.mObscured = false; - mInnerFields.mBlurring = false; mInnerFields.mDimming = false; mInnerFields.mSyswin = false; @@ -8931,9 +8463,59 @@ public class WindowManagerService extends IWindowManager.Stub Surface.closeTransaction(); } + // If we are ready to perform an app transition, check through + // all of the app tokens to be shown and see if they are ready + // to go. + if (mAppTransitionReady) { + mPendingLayoutChanges |= handleAppTransitionReadyLocked(); + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAppTransitionReadyLocked"); + } + + mInnerFields.mAdjResult = 0; + + if (!mAnimator.mAnimating && mAppTransitionRunning) { + // We have finished the animation of an app transition. To do + // this, we have delayed a lot of operations like showing and + // hiding apps, moving apps in Z-order, etc. The app token list + // reflects the correct Z-order, but the window list may now + // be out of sync with it. So here we will just rebuild the + // entire app window list. Fun! + mPendingLayoutChanges |= handleAnimatingStoppedAndTransitionLocked(); + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after handleAnimStopAndXitionLock"); + } + + if (mInnerFields.mWallpaperForceHidingChanged && mPendingLayoutChanges == 0 && + !mAppTransitionReady) { + // At this point, there was a window with a wallpaper that + // was force hiding other windows behind it, but now it + // is going away. This may be simple -- just animate + // away the wallpaper and its window -- or it may be + // hard -- the wallpaper now needs to be shown behind + // something that was hidden. + mPendingLayoutChanges |= animateAwayWallpaperLocked(); + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animateAwayWallpaperLocked"); + } + + mPendingLayoutChanges |= testWallpaperAndBackgroundLocked(); + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after testWallpaperAndBackgroundLocked"); + + if (mLayoutNeeded) { + mPendingLayoutChanges |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT; + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("mLayoutNeeded"); + } + + final int N = mWindows.size(); + for (i=N-1; i>=0; i--) { + WindowState w = mWindows.get(i); + // TODO(cmautner): Can this move up to the loop at the end of try/catch above? + updateResizingWindows(w); + } + // Update animations of all applications, including those // associated with exiting/removed apps - animateAndUpdateSurfaces(currentTime, dw, dh, innerDw, innerDh, recoveringMemory); + mAnimator.animate(); + mPendingLayoutChanges |= mAnimator.mPendingLayoutChanges; + if (DEBUG_LAYOUT_REPEATS) debugLayoutRepeats("after animate()"); if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION performLayoutAndPlaceSurfaces"); @@ -9026,6 +8608,7 @@ public class WindowManagerService extends IWindowManager.Stub // Make sure there is no animation running on this token, // so any windows associated with it will be removed as // soon as their animations are complete + token.clearAnimation(); token.animation = null; token.animating = false; if (DEBUG_ADD_REMOVE || DEBUG_TOKEN_MOVEMENT) Slog.v(TAG, @@ -9035,9 +8618,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - boolean needRelayout = false; - - if (!mInnerFields.mAnimating && mAppTransitionRunning) { + if (!mAnimator.mAnimating && mAppTransitionRunning) { // We have finished the animation of an app transition. To do // this, we have delayed a lot of operations like showing and // hiding apps, moving apps in Z-order, etc. The app token list @@ -9045,7 +8626,7 @@ public class WindowManagerService extends IWindowManager.Stub // be out of sync with it. So here we will just rebuild the // entire app window list. Fun! mAppTransitionRunning = false; - needRelayout = true; + mLayoutNeeded = true; rebuildAppWindowListLocked(); assignLayersLocked(); // Clear information about apps that were moving. @@ -9056,19 +8637,10 @@ public class WindowManagerService extends IWindowManager.Stub mH.sendEmptyMessage(H.REPORT_LOSING_FOCUS); } if (wallpaperDestroyed) { - needRelayout = adjustWallpaperWindowsLocked() != 0; - } - if ((mPendingLayoutChanges & ( - WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER | - ADJUST_WALLPAPER_LAYERS_CHANGED | - WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG | - WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) { - needRelayout = true; + mLayoutNeeded |= adjustWallpaperWindowsLocked() != 0; } - if (needRelayout) { - requestTraversalLocked(); - } else if (mInnerFields.mAnimating) { - scheduleAnimationLocked(); + if (mPendingLayoutChanges != 0) { + mLayoutNeeded = true; } // Finally update all input windows now that the window changes have stabilized. @@ -9111,7 +8683,7 @@ public class WindowManagerService extends IWindowManager.Stub } } - if (mInnerFields.mOrientationChangeComplete && !needRelayout && + if (mInnerFields.mOrientationChangeComplete && !mLayoutNeeded && !mInnerFields.mUpdateRotation) { checkDrawnWindowsLocked(); } @@ -9333,6 +8905,7 @@ public class WindowManagerService extends IWindowManager.Stub TAG, "Changing focus from " + mCurrentFocus + " to " + newFocus); final WindowState oldFocus = mCurrentFocus; mCurrentFocus = newFocus; + mAnimator.setCurrentFocus(mCurrentFocus); mLosingFocus.remove(newFocus); int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus); @@ -9464,6 +9037,7 @@ public class WindowManagerService extends IWindowManager.Stub if (mNextAppTransition != WindowManagerPolicy.TRANSIT_UNSET) { mNextAppTransition = WindowManagerPolicy.TRANSIT_UNSET; mNextAppTransitionPackage = null; + mNextAppTransitionThumbnail = null; mAppTransitionReady = true; } @@ -9473,16 +9047,16 @@ public class WindowManagerService extends IWindowManager.Stub } if (CUSTOM_SCREEN_ROTATION) { - if (mScreenRotationAnimation != null) { - mScreenRotationAnimation.kill(); - mScreenRotationAnimation = null; + if (mAnimator.mScreenRotationAnimation != null) { + mAnimator.mScreenRotationAnimation.kill(); + mAnimator.mScreenRotationAnimation = null; } - if (mScreenRotationAnimation == null) { - mScreenRotationAnimation = new ScreenRotationAnimation(mContext, + if (mAnimator.mScreenRotationAnimation == null) { + mAnimator.mScreenRotationAnimation = new ScreenRotationAnimation(mContext, mFxSession, inTransaction, mCurDisplayWidth, mCurDisplayHeight, mDisplay.getRotation()); } - if (!mScreenRotationAnimation.hasScreenshot()) { + if (!mAnimator.mScreenRotationAnimation.hasScreenshot()) { Surface.freezeDisplay(0); } } else { @@ -9507,20 +9081,20 @@ public class WindowManagerService extends IWindowManager.Stub boolean updateRotation = false; - if (CUSTOM_SCREEN_ROTATION && mScreenRotationAnimation != null - && mScreenRotationAnimation.hasScreenshot()) { + if (CUSTOM_SCREEN_ROTATION && mAnimator.mScreenRotationAnimation != null + && mAnimator.mScreenRotationAnimation.hasScreenshot()) { if (DEBUG_ORIENTATION) Slog.i(TAG, "**** Dismissing screen rotation animation"); - if (mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION, + if (mAnimator.mScreenRotationAnimation.dismiss(mFxSession, MAX_ANIMATION_DURATION, mTransitionAnimationScale, mCurDisplayWidth, mCurDisplayHeight)) { scheduleAnimationLocked(); } else { - mScreenRotationAnimation = null; + mAnimator.mScreenRotationAnimation = null; updateRotation = true; } } else { - if (mScreenRotationAnimation != null) { - mScreenRotationAnimation.kill(); - mScreenRotationAnimation = null; + if (mAnimator.mScreenRotationAnimation != null) { + mAnimator.mScreenRotationAnimation.kill(); + mAnimator.mScreenRotationAnimation = null; } updateRotation = true; } @@ -9987,8 +9561,7 @@ public class WindowManagerService extends IWindowManager.Stub } pw.print(" mSystemBooted="); pw.print(mSystemBooted); pw.print(" mDisplayEnabled="); pw.println(mDisplayEnabled); - pw.print(" mLayoutNeeded="); pw.print(mLayoutNeeded); - pw.print(" mBlurShown="); pw.println(mBlurShown); + pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded); if (mDimAnimator != null) { pw.println(" mDimAnimator:"); mDimAnimator.printTo(" ", pw); @@ -10004,9 +9577,9 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mLastWindowForcedOrientation"); pw.print(mLastWindowForcedOrientation); pw.print(" mForcedAppOrientation="); pw.println(mForcedAppOrientation); pw.print(" mDeferredRotationPauseCount="); pw.println(mDeferredRotationPauseCount); - if (mScreenRotationAnimation != null) { + if (mAnimator.mScreenRotationAnimation != null) { pw.println(" mScreenRotationAnimation:"); - mScreenRotationAnimation.printTo(" ", pw); + mAnimator.mScreenRotationAnimation.printTo(" ", pw); } pw.print(" mWindowAnimationScale="); pw.print(mWindowAnimationScale); pw.print(" mTransitionWindowAnimationScale="); pw.print(mTransitionAnimationScale); @@ -10025,6 +9598,12 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mNextAppTransitionExit=0x"); pw.print(Integer.toHexString(mNextAppTransitionExit)); } + if (mNextAppTransitionThumbnail != null) { + pw.print(" mNextAppTransitionThumbnail="); + pw.print(mNextAppTransitionThumbnail); + pw.print(" mNextAppTransitionStartX="); pw.print(mNextAppTransitionStartX); + pw.print(" mNextAppTransitionStartY="); pw.println(mNextAppTransitionStartY); + } pw.print(" mStartingIconInTransition="); pw.print(mStartingIconInTransition); pw.print(", mSkipAppTransitionAnimation="); pw.println(mSkipAppTransitionAnimation); } @@ -10192,4 +9771,11 @@ 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); + Slog.v(TAG, "mPendingLayoutChanges = 0x" + Integer.toHexString(mPendingLayoutChanges)); + } + } } diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java index 57d0374..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,37 +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); - } - - 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; @@ -927,19 +900,21 @@ 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)) { return false; } + + mService.enableScreenIfNeededLocked(); + + mService.applyEnterAnimationLocked(this); + mLastAlpha = -1; mHasDrawn = true; mLastHidden = false; mReadyToShow = false; - mService.enableScreenIfNeededLocked(); - - mService.applyEnterAnimationLocked(this); int i = mChildWindows.size(); while (i > 0) { @@ -972,204 +947,21 @@ 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); } mAppToken.updateReportedVisibilityLocked(); } - } - 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.mDisplayFrozen && mService.mPolicy.isScreenOnFully()) { - // 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) { + } else { 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 (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; - } + return true; } boolean isIdentityMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { @@ -1190,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; @@ -1202,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); } @@ -1221,8 +1013,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { } } - final boolean screenAnimation = mService.mScreenRotationAnimation != null - && mService.mScreenRotationAnimation.isAnimating(); + final boolean screenAnimation = mService.mAnimator.mScreenRotationAnimation != null + && mService.mAnimator.mScreenRotationAnimation.isAnimating(); if (selfTransformation || attachedTransformation != null || appTransformation != null || screenAnimation) { // cache often used attributes locally @@ -1251,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) { @@ -1262,7 +1054,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } if (screenAnimation) { tmpMatrix.postConcat( - mService.mScreenRotationAnimation.getEnterTransformation().getMatrix()); + mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getMatrix()); } // "convert" it into SurfaceFlinger's format @@ -1295,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(); @@ -1305,7 +1097,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { } if (screenAnimation) { mShownAlpha *= - mService.mScreenRotationAnimation.getEnterTransformation().getAlpha(); + mService.mAnimator.mScreenRotationAnimation.getEnterTransformation().getAlpha(); } } else { //Slog.i(TAG, "Not applying alpha transform"); @@ -1314,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; } @@ -1365,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); } /** @@ -1422,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); } } @@ -1441,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. @@ -1470,7 +1246,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { return isDrawnLw() && mPolicyVisibility && ((!mAttachedHidden && (atoken == null || !atoken.hiddenRequested)) - || mAnimating); + || mWinAnimator.mAnimating); } public boolean isGoneForLayoutLw() { @@ -1499,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); } @@ -1509,11 +1285,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { * sense to call from performLayoutAndPlaceSurfacesLockedInner().) */ boolean shouldAnimateMove() { - return mContentChanged && !mExiting && !mLastHidden && !mService.mDisplayFrozen + return mContentChanged && !mExiting && !mLastHidden && mService.okToDisplay() && (mFrame.top != mLastFrame.top || mFrame.left != mLastFrame.left) - && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove()) - && mService.mPolicy.isScreenOnFully(); + && (mAttachedWindow == null || !mAttachedWindow.shouldAnimateMove()); } boolean isFullscreen(int screenWidth, int screenHeight) { @@ -1599,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); - if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOnFully()) { + + 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. @@ -1626,7 +1401,7 @@ final class WindowState implements WindowManagerPolicy.WindowState { boolean hideLw(boolean doAnimation, boolean requestAnim) { if (doAnimation) { - if (mService.mDisplayFrozen || !mService.mPolicy.isScreenOnFully()) { + if (!mService.okToDisplay()) { doAnimation = false; } } @@ -1638,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; } } @@ -1813,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(); + } + } + +} |
